Commit 24fed907 authored by Davve's avatar Davve

解决图片上传

parent 1f233f9b
...@@ -15,14 +15,67 @@ class PushListView(APIView): ...@@ -15,14 +15,67 @@ class PushListView(APIView):
data = self.rpc['venus/community/push/get'](offset=page, limit=limit, filters=filter).unwrap() data = self.rpc['venus/community/push/get'](offset=page, limit=limit, filters=filter).unwrap()
except Exception as e: except Exception as e:
data = { data = {
'total': 200, 'total': 200,
'data': [ 'data': [
{'id': 1, 'title': '测试1', 'content': '测试2', 'push_time': '2018-08-09','create_time':'2019-08-07', 'creator_id':22, }, {
{'id': 2, 'title': '测试1', 'content': '测试2', 'push_time': '2018-08-09', 'create_time': '2019-08-07', 'id': 1,
'creator_id': 22, }, 'title': '测试1',
{'id': 3, 'title': '测试1', 'content': '测试2', 'push_time': '2018-08-09', 'create_time': '2019-08-07', 'content': '测试2',
'creator_id': 22, }, 'push_time': '2018-08-09 23:89:09',
] 'create_time': '2019-08-07 23:89:09',
} 'creator_id': 22,
},
{
'id': 2,
'title': '测试1',
'content': '测试2',
'push_time': '2018-08-09 23:89:09',
'create_time': '2019-08-07 23:89:09',
'creator_id': 22,
},
{
'id': 3,
'title': '测试1',
'content': '测试2',
'push_time': '2018-08-09 23:89:09',
'create_time': '2019-08-07 23:89:09',
'creator_id': 22,
},
]
}
return data
return data class PushUpdateOrCreateView(APIView):
\ No newline at end of file def get(self, request):
id = request.GET.get('id')
try:
data = self.rpc['venus/community/push/detail'](id=id).unwrap()
except Exception as e:
# raise e
data = {
'id': 1,
'create_time': '2018-09-08 23:34:34',
'push_time': 24121273912739, # 返回时间戳
'content': '这是推送内容',
'url': 'http:www.baidu.com',
'icon': 'https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=846134627,633122759&fm=173&app=49&f=JPEG?w=600&h=400&s=84C5D14ADEA4A2575042FFAA0300F005',
'title': '这是一个推送标题',
}
return {'data': data}
def post(self, request):
# TODO 图片icon上传到七牛
data = {
'url': request.POST.get('url', ''),
'push_time': request.POST.get('push_time', ''),
'icon': request.POST.get('icon', ''),
'content': request.POST.get('content', ''),
'title': request.POST.get('title', ''),
}
print(data, '--------------------')
# try:
# self.rpc['venus/community/push/create'](data=data).unwrap()
# except Exception as e:
# raise e
...@@ -14,13 +14,5 @@ class StarListView(APIView): ...@@ -14,13 +14,5 @@ class StarListView(APIView):
try: try:
data = self.rpc['venus/community/star/get'](offset=page, limit=limit, filters=filter).unwrap() data = self.rpc['venus/community/star/get'](offset=page, limit=limit, filters=filter).unwrap()
except Exception as e: except Exception as e:
data = { raise e
'total': 200,
'data': [
{'id': 1, 'name': '测试1', 'region': '测试2', 'group_nums': 22, 'gender': 1},
{'id': 2, 'name': '测试1', 'region': '测试2', 'group_nums': 13, 'gender': 1},
{'id': 3, 'name': '测试1', 'region': '测试2', 'group_nums': 18, 'gender': 0},
]
}
return data return data
\ No newline at end of file
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "chenwei"
# Date: 2018/11/19
from utils.base import APIView
from gm_upload import upload
class FileUpload(APIView):
args_POST = {
'img_type': {
'access': int,
},
}
def post(self, request):
image = request.FILES.get('file')
data = image.read()
full_image_url = upload(data, img_type=self.args_post.get('type')) + '-w'
return {
'file_url': full_image_url
}
...@@ -15,6 +15,7 @@ from .star import * ...@@ -15,6 +15,7 @@ from .star import *
from .account import * from .account import *
from .search import * from .search import *
from .tag import * from .tag import *
from .upload import *
urlpatterns = [ urlpatterns = [
# 登陆,注销相关 # 登陆,注销相关
...@@ -41,6 +42,8 @@ urlpatterns = [ ...@@ -41,6 +42,8 @@ urlpatterns = [
# push相关 # push相关
url(r'push/list$', PushListView.as_view()), url(r'push/list$', PushListView.as_view()),
url(r'push/create', PushUpdateOrCreateView.as_view()),
url(r'push/detail', PushUpdateOrCreateView.as_view()),
# pick相关 # pick相关
url(r'pick/list$', PickListView.as_view()), url(r'pick/list$', PickListView.as_view()),
...@@ -55,11 +58,16 @@ urlpatterns = [ ...@@ -55,11 +58,16 @@ urlpatterns = [
url(r'tag/detail', TagUpdateOrCreateView.as_view()), url(r'tag/detail', TagUpdateOrCreateView.as_view()),
] ]
searchurlpatterns = [ search_urlpatterns = [
url(r'search/group$', GroupSearchView.as_view()), url(r'search/group$', GroupSearchView.as_view()),
url(r'search/region', RegionSearchView.as_view()), url(r'search/region', RegionSearchView.as_view()),
url(r'search/user', UserSearchView.as_view()), url(r'search/user', UserSearchView.as_view()),
url(r'search/tag', TagSearchView.as_view()), url(r'search/tag', TagSearchView.as_view()),
] ]
urlpatterns += searchurlpatterns common_urlpatterns = [
url(r"^file/upload$", FileUpload.as_view()),
]
urlpatterns += search_urlpatterns
urlpatterns += common_urlpatterns
var api = require('./api') var api = require('./api')
// //
// const target = 'http://doctor.test.env' // const target = 'http://doctor.test.env'
// const target = 'http://172.30.8.231:8000' const target = 'http://172.30.8.231:8000'
const target = 'http://192.168.1.6:8000' // const target = 'http://192.168.1.6:8000'
// 可以修改请求内容 // 可以修改请求内容
const onProxyReq = proxyReq => {} const onProxyReq = proxyReq => {}
......
...@@ -8,3 +8,27 @@ export function fetchList(query) { ...@@ -8,3 +8,27 @@ export function fetchList(query) {
}) })
} }
export function OffLineOrOnLine(data) {
console.log(data)
return request({
url: '/api/push/list/update',
method: 'post',
data
})
}
export function CreatePush(data) {
return request({
url: '/api/push/create',
method: 'post',
data
})
}
export function fetchPushDetail(id) {
return request({
url: '/api/push/detail',
method: 'get',
params: { id }
})
}
...@@ -7,18 +7,18 @@ ...@@ -7,18 +7,18 @@
:on-success="handleImageSuccess" :on-success="handleImageSuccess"
class="image-uploader" class="image-uploader"
drag drag
action="https://httpbin.org/post"> action="/api/file/upload">
<i class="el-icon-upload"/> <i class="el-icon-upload"/>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</el-upload> </el-upload>
<div class="image-preview image-app-preview"> <!--<div class="image-preview image-app-preview">-->
<div v-show="imageUrl.length>1" class="image-preview-wrapper"> <!--<div v-show="imageUrl.length>1" class="image-preview-wrapper">-->
<img :src="imageUrl"> <!--<img :src="imageUrl">-->
<div class="image-preview-action"> <!--<div class="image-preview-action">-->
<i class="el-icon-delete" @click="rmImage"/> <!--<i class="el-icon-delete" @click="rmImage"/>-->
</div> <!--</div>-->
</div> <!--</div>-->
</div> <!--</div>-->
<div class="image-preview"> <div class="image-preview">
<div v-show="imageUrl.length>1" class="image-preview-wrapper"> <div v-show="imageUrl.length>1" class="image-preview-wrapper">
<img :src="imageUrl"> <img :src="imageUrl">
...@@ -39,12 +39,16 @@ export default { ...@@ -39,12 +39,16 @@ export default {
value: { value: {
type: String, type: String,
default: '' default: ''
},
type: {
type: String,
default: ''
} }
}, },
data() { data() {
return { return {
tempUrl: '', tempUrl: '',
dataObj: { token: '', key: '' } dataObj: { type: this.type }
} }
}, },
computed: { computed: {
...@@ -60,7 +64,7 @@ export default { ...@@ -60,7 +64,7 @@ export default {
this.$emit('input', val) this.$emit('input', val)
}, },
handleImageSuccess(file) { handleImageSuccess(file) {
this.emitInput(file.files.file) this.emitInput(file.data.file_url)
}, },
beforeUpload() { beforeUpload() {
const _self = this const _self = this
......
...@@ -100,37 +100,5 @@ export const asyncRouterMap = [ ...@@ -100,37 +100,5 @@ export const asyncRouterMap = [
PushRouter, PushRouter,
PickRouter, PickRouter,
TagRouter, TagRouter,
{
path: '/example',
component: Layout,
redirect: '/example/list',
name: 'Example',
meta: {
title: 'example',
icon: 'example'
},
children: [
{
path: 'create',
component: () => import('@/views/example/create'),
name: 'CreateArticle',
meta: { title: 'createArticle', icon: 'edit' }
},
{
path: 'edit/:id(\\d+)',
component: () => import('@/views/example/edit'),
name: 'EditArticle',
meta: { title: 'editArticle', noCache: true },
hidden: true
},
{
path: 'list',
component: () => import('@/views/example/list'),
name: 'ArticleList',
meta: { title: 'articleList', icon: 'list' }
}
]
},
{ path: '*', redirect: '/404', hidden: true } { path: '*', redirect: '/404', hidden: true }
] ]
...@@ -9,7 +9,7 @@ const AccountRouter = { ...@@ -9,7 +9,7 @@ const AccountRouter = {
name: 'Account', name: 'Account',
meta: { meta: {
title: '账号管理', title: '账号管理',
icon: 'example' icon: 'component'
}, },
children: [ children: [
{ {
......
...@@ -9,7 +9,7 @@ const GroupRouter = { ...@@ -9,7 +9,7 @@ const GroupRouter = {
name: 'Group', name: 'Group',
meta: { meta: {
title: '小组管理', title: '小组管理',
icon: 'example' icon: 'component'
}, },
children: [ children: [
{ {
......
...@@ -9,7 +9,7 @@ const PickRouter = { ...@@ -9,7 +9,7 @@ const PickRouter = {
name: 'Pick', name: 'Pick',
meta: { meta: {
title: 'Pick管理', title: 'Pick管理',
icon: 'example' icon: 'component'
}, },
children: [ children: [
{ {
......
...@@ -9,7 +9,7 @@ const PushRouter = { ...@@ -9,7 +9,7 @@ const PushRouter = {
name: 'Push', name: 'Push',
meta: { meta: {
title: 'Push管理', title: 'Push管理',
icon: 'example' icon: 'component'
}, },
children: [ children: [
{ {
......
...@@ -9,7 +9,7 @@ const StarRouter = { ...@@ -9,7 +9,7 @@ const StarRouter = {
name: 'Star', name: 'Star',
meta: { meta: {
title: '明星管理', title: '明星管理',
icon: 'example' icon: 'component'
}, },
children: [ children: [
{ {
......
...@@ -7,7 +7,7 @@ const TagRouter = { ...@@ -7,7 +7,7 @@ const TagRouter = {
name: 'Tag', name: 'Tag',
meta: { meta: {
title: '标签管理', title: '标签管理',
icon: 'example' icon: 'component'
}, },
children: [ children: [
{ {
......
...@@ -9,7 +9,7 @@ const TopicRouter = { ...@@ -9,7 +9,7 @@ const TopicRouter = {
name: 'Topic', name: 'Topic',
meta: { meta: {
title: '帖子管理', title: '帖子管理',
icon: 'example' icon: 'component'
}, },
children: [ children: [
{ {
......
...@@ -9,7 +9,7 @@ const GroupRouter = { ...@@ -9,7 +9,7 @@ const GroupRouter = {
name: 'User', name: 'User',
meta: { meta: {
title: '用户管理', title: '用户管理',
icon: 'example' icon: 'component'
}, },
children: [ children: [
{ {
......
...@@ -5,63 +5,136 @@ ...@@ -5,63 +5,136 @@
<sticky :class-name="'sub-navbar '+postForm.status"> <sticky :class-name="'sub-navbar '+postForm.status">
<el-button v-loading="loading" style="margin-left: 10px;" type="success" @click="submitForm">发布 <el-button v-loading="loading" style="margin-left: 10px;" type="success" @click="submitForm">发布
</el-button> </el-button>
<el-button v-loading="loading" type="warning" @click="draftForm">草稿</el-button>
</sticky> </sticky>
<div class="createPost-main-container"> <div class="createPost-main-container">
<el-row> <el-row :gutter="20">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>小组相关</span>
</div>
<div style="margin-bottom:50px;">
<el-col :span="24">
<el-form-item style="margin-bottom: 20px;" prop="title">
<MDinput v-model="postForm.name" :maxlength="100" name="name" required>
小组名称
</MDinput>
</el-form-item>
<el-col :span="24"> <div class="postInfo-container">
<el-form-item style="margin-bottom: 40px;" prop="title"> <el-row>
<MDinput v-model="postForm.title" :maxlength="100" name="name" required> <el-col :span="8">
标题 <el-form-item label-width="75px" label="明星称号:" class="postInfo-container-item">
</MDinput> <el-select v-model="postForm.star_name" :placeholder="'明星称号'" clearable
class="postInfo-container-item"
style="width: 220px">
<el-option v-for="item in []" :key="item.key" :label="item.display_name"
:value="item.key"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label-width="75px" label="小组组长:" class="postInfo-container-item">
<el-select v-model="postForm.pick_type" :placeholder="'性别:'" clearable
class="postInfo-container-item" style="width:220px">
<el-option v-for="item in []" :key="item.key" :label="item.display_name"
:value="item.key"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item style="margin-bottom: 20px;" label-width="75px" label="组员数量:" prop="desc">
<el-input v-model="postForm.user_nums" type="number" placeholder="请输入内容" style="width: 230px;"
readonly/>
</el-form-item>
</el-col>
</el-row>
</div>
</el-col>
</div>
<el-form-item style="margin-bottom: 20px;" label-width="75px" label="下线小组:">
<el-radio-group v-model="postForm.is_online">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item style="margin-bottom: 20px;" label-width="75px" label="推荐小组:">
<el-radio-group v-model="postForm.is_recommend">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item style="margin-bottom: 20px;" label-width="75px" label="小组简介:">
<el-input :rows="1" v-model="postForm.description" type="textarea" class="article-textarea" autosize
placeholder="请输入内容"/>
<span v-show="contentShortLength" class="word-counter">{{ contentShortLength }}</span>
</el-form-item> </el-form-item>
<div class="postInfo-container">
<el-row>
<el-col :span="8">
<el-form-item label-width="45px" label="作者:" class="postInfo-container-item">
<el-select v-model="postForm.author" :remote-method="getRemoteUserList" filterable remote placeholder="搜索用户">
<el-option v-for="(item,index) in userListOptions" :key="item+index" :label="item" :value="item"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10"> </el-card>
<el-form-item label-width="80px" label="发布时间:" class="postInfo-container-item"> </el-row>
<el-date-picker v-model="postForm.display_time" type="datetime" format="yyyy-MM-dd HH:mm:ss" placeholder="选择日期时间"/>
</el-form-item>
</el-col>
<el-col :span="6"> <el-row :gutter="20" style="margin-top:50px;">
<el-form-item label-width="60px" label="重要性:" class="postInfo-container-item"> <el-card class="box-card">
<el-rate <div slot="header" class="clearfix">
v-model="postForm.importance" <span>组员相关</span>
:max="3"
:colors="['#99A9BF', '#F7BA2A', '#FF9900']"
:low-threshold="1"
:high-threshold="3"
style="margin-top:8px;"/>
</el-form-item>
</el-col>
</el-row>
</div> </div>
</el-col> <div style="margin-bottom:50px;">
</el-row> <div class="filter-container">
<el-input :placeholder="'添加用户'" v-model="listQuery.filter.value" style="width: 180px;"
class="filter-item"
@keyup.enter.native="appendUser"/>
<el-button v-waves class="filter-item" type="primary" icon="el-icon-edit" @click="appendUser">添加
</el-button>
<el-button v-waves class="filter-item" type="primary" icon="el-icon-delete" @click="delUser">移除
</el-button>
</div>
<el-table :data="list" border fit highlight-current-row style="width: 100%"
ref="multipleTable" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="76" align="center"></el-table-column>
<el-table-column align="center" label="用户ID " width="80">
<template slot-scope="scope">
<router-link :to="'/push/edit/'+scope.row.id" class="link-type">
<span>{{ scope.row.id }}</span>
</router-link>
</template>
</el-table-column>
<el-table-column width="190px" align="center" label="用户名">
<template slot-scope="scope">
<span>{{ scope.row.username }}</span>
</template>
</el-table-column>
<el-table-column width="300px" align="center" label="联系电话">
<template slot-scope="scope">
<span>{{ scope.phone }}</span>
</template>
</el-table-column>
<el-table-column width="120px" align="center" label="发布帖子数">
<template slot-scope="scope">
<span>{{ scope.row.topic_nums }}</span>
</template>
</el-table-column>
<el-table-column width="180px" align="center" label="用户身份">
<template slot-scope="scope">
<span>{{ scope.row.user_identity }}</span>
</template>
</el-table-column>
<el-table-column width="180px" align="center" label="组内身份">
<template slot-scope="scope">
<span>{{ scope.row.internal_identity }}</span>
</template>
</el-table-column>
</el-table>
<el-form-item style="margin-bottom: 40px;" label-width="45px" label="摘要:"> <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit"
<el-input :rows="1" v-model="postForm.content_short" type="textarea" class="article-textarea" autosize placeholder="请输入内容"/> style="margin-left: 250px;" @pagination="getList"/>
<span v-show="contentShortLength" class="word-counter">{{ contentShortLength }}</span> </div>
</el-form-item> </el-card>
</el-row>
<div class="editor-container">
<Tinymce ref="editor" :height="400" v-model="postForm.content" />
</div>
<div style="margin-bottom: 20px;">
<Upload v-model="postForm.image_uri" />
</div>
</div> </div>
</el-form> </el-form>
...@@ -69,194 +142,205 @@ ...@@ -69,194 +142,205 @@
</template> </template>
<script> <script>
import Tinymce from '@/components/Tinymce' import MDinput from '@/components/MDinput'
import Upload from '@/components/Upload/singleImage3' import Sticky from '@/components/Sticky' // 粘性header组件
import MDinput from '@/components/MDinput' import waves from '@/directive/waves'
import Sticky from '@/components/Sticky' // 粘性header组件 import Pagination from '@/components/Pagination'
import { validateURL } from '@/utils/validate'
import { fetchArticle } from '@/api/article'
import { userSearch } from '@/api/remoteSearch'
const defaultForm = { import {validateURL} from '@/utils/validate'
status: 'draft', import {fetchList} from '@/api/user'
title: '', // 文章题目 import {userSearch} from '@/api/remoteSearch'
content: '', // 文章内容
content_short: '', // 文章摘要
source_uri: '', // 文章外链
image_uri: '', // 文章图片
display_time: undefined, // 前台展示时间
id: undefined,
platforms: ['a-platform'],
comment_disabled: false,
importance: 0
}
export default { const defaultForm = {
name: 'GroupDetail', status: 'draft',
components: { Tinymce, MDinput, Upload, Sticky}, title: '', // 文章题目
props: { name: '', // 文章内容
isEdit: { description: '', // 文章摘要
type: Boolean, source_uri: '', // 文章外链
default: false image_uri: '', // 文章图片
} display_time: undefined, // 前台展示时间
}, id: undefined,
data() { platforms: ['a-platform'],
const validateRequire = (rule, value, callback) => { comment_disabled: false,
if (value === '') { importance: 0
this.$message({ }
message: rule.field + '为必传项',
type: 'error' export default {
}) name: 'GroupDetail',
callback(new Error(rule.field + '为必传项')) components: {MDinput, Sticky, Pagination},
} else { directives: {waves},
callback() props: {
isEdit: {
type: Boolean,
default: false
} }
} },
const validateSourceUri = (rule, value, callback) => { data() {
if (value) { const validateRequire = (rule, value, callback) => {
if (validateURL(value)) { if (value === '') {
callback()
} else {
this.$message({ this.$message({
message: '外链url填写不正确', message: rule.field + '为必传项',
type: 'error' type: 'error'
}) })
callback(new Error('外链url填写不正确')) callback(new Error(rule.field + '为必传项'))
} else {
callback()
} }
} else {
callback()
} }
} const validateSourceUri = (rule, value, callback) => {
return { if (value) {
postForm: Object.assign({}, defaultForm), if (validateURL(value)) {
loading: false, callback()
userListOptions: [], } else {
rules: { this.$message({
image_uri: [{ validator: validateRequire }], message: '外链url填写不正确',
title: [{ validator: validateRequire }], type: 'error'
content: [{ validator: validateRequire }], })
source_uri: [{ validator: validateSourceUri, trigger: 'blur' }] callback(new Error('外链url填写不正确'))
}, }
tempRoute: {} } else {
} callback()
}, }
computed: { }
contentShortLength() { return {
return this.postForm.content_short.length postForm: Object.assign({}, defaultForm),
}, loading: false,
lang() { userListOptions: [],
return this.$store.getters.language rules: {
} title: [{validator: validateRequire}],
}, content: [{validator: validateRequire}],
created() { },
if (this.isEdit) { tempRoute: {},
const id = this.$route.params && this.$route.params.id
this.fetchData(id)
} else {
this.postForm = Object.assign({}, defaultForm)
}
// Why need to make a copy of this.$route here?
// Because if you enter this page and quickly switch tag, may be in the execution of the setTagsViewTitle function, this.$route is no longer pointing to the current page
// https://github.com/PanJiaChen/vue-element-admin/issues/1221
this.tempRoute = Object.assign({}, this.$route)
},
methods: {
fetchData(id) {
fetchArticle(id).then(response => {
this.postForm = response.data
// Just for test
this.postForm.title += ` Article Id:${this.postForm.id}`
this.postForm.content_short += ` Article Id:${this.postForm.id}`
// Set tagsview title // 小组相关
this.setTagsViewTitle() list: null,
}).catch(err => { total: 1,
console.log(err) listLoading: true,
}) multipleSelection: [],
del_list: [],
listQuery: {
page: 0,
limit: 10,
filter: {
value: '',
key: '',
},
},
}
}, },
setTagsViewTitle() { computed: {
const title = this.lang === 'zh' ? '编辑文章' : 'Edit Article' contentShortLength() {
const route = Object.assign({}, this.tempRoute, { title: `${title}-${this.postForm.id}` }) return this.postForm.content_short.length
this.$store.dispatch('updateVisitedView', route) },
}, },
submitForm() { created() {
this.postForm.display_time = parseInt(this.display_time / 1000) if (this.isEdit) {
console.log(this.postForm) const id = this.$route.params && this.$route.params.id
this.$refs.postForm.validate(valid => { this.fetchData(id)
if (valid) { this.getList()
this.loading = true } else {
this.$notify({ this.postForm = Object.assign({}, defaultForm)
title: '成功', }
message: '发布文章成功',
type: 'success', this.tempRoute = Object.assign({}, this.$route)
duration: 2000
})
this.postForm.status = 'published'
this.loading = false
} else {
console.log('error submit!!')
return false
}
})
}, },
draftForm() { methods: {
if (this.postForm.content.length === 0 || this.postForm.title.length === 0) { fetchData(id) {
this.$message({ fetchArticle(id).then(response => {
message: '请填写必要的标题和内容', this.postForm = response.data
type: 'warning' }).catch(err => {
console.log(err)
})
},
submitForm() {
this.postForm.display_time = parseInt(this.display_time / 1000)
console.log(this.postForm)
this.$refs.postForm.validate(valid => {
if (valid) {
this.loading = true
this.$notify({
title: '成功',
message: '发布文章成功',
type: 'success',
duration: 2000
})
this.postForm.status = 'published'
this.loading = false
} else {
console.log('error submit!!')
return false
}
})
},
getRemoteUserList(query) {
userSearch(query).then(response => {
if (!response.data.items) return
this.userListOptions = response.data.items.map(v => v.name)
})
},
// 添加组员相关
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
appendUser() {
},
delUser() {
},
getList() {
this.listLoading = true
fetchList(this.listQuery).then(response => {
this.list = []
this.total = 100
this.listLoading = false
}) })
return
} }
this.$message({
message: '保存成功',
type: 'success',
showClose: true,
duration: 1000
})
this.postForm.status = 'draft'
},
getRemoteUserList(query) {
userSearch(query).then(response => {
if (!response.data.items) return
this.userListOptions = response.data.items.map(v => v.name)
})
} }
} }
}
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>
@import "src/styles/mixin.scss"; @import "src/styles/mixin.scss";
.createPost-container {
position: relative; .createPost-container {
.createPost-main-container { position: relative;
padding: 40px 45px 20px 50px; .createPost-main-container {
.postInfo-container { padding: 40px 45px 20px 50px;
position: relative; .postInfo-container {
@include clearfix; position: relative;
margin-bottom: 10px; @include clearfix;
.postInfo-container-item { margin-bottom: 10px;
float: left; .postInfo-container-item {
float: left;
}
} }
} .editor-container {
.editor-container { min-height: 500px;
min-height: 500px; margin: 0 0 30px;
margin: 0 0 30px; .editor-upload-btn-container {
.editor-upload-btn-container { text-align: right;
text-align: right; margin-right: 10px;
margin-right: 10px; .editor-upload-btn {
.editor-upload-btn { display: inline-block;
display: inline-block; }
} }
} }
} }
.word-counter {
width: 40px;
position: absolute;
right: -10px;
top: 0px;
}
} }
.word-counter {
width: 40px;
position: absolute;
right: -10px;
top: 0px;
}
}
</style> </style>
...@@ -5,75 +5,44 @@ ...@@ -5,75 +5,44 @@
<el-select v-model="listQuery.filter.key" :placeholder="'搜索字段'" clearable class="filter-item" style="width: 110px"> <el-select v-model="listQuery.filter.key" :placeholder="'搜索字段'" clearable class="filter-item" style="width: 110px">
<el-option v-for="item in SearchTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/> <el-option v-for="item in SearchTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
</el-select> </el-select>
<el-select v-model="listQuery.filter.is_online" :placeholder="'上线'" clearable class="filter-item" style="width: 100px">
<el-option v-for="item in BooleanTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
</el-select>
<el-select v-model="listQuery.filter.is_recommend" :placeholder="'推荐'" clearable class="filter-item" style="width: 100px">
<el-option v-for="item in ReBooleanTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
</el-select>
<el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">搜索</el-button> <el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">搜索</el-button>
<el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate">创建</el-button> <el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate">创建</el-button>
<el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleOfflineOrOnline('offline')">下线</el-button>
<el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleOfflineOrOnline('online')">上线</el-button>
<el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleOfflineOrOnline('recommend')">推荐</el-button>
</div> </div>
<el-table v-loading="listLoading" :data="list" border fit highlight-current-row style="width: 100%" ref="multipleTable" @selection-change="handleSelectionChange"> <el-table v-loading="listLoading" :data="list" border fit highlight-current-row style="width: 100%" ref="multipleTable" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center"></el-table-column> <el-table-column type="selection" width="55" align="center"></el-table-column>
<el-table-column align="center" label="小组ID " width="80"> <el-table-column align="center" label="推送ID " width="80">
<template slot-scope="scope"> <template slot-scope="scope">
<router-link :to="'/pick/edit/'+scope.row.id" class="link-type"> <router-link :to="'/push/edit/'+scope.row.id" class="link-type">
<span>{{ scope.row.id }}</span> <span>{{ scope.row.id }}</span>
</router-link> </router-link>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column width="190px" align="center" label="小组名称"> <el-table-column width="190px" align="center" label="推送内容">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ scope.row.name }}</span> <span>{{ scope.row.content }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column width="300px" align="center" label="小组简介"> <el-table-column width="300px" align="center" label="推送时间">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ scope.row.desc }}</span> <span>{{ scope.row.push_time }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column width="120px" align="center" label="明星名称"> <el-table-column width="120px" align="center" label="创建时间">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ scope.row.star.name }}</span> <span>{{ scope.row.create_time }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column width="80px" align="center" label="用户数"> <el-table-column width="80px" align="center" label="创建用户">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ scope.row.user_nums }}</span> <span>{{ scope.row.creator }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column width="80px" align="center" label="帖子数">
<template slot-scope="scope">
<span>{{ scope.row.topic_nums }}</span>
</template>
</el-table-column>
<el-table-column width="140px" align="center" label="组长">
<template slot-scope="scope">
<span>{{ scope.row.creator.name }}</span>
</template>
</el-table-column>
<el-table-column width="80px" align="center" label="下线">
<template slot-scope="scope">
<el-tag :type="scope.row.is_online | isOnlineFilter">{{ scope.row.is_online==1 ? '是' : '否' }}</el-tag>
</template>
</el-table-column>
<el-table-column width="80px" align="center" label="推荐">
<template slot-scope="scope">
<el-tag :type="scope.row.is_recommend | isOnlineFilter">{{ scope.row.is_recommend==1 ? '是' : '否' }}</el-tag>
</template>
</el-table-column>is_recommend
</el-table> </el-table>
...@@ -90,30 +59,12 @@ import waves from '@/directive/waves' ...@@ -90,30 +59,12 @@ import waves from '@/directive/waves'
export default { export default {
name: 'GroupList', name: 'GroupList',
components: { Pagination }, components: { Pagination },
filters: {
isOnlineFilter(status) {
const statusMap = {
1: 'success',
0: 'info',
}
return statusMap[status]
},
genderFilter(status) {
const statusMap = {
'男': 'success',
'女': 'info',
'全部': 'danger'
}
return statusMap[status]
},
},
directives: { waves }, directives: { waves },
data() { data() {
return { return {
list: null, list: null,
total: 0, total: 0,
listLoading: true, listLoading: true,
multipleSelection: [],
del_list: [], del_list: [],
listQuery: { listQuery: {
page: 0, page: 0,
...@@ -121,22 +72,11 @@ export default { ...@@ -121,22 +72,11 @@ export default {
filter: { filter: {
value: '', value: '',
key: '', key: '',
is_online: '',
is_recommend: '',
}, },
}, },
BooleanTypeOptions: [
{'key': 1, 'display_name': '是'},
{'key': 0, 'display_name': '否'}
],
ReBooleanTypeOptions: [
{'key': 1, 'display_name': '是'},
{'key': 0, 'display_name': '否'}
],
SearchTypeOptions:[ SearchTypeOptions:[
{'key': 'id', 'display_name': '小组ID'}, {'key': 'id', 'display_name': '推送ID'},
{'key': 'name', 'display_name': '小组名称'}, {'key': 'content', 'display_name': '推送内容'},
{'key': 'star_name', 'display_name': '明星名称'},
] ]
} }
}, },
...@@ -152,9 +92,6 @@ export default { ...@@ -152,9 +92,6 @@ export default {
this.listLoading = false this.listLoading = false
}) })
}, },
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleSizeChange(val) { handleSizeChange(val) {
this.listQuery.limit = val this.listQuery.limit = val
this.getList() this.getList()
...@@ -163,31 +100,12 @@ export default { ...@@ -163,31 +100,12 @@ export default {
this.listQuery.page = val this.listQuery.page = val
this.getList() this.getList()
}, },
handleOfflineOrOnline(val){
const length = this.multipleSelection.length;
let str = '';
this.del_list = this.del_list.concat(this.multipleSelection);
for (let i = 0; i < length; i++) {
if (val === 'offline'){
this.multipleSelection[i].is_online = 0
} else if(val === 'recommend'){
this.multipleSelection[i].is_recommend = 1
} else{
this.multipleSelection[i].is_online = 1
}
str += this.multipleSelection[i].id + ' ';
}
OffLineOrOnLine({type:val, ids:str}).then(response => {
this.multipleSelection = [];
this.$message.success(response.data.data.message);
})
},
handleFilter() { handleFilter() {
this.listQuery.page = 0 this.listQuery.page = 0
this.getList() this.getList()
}, },
handleCreate() { handleCreate() {
this.$router.push('/pick/create') this.$router.push('/push/create')
} }
} }
} }
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<size-select class="international right-menu-item"/> <size-select class="international right-menu-item"/>
</el-tooltip> </el-tooltip>
<lang-select class="international right-menu-item"/>
<el-tooltip :content="$t('navbar.theme')" effect="dark" placement="bottom"> <el-tooltip :content="$t('navbar.theme')" effect="dark" placement="bottom">
<theme-picker class="theme-switch right-menu-item"/> <theme-picker class="theme-switch right-menu-item"/>
</el-tooltip> </el-tooltip>
...@@ -56,6 +56,7 @@ import ErrorLog from '@/components/ErrorLog' ...@@ -56,6 +56,7 @@ import ErrorLog from '@/components/ErrorLog'
import Screenfull from '@/components/Screenfull' import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect' import SizeSelect from '@/components/SizeSelect'
import ThemePicker from '@/components/ThemePicker' import ThemePicker from '@/components/ThemePicker'
import LangSelect from '@/components/LangSelect'
export default { export default {
components: { components: {
...@@ -64,7 +65,8 @@ export default { ...@@ -64,7 +65,8 @@ export default {
ErrorLog, ErrorLog,
Screenfull, Screenfull,
SizeSelect, SizeSelect,
ThemePicker ThemePicker,
LangSelect
}, },
computed: { computed: {
...mapGetters([ ...mapGetters([
......
...@@ -3,9 +3,8 @@ ...@@ -3,9 +3,8 @@
<el-form ref="postForm" :model="postForm" :rules="rules" class="form-container"> <el-form ref="postForm" :model="postForm" :rules="rules" class="form-container">
<sticky :class-name="'sub-navbar '+postForm.status"> <sticky :class-name="'sub-navbar '+postForm.status">
<el-button v-loading="loading" style="margin-left: 10px;" type="success" @click="submitForm">发布 <el-button v-loading="loading" style="margin-left: 10px;" type="success" @click="submitForm">保存
</el-button> </el-button>
<el-button v-loading="loading" type="warning" @click="draftForm">草稿</el-button>
</sticky> </sticky>
<div class="createPost-main-container"> <div class="createPost-main-container">
...@@ -14,35 +13,44 @@ ...@@ -14,35 +13,44 @@
<el-col :span="24"> <el-col :span="24">
<el-form-item style="margin-bottom: 40px;" prop="title"> <el-form-item style="margin-bottom: 40px;" prop="title">
<MDinput v-model="postForm.title" :maxlength="100" name="name" required> <MDinput v-model="postForm.title" :maxlength="100" name="name" required>
标题 推送标题
</MDinput> </MDinput>
</el-form-item> </el-form-item>
<div class="postInfo-container"> <div class="postInfo-container">
<el-row> <el-row>
<el-col :span="8"> <el-col :span="12">
<el-form-item label-width="45px" label="作者:" class="postInfo-container-item"> <el-form-item style="margin-bottom: 40px;" label-width="75px" label="推送ID:" prop="id" v-if="isEdit">
<el-select v-model="postForm.author" :remote-method="getRemoteUserList" filterable remote placeholder="搜索用户"> <el-input :rows="1" v-model="postForm.id" type="text" class="article-textarea"
<el-option v-for="(item,index) in userListOptions" :key="item+index" :label="item" :value="item"/> style="width: 300px" readonly v-if="isEdit"/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="10">
<el-form-item label-width="80px" label="发布时间:" class="postInfo-container-item"> <el-form-item style="margin-bottom: 40px;" label-width="75px" label="创建时间:" prop="create_time" v-if="isEdit">
<el-date-picker v-model="postForm.display_time" type="datetime" format="yyyy-MM-dd HH:mm:ss" placeholder="选择日期时间"/> <el-input :rows="1" v-model="postForm.create_time" type="text" class="article-textarea"
style="width: 300px" readonly v-if="isEdit"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item style="margin-bottom: 40px;" label-width="75px" label="推送落地:" prop="url" >
<el-input :rows="1" v-model="postForm.url" type="text" class="article-textarea"
style="width: 300px"/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="10">
<el-form-item label-width="60px" label="重要性:" class="postInfo-container-item"> <el-form-item label-width="80px" label="推送时间:" class="postInfo-container-item" prop="push_time" >
<el-rate <el-date-picker
v-model="postForm.importance" v-model="postForm.push_time"
:max="3" type="datetime"
:colors="['#99A9BF', '#F7BA2A', '#FF9900']" format="yyyy-MM-dd HH:mm:ss"
:low-threshold="1" placeholder="选择日期时间"
:high-threshold="3" style="width: 300px"
style="margin-top:8px;"/> :picker-options="expireTimeOption"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
...@@ -50,17 +58,16 @@ ...@@ -50,17 +58,16 @@
</el-col> </el-col>
</el-row> </el-row>
<el-form-item style="margin-bottom: 40px;" label-width="45px" label="摘要:"> <el-form-item style="margin-bottom: 40px;" label-width="75px" label="推送内容:" prop="content">
<el-input :rows="1" v-model="postForm.content_short" type="textarea" class="article-textarea" autosize placeholder="请输入内容"/> <el-input :rows="1" v-model="postForm.content" type="textarea" class="article-textarea" autosize placeholder="请输入内容"/>
<span v-show="contentShortLength" class="word-counter">{{ contentShortLength }}</span> <span v-show="contentShortLength" class="word-counter">{{ contentShortLength }}</span>
</el-form-item> </el-form-item>
<div class="editor-container">
<Tinymce ref="editor" :height="400" v-model="postForm.content" />
</div>
<div style="margin-bottom: 20px;"> <div style="margin-bottom: 20px;">
<Upload v-model="postForm.image_uri" /> <el-form-item style="margin-bottom: 40px;" label-width="75px" label="推送头像:" prop="icon">
<span v-model="type"></span>
<Upload v-model="postForm.icon" :type="type"/>
</el-form-item>
</div> </div>
</div> </div>
</el-form> </el-form>
...@@ -69,31 +76,24 @@ ...@@ -69,31 +76,24 @@
</template> </template>
<script> <script>
import Tinymce from '@/components/Tinymce'
import Upload from '@/components/Upload/singleImage3' import Upload from '@/components/Upload/singleImage3'
import MDinput from '@/components/MDinput' import MDinput from '@/components/MDinput'
import Sticky from '@/components/Sticky' // 粘性header组件 import Sticky from '@/components/Sticky' // 粘性header组件
import { validateURL } from '@/utils/validate' import { validateURL } from '@/utils/validate'
import { fetchArticle } from '@/api/article' import { fetchPushDetail, CreatePush } from '@/api/push'
import { userSearch } from '@/api/remoteSearch'
const defaultForm = { const defaultForm = {
status: 'draft', status: 'draft',
title: '', // 文章题目 title: '',
content: '', // 文章内容 content: '',
content_short: '', // 文章摘要 icon: '',
source_uri: '', // 文章外链 push_time: '',
image_uri: '', // 文章图片 url: '',
display_time: undefined, // 前台展示时间
id: undefined,
platforms: ['a-platform'],
comment_disabled: false,
importance: 0
} }
export default { export default {
name: 'ArticleDetail', name: 'PushDetail',
components: { Tinymce, MDinput, Upload, Sticky}, components: { MDinput, Upload, Sticky},
props: { props: {
isEdit: { isEdit: {
type: Boolean, type: Boolean,
...@@ -112,41 +112,31 @@ export default { ...@@ -112,41 +112,31 @@ export default {
callback() callback()
} }
} }
const validateSourceUri = (rule, value, callback) => {
if (value) {
if (validateURL(value)) {
callback()
} else {
this.$message({
message: '外链url填写不正确',
type: 'error'
})
callback(new Error('外链url填写不正确'))
}
} else {
callback()
}
}
return { return {
postForm: Object.assign({}, defaultForm), postForm: Object.assign({}, defaultForm),
loading: false, loading: false,
userListOptions: [], userListOptions: [],
expireTimeOption: {
disabledDate(date){
return date.getTime() <= Date.now();
}
},
rules: { rules: {
image_uri: [{ validator: validateRequire }], title: [{ validator: validateRequire, trigger: 'blur'}],
title: [{ validator: validateRequire }], content: [{ validator: validateRequire, trigger: 'blur'}],
content: [{ validator: validateRequire }], url: [{ validator: validateRequire, trigger: 'blur'}],
source_uri: [{ validator: validateSourceUri, trigger: 'blur' }] icon: [{ validator: validateRequire, trigger: 'blur'}],
push_time: [{ validator: validateRequire, trigger: 'blur'}],
}, },
tempRoute: {} tempRoute: {},
dataObj: { token: 'fahsdfiwqehfkajsdhfjkasdhfkj', key: 'fasdhfkasdhfkjashdfkjhasdfads' },
type: '1' // 图片类型
} }
}, },
computed: { computed: {
contentShortLength() { contentShortLength() {
return this.postForm.content_short.length return this.postForm.content.length
}, },
lang() {
return this.$store.getters.language
}
}, },
created() { created() {
if (this.isEdit) { if (this.isEdit) {
...@@ -156,72 +146,48 @@ export default { ...@@ -156,72 +146,48 @@ export default {
this.postForm = Object.assign({}, defaultForm) this.postForm = Object.assign({}, defaultForm)
} }
// Why need to make a copy of this.$route here?
// Because if you enter this page and quickly switch tag, may be in the execution of the setTagsViewTitle function, this.$route is no longer pointing to the current page
// https://github.com/PanJiaChen/vue-element-admin/issues/1221
this.tempRoute = Object.assign({}, this.$route) this.tempRoute = Object.assign({}, this.$route)
}, },
methods: { methods: {
fetchData(id) { fetchData(id) {
fetchArticle(id).then(response => { fetchPushDetail(id).then(response => {
this.postForm = response.data this.postForm = response.data.data.data
// Just for test }).catch(err => {
this.postForm.title += ` Article Id:${this.postForm.id}`
this.postForm.content_short += ` Article Id:${this.postForm.id}`
// Set tagsview title
this.setTagsViewTitle()
}).catch(err => {
console.log(err) console.log(err)
}) })
}, },
setTagsViewTitle() {
const title = this.lang === 'zh' ? '编辑文章' : 'Edit Article'
const route = Object.assign({}, this.tempRoute, { title: `${title}-${this.postForm.id}` })
this.$store.dispatch('updateVisitedView', route)
},
submitForm() { submitForm() {
this.postForm.display_time = parseInt(this.display_time / 1000)
console.log(this.postForm)
this.$refs.postForm.validate(valid => { this.$refs.postForm.validate(valid => {
if (valid) { if (valid) {
this.loading = true this.loading = true
this.$notify({ CreatePush(this.postForm).then(response => {
title: '成功', this.$notify({
message: '发布文章成功', title: '成功',
type: 'success', message: response.data.data.message,
duration: 2000 type: 'success',
}) duration: 2000
this.postForm.status = 'published' })
this.loading = false setTimeout(() => {
this.$router.push('/push/list')
}, 1000)
}).catch(err => {
this.$notify({
title: '失败',
message: '操作失败',
type: 'danger',
duration: 2000
})
});
this.postForm.status = 'published'
this.loading = false
} else { } else {
console.log('error submit!!') console.log('error submit!!')
return false return false
} }
}) })
}, },
draftForm() {
if (this.postForm.content.length === 0 || this.postForm.title.length === 0) {
this.$message({
message: '请填写必要的标题和内容',
type: 'warning'
})
return
}
this.$message({
message: '保存成功',
type: 'success',
showClose: true,
duration: 1000
})
this.postForm.status = 'draft'
},
getRemoteUserList(query) {
userSearch(query).then(response => {
if (!response.data.items) return
this.userListOptions = response.data.items.map(v => v.name)
})
}
} }
} }
</script> </script>
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
<el-table-column width="150px" align="center" label="小组数量"> <el-table-column width="150px" align="center" label="小组数量">
<template slot-scope="scope"> <template slot-scope="scope">
<router-link :to="'/pick/edit/'+scope.row.id" class="link-type"> <router-link :to="'/pick/edit/'+scope.row.id" class="link-type">
<span>{{ scope.row.group_nums }}</span> <span>{{ scope.row.group_counts }}</span>
</router-link> </router-link>
</template> </template>
</el-table-column> </el-table-column>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment