Commit 811e6beb authored by qiaobin's avatar qiaobin

Merge remote-tracking branch 'origin/dev' into dev

parents 4342c751 b8ea022c
VUE_APP_URL = 'http://localhost:8297/' VUE_APP_URL = 'http://localhost:8297/'
\ No newline at end of file VUE_APP_WEBSOCKET = 'ws://localhost:8297/websocket'
\ No newline at end of file
NODE_ENV=production NODE_ENV=production
VUE_APP_URL = 'http://172.16.1.55:8297/' VUE_APP_URL = 'http://172.16.1.55:8297/'
\ No newline at end of file VUE_APP_WEBSOCKET = 'ws://172.16.1.55:8297/websocket'
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
"@antv/g2": "4.2.4", "@antv/g2": "4.2.4",
"@babel/polyfill": "7.0.0", "@babel/polyfill": "7.0.0",
"@babel/runtime": "7.2.0", "@babel/runtime": "7.2.0",
"@tinymce/tinymce-vue": "2.1.0",
"ant-design-vue": "1.7.8", "ant-design-vue": "1.7.8",
"axios": "0.18.0", "axios": "0.18.0",
"dayjs": "1.7.7", "dayjs": "1.7.7",
...@@ -25,12 +24,12 @@ ...@@ -25,12 +24,12 @@
"lodash.get": "4.4.2", "lodash.get": "4.4.2",
"lodash.pick": "4.4.0", "lodash.pick": "4.4.0",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"tinymce": "5.0.8", "simple-lightbox": "^2.1.0",
"vue": "2.6.11", "vue": "2.6.11",
"vue-cropper": "0.4.4",
"vue-ls": "3.2.0", "vue-ls": "3.2.0",
"vue-router": "3.0.1", "vue-router": "3.0.1",
"vuex": "3.0.1" "vuex": "3.0.1",
"wangeditor": "^4.7.5"
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-transform-runtime": "7.2.0", "@babel/plugin-transform-runtime": "7.2.0",
......
import { axios } from '@/util/axios/request'
const BASE_URL = '/home/notice'
export function getPage(data) {
return axios({
url: `${BASE_URL}/page`,
method: 'post',
data
})
}
export function getDetail(id) {
return axios({
url: `${BASE_URL}/${id}`,
method: 'get',
})
}
export function save(data) {
return axios({
url: `${BASE_URL}/save-or-update`,
method: 'post',
data
})
}
export function deleteOne(id) {
return axios({
url: `${BASE_URL}/${id}`,
method: 'delete',
})
}
\ No newline at end of file
import { axios } from '@/util/axios/request'
const BASE_URL = '/order'
export function getPage(data) {
return axios({
url: `${BASE_URL}/page`,
method: 'post',
data
})
}
export function getDetail(id) {
return axios({
url: `${BASE_URL}/${id}`,
method: 'get',
})
}
// 指派估价员
export function dispatchValuator(data) {
return axios({
url: `${BASE_URL}/valuation`,
method: 'post',
useFullLoading: true,
data
})
}
// 重新指派估价员
export function reDispatchValuator(data) {
return axios({
url: `${BASE_URL}/revaluation`,
method: 'post',
useFullLoading: true,
data
})
}
// 确定价格发送订单
export function sendPrice(data) {
return axios({
url: `${BASE_URL}/send`,
method: 'post',
useFullLoading: true,
data
})
}
export function dispatchWorker(data) {
return axios({
url: `${BASE_URL}/dispatch`,
method: 'post',
useFullLoading: true,
data
})
}
export function reDispatchWorker(data) {
return axios({
url: `${BASE_URL}/redispatch`,
method: 'post',
useFullLoading: true,
data
})
}
export function finishOrder(data) {
return axios({
url: `${BASE_URL}/finish`,
method: 'post',
useFullLoading: true,
data
})
}
// 订单状态
export const STATUS = {
RESERVE: 1, // 已提交
VALUATION: 2, // 待估价
SEND: 3, // 已估价,待支付
PAY: 4, // 已付款
DISPATCH: 5, // 已派单
}
\ No newline at end of file
import { axios } from '@/util/axios/request'
const BASE_URL = '/service/promote'
export function getPage(data) {
return axios({
url: `${BASE_URL}/page`,
method: 'post',
data
})
}
...@@ -42,4 +42,13 @@ export function saveOrUpdateSubClass(data) { ...@@ -42,4 +42,13 @@ export function saveOrUpdateSubClass(data) {
method: 'post', method: 'post',
data data
}) })
}
export function getSubClassSelectable() {
return axios({
url: `${BASE_URL}/subclass-selectable`,
method: 'get',
})
} }
\ No newline at end of file
import {axios} from '@/util/axios/request' import { axios } from '@/util/axios/request'
const api = { const api = {
getPage: '/sys/role/page', getPage: '/sys/role/page',
...@@ -46,3 +46,11 @@ export function changeStatus(id) { ...@@ -46,3 +46,11 @@ export function changeStatus(id) {
useFullLoading: true useFullLoading: true
}) })
} }
export function getAll() {
return axios({
url: '/sys/role/all-available',
method: 'get'
})
}
\ No newline at end of file
import { axios } from '@/util/axios/request'
const BASE_URL = '/valuator'
export function getValuators(name) {
return axios({
url: `${BASE_URL}/search`,
params: { name }
})
}
\ No newline at end of file
import { axios } from '@/util/axios/request'
const BASE_URL = '/worker'
export function searchWorkers(name) {
return axios({
url: `${BASE_URL}/search`,
params: { name }
})
}
export function getPage(data) {
return axios({
url: `${BASE_URL}/page`,
method: 'post',
data
})
}
export function getDetail(id) {
return axios({
url: `${BASE_URL}/${id}`,
method: 'get'
})
}
export function save(data) {
return axios({
url: `${BASE_URL}/save`,
method: 'post',
data
})
}
export function update(data) {
return axios({
url: `${BASE_URL}/update`,
method: 'post',
data
})
}
export function deleteWorker(id) {
return axios({
url: `${BASE_URL}/delete/${id}`,
method: 'delete',
})
}
\ No newline at end of file
...@@ -146,7 +146,6 @@ export default { ...@@ -146,7 +146,6 @@ export default {
* @returns 图片url数组 * @returns 图片url数组
* */ * */
getValue() { getValue() {
console.info(this.imageList)
return this.getImageUrlList(this.imageList) return this.getImageUrlList(this.imageList)
} }
}, },
......
<!--
基于wangEditor的vue的富文本编辑器,请通过组件的ref直接设置和获取富文本内容
由于wangEditor本身的特性(也许是bug),通过双向绑定和回调函数的方式直接修改外部的内容变量会引发末尾回车键失效的问题
文档地址 https://www.wangeditor.com/doc/
-->
<template>
<a-spin :spinning="loading">
<div class="wangeditor-atkj-wrapper" :id="id"></div>
</a-spin>
</template>
<script>
// 引入 wangEditor
import wangEditor from 'wangeditor'
export default {
name: 'RichTextEditor',
props: {
id: {
type: String,
default: () => 'wangeditor-atkj-wrapper-default-id'
},
height: {
type: Number,
default: () => 300
},
videoSizeLimit: {
type: Number,
default: () => 100
},
isSessionStorage: {
type: Boolean,
default: () => true
}
},
data() {
return {
editor: null,
loading: false
}
},
beforeDestroy() {
this.editor.destroy()
this.editor = null
},
mounted() {
if (this.editor != null) {
return
}
this.init()
},
activated() {
if (this.editor != null) {
return
}
this.init()
},
methods: {
// 设置内容
setContent(v) {
this.editor.txt.html(v)
},
// 获取内容
getContent() {
return this.editor.txt.html()
},
// 清空内容
clear() {
this.editor.txt.clear()
},
init() {
const _this = this
const editor = new wangEditor(`.wangeditor-atkj-wrapper#${this.id}`)
// 配置 onchange 回调函数,将数据同步到 vue 中
editor.config.showLinkImg = false //关闭网络路径图片方式
editor.config.uploadImgServer = `${process.env.VUE_APP_URL}upload?fileType=IMG`
editor.config.uploadFileName = 'files' // formdata中的name属性
var token = ''
if (this.isSessionStorage) {
token = sessionStorage.getItem('Access-Token')
} else {
token = localStorage.getItem('Access-Token')
}
editor.config.uploadImgHeaders = {
// 设置请求头
Authorization: token // 设置请求头
}
// 设置高度
editor.config.height = this.height
editor.config.uploadVideoServer = `${process.env.VUE_APP_URL}upload?fileType=VIDEO`
editor.config.uploadVideoName = 'files'
editor.config.uploadVideoHeaders = {
Authorization: localStorage.getItem('token') // 设置请求头
}
editor.config.uploadVideoMaxSize = 1024 * this.videoSizeLimit
editor.config.zIndex = 0
editor.config.uploadImgHooks = {
// 图片上传并返回结果,但图片插入错误时触发
fail: function (xhr, editor, result) {
console.error('richTextError', result)
},
// eslint-disable-next-line no-unused-vars
success: function (xhr, editor, result) {
// 图片上传并返回结果,图片插入成功之后触发
},
/**
* insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
* result 即服务端返回的接口
*/
customInsert: function (insertImgFn, result) {
insertImgFn(result.data.urls[0])
}
}
editor.config.uploadVideoHooks = {
// 视频上传并返回了结果,想要自己把视频插入到编辑器中
// 例如服务器端返回的不是 { errno: 0, data: { url : '.....'} } 这种格式,可使用 customInsert
customInsert: function (insertVideoFn, result) {
// result 即服务端返回的接口
// insertVideoFn 可把视频插入到编辑器,传入视频 src ,执行函数即可
if (result.code == 200) {
insertVideoFn(result.data.urls[0])
} else {
_this.$message.error('上传失败')
_this.loading = false
}
},
before() {
_this.loading = true
},
fail() {
_this.loading = false
},
// 上传视频出错,一般为 http 请求的错误
error() {
_this.loading = false
},
// 上传视频超时
timeout() {
_this.loading = false
}
}
// 自定义插入视频, 主要用来处理loading状态
editor.config.customInsertVideo = function (url) {
const videoElement = document.createElement('video')
videoElement.setAttribute('controls', 'controls')
videoElement.setAttribute('style', 'max-width:100%')
videoElement.setAttribute('src', url)
// 4、loadeddata:视频下载监听。当当前帧的数据已加载,但没有足够的数据来播放指定音频/视频的下一帧时触发
// eslint-disable-next-line no-unused-vars
videoElement.addEventListener('loadeddata', function (e) {
_this.loading = false
})
/**
* 此处参考
* https://github.com/wangeditor-team/wangEditor/blob/master/src/editor/command.ts insertElem
*/
const range = editor.selection.getRange()
if (range == null) return
if (range.insertNode) {
range.insertNode(videoElement)
}
}
// 内容change
// eslint-disable-next-line no-unused-vars
editor.config.onchange = (_newHtml) => {}
// 创建编辑器
editor.create()
this.editor = editor
}
},
// beforeDestroy() {
// 调用销毁 API 对当前编辑器实例进行销毁
// }
}
</script>
<style lang="less">
.wangeditor-atkj-wrapper {
.home {
width: 1200px;
margin: auto;
position: relative;
}
.home .btn {
position: absolute;
right: 0;
top: 0;
padding: 5px 10px;
cursor: pointer;
}
.home h3 {
margin: 30px 0 15px;
}
.w-e-text-container {
border: 1px solid #c9d8db;
border-top: none;
z-index: 25;
}
.w-e-toolbar {
z-index: 28 !important;
}
}
</style>
<template>
<div class="tinymce-editor">
<editor
v-model="myValue"
:init="init"
>
</editor>
</div>
</template>
<script>
import {axios} from '@/util/axios/request'
import tinymce from 'tinymce/tinymce'
import Editor from '@tinymce/tinymce-vue'
import 'tinymce/themes/silver'
// // 编辑器插件plugins
// import 'tinymce/themes/modern/theme'
import 'tinymce/plugins/image'
import 'tinymce/plugins/media'
import 'tinymce/plugins/table'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/wordcount'
import 'tinymce/plugins/colorpicker'
const initParam = {
language_url: '/tinymce/langs/zh_CN.js',
language: 'zh_CN',
skin_url: '/tinymce/skins/ui/oxide',
height: 600,
plugins: `lists image media table wordcount `,
paste_auto_cleanup_on_paste : true,
paste_remove_styles: true,
paste_remove_styles_if_webkit: true,
paste_strip_class_attributes: true,
toolbar: `undo redo | formatselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | lists image media table | removeformat`,
fontsize_formats: "8px 10px 12px 14px 16px 18px 24px 36px",
lineheight_formats: "8pt 9pt 10pt 11pt 12pt 14pt 16pt 18pt 20pt 22pt 24pt 26pt 36pt",
content_style: `
* { padding:0; margin:0; }
html, body { height:100%; }
img { max-width:100%; display:block;height:auto; }
a { text-decoration: none; }
iframe { width: 100%; }
p { line-height:1.6; margin: 0px; }
table { word-wrap:break-word; word-break:break-all; max-width:100%; border:none; border-color:#999; }
.mce-object-iframe { width:100%; box-sizing:border-box; margin:0; padding:0; }
ul,ol { list-style-position:inside; }
`,
style_formats: [
{
title: '首行缩进',
block: 'p',
styles: { 'text-indent': '2em' }
},
{
title: '行高',
items: [
{ title: '1', styles: { 'line-height': '1' }, inline: 'span' },
{ title: '1.5', styles: { 'line-height': '1.5' }, inline: 'span' },
{ title: '2', styles: { 'line-height': '2' }, inline: 'span' },
{ title: '2.5', styles: { 'line-height': '2.5' }, inline: 'span' },
{ title: '3', styles: { 'line-height': '3' }, inline: 'span' }
]
}
],
font_formats: `
微软雅黑=微软雅黑;
宋体=宋体;
黑体=黑体;
仿宋=仿宋;
楷体=楷体;
隶书=隶书;
幼圆=幼圆;
Andale Mono=andale mono,times;
Arial=arial, helvetica,
sans-serif;
Arial Black=arial black, avant garde;
Book Antiqua=book antiqua,palatino;
Comic Sans MS=comic sans ms,sans-serif;
Courier New=courier new,courier;
Georgia=georgia,palatino;
Helvetica=helvetica;
Impact=impact,chicago;
Symbol=symbol;
Tahoma=tahoma,arial,helvetica,sans-serif;
Terminal=terminal,monaco;
Times New Roman=times new roman,times;
Trebuchet MS=trebuchet ms,geneva;
Verdana=verdana,geneva;
Webdings=webdings;
Wingdings=wingdings,zapf dingbats`,
branding: false,
menubar: false,
images_upload_handler: function (blobInfo, success, failure) {
let formdata = new FormData()
formdata.set('file', blobInfo.blob())
axios({
url: '/common/upload/file/richText/img',
method: 'post',
data: formdata,
}).then(resp => {
if (resp && resp.code == SYS_CONST.REQUEST.SUCCEED) {
success(resp.data.url)
} else {
failure('error' + resp)
}
})
}
}
export default {
components: {
Editor
},
props: {
value: {
type: String,
default: ''
},
},
data () {
return {
init: initParam,
myValue: this.value,
}
},
mounted () {
tinymce.init({})
},
methods: {
// // 添加相关的事件,可用的事件参照文档=> https://github.com/tinymce/tinymce-vue => All available events
// // 需要什么事件可以自己增加
// onClick (e) {
// this.$emit('onClick', e, tinymce)
// },
// // 可以添加一些自己的自定义事件,如清空内容
// clear () {
// this.myValue = ''
// }
// show(content){
// this.$nextTick(() => {
// this.$emit('input', content);
// });
// this.$emit('input', content);
// }
},
watch: {
value (newValue) {
this.myValue = newValue
},
myValue (newValue) {
this.$emit('input', newValue)
}
}
}
</script>
...@@ -162,7 +162,7 @@ export default { ...@@ -162,7 +162,7 @@ export default {
}, },
activated() { mounted() {
// 初始化一些必要数据 // 初始化一些必要数据
// this.list.forEach(); // this.list.forEach();
// 计算修改量 // 计算修改量
......
...@@ -41,7 +41,7 @@ export default { ...@@ -41,7 +41,7 @@ export default {
useSelection: true, useSelection: true,
// 标题 // 标题
title: '列表', title: '列表',
keep: false, // 保持状态 keep: true, // 保持状态
useSearch: true, // 显示搜索 useSearch: true, // 显示搜索
customClass: '', customClass: '',
useTitle: true, useTitle: true,
...@@ -134,7 +134,7 @@ export default { ...@@ -134,7 +134,7 @@ export default {
} }
} }
this.loading = false this.loading = false
if(this.loadSuccess) { if (this.loadSuccess) {
this.loadSuccess() this.loadSuccess()
} }
}) })
...@@ -226,6 +226,7 @@ export default { ...@@ -226,6 +226,7 @@ export default {
} }
}, },
onCollapse(gap) { onCollapse(gap) {
console.info('gap', gap)
this.searchHeight = gap this.searchHeight = gap
} }
}, },
......
...@@ -79,7 +79,10 @@ ...@@ -79,7 +79,10 @@
</a-table> </a-table>
<slot name="free" /> <slot name="free" />
</div> </div>
<span v-else>what the fuck?</span> <div v-else>
what the fuck? <br />
where is my fucking page?
</div>
</template> </template>
<script> <script>
import SearchForm from './SearchForm' import SearchForm from './SearchForm'
......
...@@ -13,7 +13,7 @@ export default { ...@@ -13,7 +13,7 @@ export default {
props: { props: {
title: { title: {
type: String, type: String,
default: '服务预约管理', default: '城市匠人管理',
required: false required: false
}, },
showTitle: { showTitle: {
......
...@@ -3,6 +3,7 @@ import Router from 'vue-router' ...@@ -3,6 +3,7 @@ import Router from 'vue-router'
import { constantRouterMap, initRouterTree } from '@/router/router.config' import { constantRouterMap, initRouterTree } from '@/router/router.config'
import NProgress from 'nprogress' // progress bar import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style import 'nprogress/nprogress.css' // progress bar style
import 'simple-lightbox/dist/simpleLightbox.min.css' // progress bar style
import store from '@/store/index' import store from '@/store/index'
import { ACCESS_TOKEN } from '@/store/mutation-types' import { ACCESS_TOKEN } from '@/store/mutation-types'
import notification from 'ant-design-vue/es/notification' import notification from 'ant-design-vue/es/notification'
......
import Vue from 'vue' import Vue from 'vue'
import {getInfo, login} from "@/api/common/login" import { getInfo, login } from "@/api/common/login"
import {ACCESS_TOKEN, BEARER} from "@/store/mutation-types" import { ACCESS_TOKEN, BEARER } from "@/store/mutation-types"
import SocketService from '@/util/websocket'
const user = { const user = {
state: { state: {
...@@ -12,6 +13,7 @@ const user = { ...@@ -12,6 +13,7 @@ const user = {
roles: [], roles: [],
info: {}, info: {},
buttons: null, buttons: null,
websocket: null,
}, },
mutations: { mutations: {
...@@ -33,11 +35,14 @@ const user = { ...@@ -33,11 +35,14 @@ const user = {
SET_BUTTONS: (state, buttons) => { SET_BUTTONS: (state, buttons) => {
state.buttons = buttons state.buttons = buttons
}, },
SET_WEBSOCKET: (state, websocket) => {
state.websocket = websocket
}
}, },
actions: { actions: {
// 登录 // 登录
Login({commit}, userInfo) { Login({ commit }, userInfo) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
login(userInfo).then(response => { login(userInfo).then(response => {
if (response.code == SYS_CONST.REQUEST.SUCCEED) { if (response.code == SYS_CONST.REQUEST.SUCCEED) {
...@@ -57,7 +62,7 @@ const user = { ...@@ -57,7 +62,7 @@ const user = {
}) })
}, },
// 获取用户信息 // 获取用户信息
GetInfo({commit}) { GetInfo({ commit }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getInfo().then(response => { getInfo().then(response => {
let data = response.data; let data = response.data;
...@@ -74,6 +79,9 @@ const user = { ...@@ -74,6 +79,9 @@ const user = {
commit('SET_AVATAR', data.userInfo.avatar); commit('SET_AVATAR', data.userInfo.avatar);
commit('SET_BUTTONS', buttonAuthList); commit('SET_BUTTONS', buttonAuthList);
SocketService.init()
resolve(response) resolve(response)
}).catch(error => { }).catch(error => {
reject(error) reject(error)
...@@ -82,7 +90,7 @@ const user = { ...@@ -82,7 +90,7 @@ const user = {
}, },
// 登出 // 登出
Logout({commit}) { Logout({ commit }) {
return new Promise((resolve) => { return new Promise((resolve) => {
commit('SET_TOKEN', ''); commit('SET_TOKEN', '');
commit('SET_ROLES', []); commit('SET_ROLES', []);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
*/ */
import store from '@/store/index' import store from '@/store/index'
import {getCommonCode} from '@/api/system/sysCode' import {getCommonCode} from '@/api/system/sysCode'
import {getSubClassSelectable} from '@/api/serv'
export function triggerWindowResizeEvent() { export function triggerWindowResizeEvent() {
let event = document.createEvent('HTMLEvents') let event = document.createEvent('HTMLEvents')
...@@ -97,9 +98,11 @@ export function hasBtnPermission(permission) { ...@@ -97,9 +98,11 @@ export function hasBtnPermission(permission) {
} }
const bizCode = { const bizCode = {
SUB_CLASSES: 'subClasses'
}; };
const bizCodeMapping = { const bizCodeMapping = {
[bizCode.SUB_CLASSES]: () => getSubClassSelectable().then(({data}) => data)
}; };
export { bizCode, bizCodeMapping }; export { bizCode, bizCodeMapping };
......
import store from '@/store'
import { notification } from 'ant-design-vue'
export default class SocketService {
static webSocket = null
static reConnectTimeout = 1000
static init() {
const token = sessionStorage.getItem('Access-Token') || localStorage.getItem('Access-Token')
const ws = new WebSocket(`${process.env.VUE_APP_WEBSOCKET}?token=${token}`)
this.reConnectTimeout = 1000
ws.onmessage = this.onmessage
ws.onerror = this.onerror
ws.onclose = this.onclose
ws.onopen = this.onopen
this.webSocket = ws
store.commit('SET_WEBSOCKET', ws)
return ws
}
static onclose() {
console.info('连接关闭')
}
static onopen() {
console.info('连接建立')
}
static onerror() {
console.info('连接发生错误')
store.commit('SET_WEBSOCKET', null)
}
static reconnect() {
this.webSocket = null
setTimeout(() => {
console.info('reconnect at ', new Date())
this.init(store.getters.userInfo.id)
this.reConnectTimeout = this.reConnectTimeout + 5000
}, this.reConnectTimeout)
}
static onmessage(e) {
console.info('from server', e)
const { data } = e
if (data == 1) {
notification.open({
message: '消息提醒',
description: '用户已支付,请派单',
key: 'orderNotification',
btn: h => {
return h(
'a-button',
{
props: {
type: 'primary',
size: 'small',
},
on: {
click: () => this.$notification.close('orderNotification'),
},
},
'确定',
);
},
});
}
}
}
// 心跳检测
// eslint-disable-next-line no-unused-vars
const heartCheck = {
interval: 60000,
intervalObj: null,
start: function () {
console.log('start heart check');
this.intervalObj && clearInterval(this.intervalObj);
this.intervalObj = setInterval(function () {
//发送测试信息,后端收到后,返回一个消息,
console.info('heart beat check')
SocketService.webSocket.send('hello');
}, this.interval)
}
}
\ No newline at end of file
<template>
<table-template :soul="this">
<template #action="{ record }">
<a-space>
<a
v-if="record.releaseStatus == 1 || record.releaseStatus == 3"
@click="release(record)"
>
发布
</a>
<a v-if="record.releaseStatus == 2" @click="revoke(record)">撤销</a>
<a @click="detail(record.id)">详情</a>
<a
style="color: red"
v-if="record.releaseStatus == 1 || record.releaseStatus == 3"
@click="deleteNotice(record.id)"
>
删除
</a>
</a-space>
</template>
<template #free>
<NoticeDetail ref="NoticeDetail" :success="reset" />
</template>
</table-template>
</template>
<script>
import { TableTemplate, TableScript, SearchType } from '@/components/table'
import { getPage, save, deleteOne } from '@/api/notice'
import NoticeDetail from './NoticeDetail'
import dayjs from 'dayjs'
const columns = [
{
title: '名称',
width: 130,
dataIndex: 'title',
filter: { type: SearchType.STRING }
},
{
title: '内容',
dataIndex: 'content'
},
{ title: '状态', dataIndex: 'releaseStatusValue', width: 100 },
{
title: '状态',
dataIndex: 'releaseStatus',
filter: { type: SearchType.ENUM },
hidden: true,
enum: 'BIZ0003'
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 220,
sorter: true,
filter: { type: SearchType.RANGE },
customRender: (text) => dayjs(text).format('YYYY-MM-DD HH:mm:ss')
},
{
title: '操作',
width: 150,
scopedSlots: { customRender: 'action' }
}
]
export default {
name: 'HomeNotice',
mixins: [TableScript],
components: { TableTemplate, NoticeDetail },
data() {
return {
columns,
useYScroll: true,
title: '首页通知管理',
codes: [['BIZ0003'], []],
toolbar: [
{
text: '新建',
handler: 'add'
}
]
}
},
methods: {
queryData: getPage,
release(record) {
const _this = this
this.$confirm({
title: '是否发布此通知',
onOk() {
save({ id: record.id, releaseStatus: 2 }).then(({ code }) => {
if (code == 200) {
_this.$message.success('发布成功')
_this.reset()
}
})
}
})
},
revoke(record) {
const _this = this
this.$confirm({
title: '是否撤销此通知',
onOk() {
save({ id: record.id, releaseStatus: 3 }).then(({ code }) => {
if (code == 200) {
_this.$message.success('撤销成功')
_this.reset()
}
})
}
})
},
deleteNotice(id) {
const _this = this
this.$confirm({
title: '是否删除此通知',
onOk() {
deleteOne(id).then(({ code }) => {
if (code == 200) {
_this.$message.success('删除成功')
_this.reset()
}
})
}
})
},
detail(id) {
this.$refs.NoticeDetail.show(id)
},
add() {
this.$refs.NoticeDetail.show(null)
}
}
}
</script>
\ No newline at end of file
<template>
<a-drawer :width="500" :visible="visible" title="服务类别" @close="close">
<a-form :form="form" layout="vertical">
<a-form-item label="名称">
<a-input
v-decorator="[
'title',
{
rules: [{ required: true }]
}
]"
/>
</a-form-item>
<a-form-item label="内容(18字)">
<a-input
v-decorator="[
'content',
{
rules: [
{
required: true
},
{
max: 18
}
]
}
]"
/>
</a-form-item>
<a-form-item label="排序">
<a-input-number v-decorator="['showOrder']" />
</a-form-item>
</a-form>
<div class="drawer-form-bottom-toolbar">
<a-button :style="{ marginRight: '8px' }" @click="close"> 取消 </a-button>
<a-button type="primary" @click="submit"> 保存 </a-button>
</div>
</a-drawer>
</template>
<script>
import { getDetail, save } from '@/api/notice'
export default {
name: 'NoticeDetail',
props: { success: Function },
data() {
return {
form: this.$form.createForm(this),
visible: false,
id: null,
categoryId: null,
categoryName: ''
}
},
methods: {
show(id) {
this.id = id
this.visible = true
if (id) {
getDetail(this.id).then(({ data }) => {
this.form.setFieldsValue(data)
})
}
},
close() {
this.id = null
this.form.resetFields()
this.visible = false
},
submit() {
this.form.validateFields((err, values) => {
if (err) {
return
}
const reqData = {
...values,
id: this.id
}
save(reqData).then(({ code }) => {
if (code == 200) {
this.$message.success('保存成功')
this.close()
this.success()
}
})
})
}
}
}
</script>
\ No newline at end of file
<!-- 选择估价员 -->
<template>
<a-drawer width="30%" :visible="visible" title="指派估价员" @close="close">
<a-steps :current="step" @change="stepChange">
<a-step title="选择估价员" />
<a-step title="选择上门时间" />
</a-steps>
<br />
<div v-show="step == 0">
<a-form layout="inline">
<a-form-item label="名称">
<a-input v-model="name" />
</a-form-item>
<a-form-item>
<a-button type="primary" icon="search" @click="search" />
</a-form-item>
</a-form>
<br />
<a-radio-group v-model="id">
<template v-for="(valuator, i) in valuators">
<div class="valuator-selector-item-box" :key="i">
<a-radio :value="valuator.id" />
<div class="valuator-selector-item">
<p>姓名:{{ valuator.name }}</p>
<p>电话:{{ valuator.phone }}</p>
<div class="valuator-selector-item-assign-list">
<template v-for="(assign, idx) in valuator.assignTime">
<p :key="idx">已派时间:{{ assign }}</p>
</template>
</div>
</div>
</div>
</template>
</a-radio-group>
</div>
<div v-show="step == 1">
<span>选择上门时间</span>
<a-form :form="form">
<a-form-item label="上门时间">
<a-date-picker
size="large"
v-decorator="[
'expectArrivalTime',
{ rules: [{ required: true, message: '请选择上门时间' }] }
]"
format="YYYY-MM-DD HH:mm"
valueFormat="YYYY-MM-DD HH:mm"
:show-time="{
format: 'HH:mm',
valueFormat: 'HH:mm',
minuteStep: 30,
defaultValue: defaultTime
}"
:show-today="false"
/>
</a-form-item>
<a-form-item label="备注">
<a-textarea
v-decorator="[
'remark',
{ rules: [{ required: true, message: '请填写备注' }] }
]"
:autoSize="{ minRows: 5 }"
/>
</a-form-item>
</a-form>
</div>
<div class="drawer-form-bottom-toolbar">
<a-button v-show="step == 0" type="primary" @click="choose">
选择
</a-button>
<a-button type="primary" v-show="step == 1" @click="dispatch">
指派
</a-button>
</div>
</a-drawer>
</template>
<script>
import { getValuators } from '@/api/valuator'
import { dispatchValuator, reDispatchValuator } from '@/api/order'
import moment from 'moment'
export default {
name: 'ChooseValuator',
props: ['afterChoose', 'orderId'],
data() {
return {
visible: false,
id: null,
name: null,
valuators: [],
step: 0,
form: this.$form.createForm(this),
mode: null,
defaultTime: moment("1995-12-25 00:00")
}
},
methods: {
choose() {
if (!this.id) {
return
}
console.info('chosen id', this.id)
this.step = 1
},
close() {
this.id = null
this.name = null
this.step = 0
this.mode = null
this.form.resetFields()
this.visible = false
},
show(mode) {
this.visible = true
this.mode = mode
},
search() {
getValuators(this.name).then(({ data }) => {
console.info('valuators', data)
this.valuators = data
})
},
stepChange(step) {
if (step == 0) {
this.step = 0
}
},
dispatch() {
this.form.validateFieldsAndScroll((err, values) => {
if (err) {
return
}
const reqData = {
...values,
id: this.orderId,
hostId: this.id
}
console.info('reqData', reqData)
const dispatch =
this.mode == 'first' ? dispatchValuator : reDispatchValuator
dispatch(reqData).then(({ code }) => {
if (code == 200) {
this.$message.success('指派成功')
this.close()
this.afterChoose()
}
})
})
}
},
mounted() {
this.search()
}
}
</script>
<style lang="less" scoped>
.valuator-selector-item-box {
display: flex;
.valuator-selector-item {
margin-left: 10px;
font-size: 15px;
font-weight: bold;
.valuator-selector-item-assign-list {
padding-left: 5px;
color: rgb(139, 139, 139);
}
}
}
</style>
\ No newline at end of file
<!-- 选择估价员 -->
<template>
<a-drawer width="30%" :visible="visible" title="指派估价员" @close="close">
<a-steps :current="step" @change="stepChange">
<a-step title="选择维修工" />
<a-step title="填写信息" />
</a-steps>
<br />
<div v-show="step == 0">
<a-form layout="inline">
<a-form-item label="名称">
<a-input v-model="name" />
</a-form-item>
<a-form-item>
<a-button type="primary" icon="search" @click="search" />
</a-form-item>
</a-form>
<br />
<a-radio-group v-model="id">
<template v-for="(valuator, i) in workers">
<div class="valuator-selector-item-box" :key="i">
<a-radio :value="valuator.id" />
<div class="valuator-selector-item">
<p>姓名:{{ valuator.name }}</p>
<p>电话:{{ valuator.phone }}</p>
<div class="valuator-selector-item-assign-list">
<template v-for="(assign, idx) in valuator.assignTime">
<p :key="idx">已派时间:{{ assign }}</p>
</template>
</div>
</div>
</div>
</template>
</a-radio-group>
</div>
<div v-show="step == 1">
<span>选择上门时间</span>
<a-form :form="form">
<a-form-item label="备注">
<a-textarea
v-decorator="[
'remark',
{ rules: [{ required: true, message: '请填写备注' }] }
]"
:autoSize="{ minRows: 5 }"
/>
</a-form-item>
</a-form>
</div>
<div class="drawer-form-bottom-toolbar">
<a-button v-show="step == 0" type="primary" @click="choose">
选择
</a-button>
<a-button type="primary" v-show="step == 1" @click="dispatch">
指派
</a-button>
</div>
</a-drawer>
</template>
<script>
import { searchWorkers } from '@/api/worker'
import { dispatchWorker, reDispatchWorker } from '@/api/order'
export default {
name: 'ChooseWorker',
props: ['afterChoose', 'orderId'],
data() {
return {
visible: false,
id: null,
name: null,
workers: [],
step: 0,
form: this.$form.createForm(this),
mode: null,
}
},
methods: {
choose() {
if (!this.id) {
return
}
console.info('chosen id', this.id)
this.step = 1
},
close() {
this.id = null
this.name = null
this.step = 0
this.mode = null
this.form.resetFields()
this.visible = false
},
show(mode) {
this.visible = true
this.mode = mode
},
search() {
searchWorkers(this.name).then(({ data }) => {
this.workers = data
})
},
stepChange(step) {
if (step == 0) {
this.step = 0
}
},
dispatch() {
this.form.validateFieldsAndScroll((err, values) => {
if (err) {
return
}
const reqData = {
...values,
id: this.orderId,
hostId: this.id
}
console.info('reqData', reqData)
const dispatch =
this.mode == 'first' ? dispatchWorker : reDispatchWorker
dispatch(reqData).then(({ code }) => {
if (code == 200) {
this.$message.success('指派成功')
this.close()
this.afterChoose()
}
})
})
}
},
mounted() {
this.search()
}
}
</script>
<style lang="less" scoped>
.valuator-selector-item-box {
display: flex;
.valuator-selector-item {
margin-left: 10px;
font-size: 15px;
font-weight: bold;
.valuator-selector-item-assign-list {
padding-left: 5px;
color: rgb(139, 139, 139);
}
}
}
</style>
\ No newline at end of file
<template>
<a-drawer width="60%" :visible="visible" title="订单详情" @close="close">
<ChooseValuator
ref="ChooseValuator"
:afterChoose="fetchData"
:orderId="id"
/>
<SendPriceModal ref="SendPriceModal" :onSuccess="fetchData" :orderId="id" />
<ChooseWorker ref="ChooseWorker" :afterChoose="fetchData" :orderId="id" />
<div id="order-detail-drawer-box">
<div id="order-detail-drawer-box-info">
<a-descriptions title="订单信息" layout="vertical" :column="2">
<a-descriptions-item label="服务类型">
{{ order.serviceName || '-' }}
</a-descriptions-item>
<a-descriptions-item label="下单时间">
{{
order.createTime
? dayjs(order.createTime).format('YYYY-MM-DD HH:mm')
: '-'
}}
</a-descriptions-item>
<a-descriptions-item label="联系人">
{{ order.name || '-' }}
</a-descriptions-item>
<a-descriptions-item label="联系电话">
{{ order.phone || '-' }}
</a-descriptions-item>
<a-descriptions-item label="订单编号">
{{ order.orderNo || '-' }}
</a-descriptions-item>
<a-descriptions-item label="上门时间">
{{
order.expectArrivalTime
? dayjs(order.expectArrivalTime).format('YYYY-MM-DD HH:mm')
: '-'
}}
</a-descriptions-item>
<a-descriptions-item label="数量" span="2">
{{ order.num || '-' }}
</a-descriptions-item>
<a-descriptions-item label="地址" span="2">
{{ order.address || '-' }}
</a-descriptions-item>
<a-descriptions-item label="需求说明" :span="2">
{{ order.demandDesc || '-' }}
</a-descriptions-item>
<a-descriptions-item label="现场照片" :span="2">
<div id="order-images">
<template v-for="(url, i) in order.demandImgUrls">
<a :key="i" :href="url">
<img width="100" style="margin: 0 5px 5px 0" :src="url" />
</a>
</template>
</div>
</a-descriptions-item>
</a-descriptions>
</div>
<div id="order-detail-drawer-box-timeline">
<a-timeline>
<template v-for="(log, i) in order.process">
<a-timeline-item :key="i">
<p>{{ log.description }}</p>
<p v-if="log.expectArrivalTime">
上门估价时间:&nbsp;{{
dayjs(log.expectArrivalTime).format('YYYY-MM-DD HH:mm')
}}
</p>
<p v-if="log.remark">备注:&nbsp;{{ log.remark }}</p>
<p>{{ dayjs(log.createTime).format('YYYY-MM-DD HH:mm') }}</p>
</a-timeline-item>
</template>
</a-timeline>
</div>
</div>
<div class="drawer-form-bottom-toolbar">
<a-space>
<a-button
@click="sendPrice"
type="primary"
v-if="
!past &&
(order.orderStatus == STATUS.RESERVE ||
order.orderStatus == STATUS.VALUATION)
"
>
发送订单
</a-button>
<a-button
@click="sendValuator"
v-if="!past && order.orderStatus == STATUS.RESERVE"
>
现场估价
</a-button>
<a-button
@click="reSendValuator"
v-if="order.orderStatus == STATUS.VALUATION"
>
重新指派估价员
</a-button>
<a-button
v-if="!past && order.orderStatus == STATUS.PAY"
type="primary"
@click="dispatch"
>
派单
</a-button>
<a-button
v-if="!past && order.orderStatus == STATUS.DISPATCH"
@click="reDispatch"
>
重新派单
</a-button>
<a-button
@click="finish"
v-if="past && order.orderStatus == STATUS.DISPATCH"
type="primary"
>
完成
</a-button>
</a-space>
</div>
</a-drawer>
</template>
<script>
import ImageUpload from '@/components/image-upload/ImageUpload'
import { getDetail, STATUS, finishOrder } from '@/api/order'
import SimpleLightbox from 'simple-lightbox'
import ChooseValuator from './ChooseValuator'
import SendPriceModal from './SendPriceModal'
import ChooseWorker from './ChooseWorker'
import dayjs from 'dayjs'
const defaultData = {
process: [],
demandImgUrls: []
}
export default {
name: 'OrderDetail',
components: { ImageUpload, ChooseValuator, SendPriceModal, ChooseWorker },
props: { success: Function },
data() {
return {
form: this.$form.createForm(this),
visible: false,
id: null,
order: defaultData,
STATUS,
past: false, // 是否已过服务时间
lightbox: null,
dayjs
}
},
methods: {
show(id) {
this.id = id
this.visible = true
if (this.id) {
this.fetchData()
}
},
close() {
this.id = null
this.order = defaultData
this.lightbox && this.lightbox.destroy()
this.visible = false
},
// 发送订单
sendPrice() {
this.$refs.SendPriceModal.show()
},
// 指派估价员
sendValuator() {
this.$refs.ChooseValuator.show('first')
},
// 重新指派估价员
reSendValuator() {
this.$refs.ChooseValuator.show('rework')
},
dispatch() {
this.$refs.ChooseWorker.show('first')
},
reDispatch() {
this.$refs.ChooseWorker.show('rework')
},
fetchData() {
getDetail(this.id).then(({ data }) => {
this.order = data
// 判断是否已过服务时间
this.past = dayjs().diff(data.expectArrivalTime, 'day') > 0
this.$nextTick(() => {
this.lightbox = new SimpleLightbox({ elements: '#order-images a' })
})
})
},
finish() {
const _this = this
this.$confirm({
title: '提示',
content: '是否结束此订单',
onOk() {
finishOrder({ id: _this.id }).then(({ code }) => {
if (code == 200) {
_this.$message.success('订单已完成')
_this.fetchData()
}
})
}
})
}
},
mounted() {}
}
</script>
<style lang="less" scoped>
#order-detail-drawer-box {
height: 100%;
display: flex;
#order-detail-drawer-box-info {
width: 60%;
}
#order-detail-drawer-box-timeline {
width: 40%;
max-height: 100%;
overflow-y: auto;
padding-top: 10px;
}
}
</style>
\ No newline at end of file
<template>
<table-template :soul="this">
<template #detail="{ record }">
<a @click="detail(record)">查看详情</a>
</template>
<template #free>
<OrderDetail ref="OrderDetail" :success="reset" />
</template>
</table-template>
</template>
<script>
import { TableTemplate, TableScript, SearchType } from '@/components/table'
import { getPage, STATUS } from '@/api/order'
import OrderDetail from './OrderDetail.vue'
import dayjs from 'dayjs'
import { bizCode } from '@/util/util'
const columns = [
{ title: '服务项', width: 130, dataIndex: 'serviceName' },
{
title: '服务项',
hidden: true,
dataIndex: 'subClassId',
enum: bizCode.SUB_CLASSES,
filter: { type: SearchType.ENUM }
},
{
title: '订单状态',
width: 100,
dataIndex: 'orderStatusValue'
},
{
title: '订单状态',
hidden: true,
dataIndex: 'orderStatus',
filter: { type: SearchType.ENUM },
enum: 'BIZ0002'
},
{
title: '订单号',
width: 200,
dataIndex: 'orderNo',
filter: { type: SearchType.STRING }
},
{
title: '用户',
width: 120,
dataIndex: 'userName',
filter: { type: SearchType.STRING }
},
{
title: '联系电话',
dataIndex: 'phone',
width: 130,
filter: { type: SearchType.STRING }
},
{
title: '服务时间',
dataIndex: 'expectArrivalTime',
width: 130,
filter: { type: SearchType.RANGE },
customRender: (text) => dayjs(text).format('YYYY-MM-DD HH:mm:ss')
},
{
title: '提交时间',
dataIndex: 'createTime',
width: 120,
sorter: true,
filter: { type: SearchType.RANGE },
customRender: (text) => dayjs(text).format('YYYY-MM-DD HH:mm:ss')
},
{
title: '详情',
width: 120,
align: 'center',
scopedSlots: { customRender: 'detail' }
}
]
export default {
name: 'OrderList',
mixins: [TableScript],
components: { TableTemplate, OrderDetail },
data() {
return {
columns,
useYScroll: true,
title: '订单管理',
STATUS,
codes: [['BIZ0002'], [bizCode.SUB_CLASSES]]
}
},
methods: {
queryData: getPage,
detail(record) {
this.$refs.OrderDetail.show(record.id)
}
}
}
</script>
\ No newline at end of file
<template>
<a-modal
:visible="visible"
:title="null"
@cancel="close"
:footer="null"
:width="330"
>
<div style="text-align: center">
<a-space>
<span></span>
<a-input-number style="width: 120px" v-model="price" />
<a-button type="primary" @click="send">发送订单</a-button>
</a-space>
</div>
</a-modal>
</template>
<script>
import { sendPrice } from '@/api/order'
export default {
name: 'SendPriceModal',
props: ['onSuccess', 'orderId'],
data() {
return {
visible: false,
price: 0
}
},
methods: {
show() {
this.visible = true
},
send() {
const reqData = {
id: this.orderId,
price: this.price
}
sendPrice(reqData).then(({ code }) => {
if (code == 200) {
this.$message.success('发送成功')
this.onSuccess()
this.close()
}
})
},
close() {
this.visible = false
this.price = 0
}
}
}
</script>
<template>
<table-template :soul="this"> </table-template>
</template>
<script>
import { TableTemplate, TableScript, SearchType } from '@/components/table'
import { getPage } from '@/api/promote'
const columns = [
{
title: '用户名',
width: 150,
dataIndex: 'userName',
filter: { type: SearchType.STRING }
},
{
title: '推广数量',
width: 150,
dataIndex: 'count'
},
{ title: ' ', dataIndex: 'x' }
]
export default {
name: 'PromotionList',
mixins: [TableScript],
components: { TableTemplate },
data() {
return {
columns,
useYScroll: true,
title: '推广统计'
}
},
methods: {
queryData: getPage
}
}
</script>
\ No newline at end of file
<template>
<a-drawer :width="500" :visible="visible" title="服务类别" @close="close">
<a-form :form="form" layout="vertical">
<a-form-item label="名称">
<a-input v-decorator="['serviceName']" />
</a-form-item>
<a-form-item label="次级标题">
<a-input v-decorator="['description']" />
</a-form-item>
<a-form-item label="排序">
<a-input-number v-decorator="['sequence']" />
</a-form-item>
</a-form>
<div class="drawer-form-bottom-toolbar">
<a-button :style="{ marginRight: '8px' }" @click="close"> 取消 </a-button>
<a-button type="primary" @click="submit"> 保存 </a-button>
</div>
</a-drawer>
</template>
<script>
import { updateCategory, getDetails } from '@/api/serv'
export default {
name: 'CategoryEdit',
props: { success: Function },
data() {
return {
form: this.$form.createForm(this),
visible: false,
id: null,
categoryId: null,
categoryName: ''
}
},
methods: {
show(id) {
this.id = id
this.visible = true
if (id) {
getDetails(this.id).then(({ data }) => {
this.form.setFieldsValue(data)
})
}
},
close() {
this.id = null
this.form.resetFields()
this.visible = false
},
submit() {
this.form.validateFields((err, values) => {
if (err) {
return
}
const reqData = {
...values,
id: this.id
}
updateCategory(reqData).then(({ code }) => {
if (code == 200) {
this.$message.success('保存成功')
this.close()
this.success()
}
})
})
}
}
}
</script>
\ No newline at end of file
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
<a-space> <a-space>
<template v-if="record.type == 1"> <template v-if="record.type == 1">
<a @click="add(record)">添加服务项</a> <a @click="add(record)">添加服务项</a>
<a @click="editCategory(record)">修改信息</a>
</template> </template>
<template v-if="record.type == 2"> <template v-if="record.type == 2">
<a @click="edit(record)">修改信息</a> <a @click="edit(record)">修改信息</a>
...@@ -22,6 +23,7 @@ ...@@ -22,6 +23,7 @@
</template> </template>
<template #free> <template #free>
<SubClassEdit ref="SubClassEdit" :success="reset" /> <SubClassEdit ref="SubClassEdit" :success="reset" />
<CategoryEdit ref="CategoryEdit" :success="reset" />
</template> </template>
</table-template> </table-template>
</template> </template>
...@@ -29,6 +31,7 @@ ...@@ -29,6 +31,7 @@
import { TableTemplate, TableScript, SearchType } from '@/components/table' import { TableTemplate, TableScript, SearchType } from '@/components/table'
import { getCategoryList, saveOrUpdateSubClass } from '@/api/serv' import { getCategoryList, saveOrUpdateSubClass } from '@/api/serv'
import SubClassEdit from './SubClassEdit.vue' import SubClassEdit from './SubClassEdit.vue'
import CategoryEdit from './CategoryEdit.vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
const columns = [ const columns = [
...@@ -61,7 +64,7 @@ const columns = [ ...@@ -61,7 +64,7 @@ const columns = [
export default { export default {
name: 'ServiceList', name: 'ServiceList',
mixins: [TableScript, {}], mixins: [TableScript, {}],
components: { TableTemplate, SubClassEdit }, components: { TableTemplate, SubClassEdit, CategoryEdit },
data() { data() {
return { return {
columns, columns,
...@@ -76,7 +79,6 @@ export default { ...@@ -76,7 +79,6 @@ export default {
methods: { methods: {
queryData: getCategoryList, queryData: getCategoryList,
loadSuccess() { loadSuccess() {
console.info('xxxxxxxxxssssssssssss')
this.expandedRowKeys = this.dataSource.map((d) => d.id + '') this.expandedRowKeys = this.dataSource.map((d) => d.id + '')
}, },
enableChange(record, index) { enableChange(record, index) {
...@@ -118,6 +120,9 @@ export default { ...@@ -118,6 +120,9 @@ export default {
categoryId: record.id, categoryId: record.id,
categoryName: record.serviceName categoryName: record.serviceName
}) })
},
editCategory(record) {
this.$refs.CategoryEdit.show(record.id)
} }
} }
} }
......
<template> <template>
<a-drawer <a-drawer
:width="500" :width="1000"
:visible="visible" :visible="visible"
:title="id ? '编辑服务项' : '新增服务项'" :title="id ? '编辑服务项' : '新增服务项'"
@close="close" @close="close"
> >
<a-form :form="form" layout="vertical"> <a-form :form="form" layout="vertical">
<a-form-item :label="`服务大类: ${categoryName}`"> </a-form-item> <a-row>
<a-form-item label="名称"> <a-form-item :label="`服务大类: ${categoryName}`"> </a-form-item>
<a-input v-decorator="['serviceName']" /> <a-col :span="11">
</a-form-item> <a-form-item label="名称">
<ImageUpload <a-input v-decorator="['serviceName']" />
label="图片" </a-form-item>
decoration="img" </a-col>
:formItemLayout="null" <a-col :span="11" :offset="1">
:required="true" <a-form-item label="次级标题">
ref="image" <a-input v-decorator="['description']" />
:form="form" </a-form-item>
/> </a-col>
<a-form-item label="排序"> <a-col :span="5">
<a-input-number v-decorator="['sequence']" /> <ImageUpload
</a-form-item> label="图片"
decoration="img"
:formItemLayout="null"
:required="true"
ref="image"
:form="form"
/>
</a-col>
<a-col :span="5" :offset="1">
<ImageUpload
label="详情图片"
decoration="detailImg"
:formItemLayout="null"
:required="true"
ref="detailImg"
:form="form"
/>
</a-col>
<a-col :span="11" :offset="1">
<a-form-item label="排序">
<a-input-number v-decorator="['sequence']" />
</a-form-item>
</a-col>
<a-col :span="23">
<a-form-item label="服务详情">
<RichText ref="RichText" :height="900" />
</a-form-item>
</a-col>
</a-row>
</a-form> </a-form>
<div class="drawer-form-bottom-toolbar"> <div class="drawer-form-bottom-toolbar">
<a-button :style="{ marginRight: '8px' }" @click="close"> 取消 </a-button> <a-button :style="{ marginRight: '8px' }" @click="close"> 取消 </a-button>
...@@ -31,10 +59,11 @@ ...@@ -31,10 +59,11 @@
<script> <script>
import ImageUpload from '@/components/image-upload/ImageUpload' import ImageUpload from '@/components/image-upload/ImageUpload'
import { saveOrUpdateSubClass, getSubDetails } from '@/api/serv' import { saveOrUpdateSubClass, getSubDetails } from '@/api/serv'
import RichText from '@/components/richtext/richtext-editor'
export default { export default {
name: 'SubClassEdit', name: 'SubClassEdit',
components: { ImageUpload }, components: { ImageUpload, RichText },
props: { success: Function }, props: { success: Function },
data() { data() {
return { return {
...@@ -55,6 +84,8 @@ export default { ...@@ -55,6 +84,8 @@ export default {
getSubDetails(this.id).then(({ data }) => { getSubDetails(this.id).then(({ data }) => {
this.form.setFieldsValue(data) this.form.setFieldsValue(data)
this.$refs.image.setValue([data.img]) this.$refs.image.setValue([data.img])
this.$refs.detailImg.setValue([data.detailImg])
this.$refs.RichText.setContent(data.textDescription)
}) })
} }
}, },
...@@ -63,7 +94,9 @@ export default { ...@@ -63,7 +94,9 @@ export default {
this.categoryId = null this.categoryId = null
this.categoryName = '' this.categoryName = ''
this.$refs.image.reset() this.$refs.image.reset()
this.$refs.detailImg.reset()
this.form.resetFields() this.form.resetFields()
this.$refs.RichText.clear()
this.visible = false this.visible = false
}, },
submit() { submit() {
...@@ -74,8 +107,10 @@ export default { ...@@ -74,8 +107,10 @@ export default {
const reqData = { const reqData = {
...values, ...values,
img: this.$refs.image.getValue()[0], img: this.$refs.image.getValue()[0],
detailImg: this.$refs.detailImg.getValue()[0],
id: this.id, id: this.id,
categoryId: this.categoryId categoryId: this.categoryId,
textDescription: this.$refs.RichText.getContent()
} }
saveOrUpdateSubClass(reqData).then(({ code }) => { saveOrUpdateSubClass(reqData).then(({ code }) => {
if (code == 200) { if (code == 200) {
......
<template>
<a-drawer
:width="500"
:visible="visible"
:title="id ? '编辑' : '新增'"
@close="close"
>
<a-form :form="form" layout="vertical">
<a-form-item label="姓名">
<a-input v-decorator="['name', { rules: [{ required: true, message: '请输入姓名' }] }]" />
</a-form-item>
<a-form-item label="手机号">
<a-input v-decorator="['phone', { rules: [{ required: true, message: '请输入手机号' }] }]" />
</a-form-item>
</a-form>
<div class="drawer-form-bottom-toolbar">
<a-button :style="{ marginRight: '8px' }" @click="close"> 取消 </a-button>
<a-button type="primary" @click="submit"> 保存 </a-button>
</div>
</a-drawer>
</template>
<script>
import ImageUpload from '@/components/image-upload/ImageUpload'
import { save, getDetail, update } from '@/api/worker'
export default {
name: 'ServiceWorkerEdit',
components: { ImageUpload },
props: { success: Function },
data() {
return {
form: this.$form.createForm(this),
visible: false,
id: null
}
},
methods: {
show(id) {
this.id = id
this.visible = true
if (this.id) {
getDetail(this.id).then(({ data }) => {
this.form.setFieldsValue(data)
})
}
},
close() {
this.id = null
this.form.resetFields()
this.visible = false
},
submit() {
this.form.validateFields((err, values) => {
if (err) {
return
}
const reqData = {
...values,
id: this.id
}
const saveRequest = this.id ? update : save
saveRequest(reqData).then(({ code }) => {
if (code == 200) {
this.$message.success('保存成功')
this.close()
this.success()
}
})
})
}
}
}
</script>
\ No newline at end of file
<template>
<table-template :soul="this">
<template #action="{ record }">
<a-space>
<a @click="edit(record.id)">编辑</a>
<a style="color: red" @click="deleteRow(record.id)">删除</a>
</a-space>
</template>
<template #free>
<ServiceWorkerEdit ref="ServiceWorkerEdit" :success="reset" />
</template>
</table-template>
</template>
<script>
import { TableTemplate, TableScript, SearchType } from '@/components/table'
import { getPage, deleteWorker } from '@/api/worker'
import dayjs from 'dayjs'
import ServiceWorkerEdit from './ServiceWorkerEdit.vue'
const columns = [
{
title: '姓名',
dataIndex: 'name',
width: 120,
filter: { type: SearchType.STRING }
},
{ title: '手机号', width: 120, align: 'center' },
{ title: '' },
{
title: '创建时间',
dataIndex: 'createTime',
width: 150,
customRender: (text) => dayjs(text).format('YYYY-MM-DD HH:mm:ss')
},
{
title: '操作',
width: 120,
scopedSlots: { customRender: 'action' },
align: 'center'
}
]
export default {
name: 'ServiceWorkerList',
mixins: [TableScript],
components: { TableTemplate, ServiceWorkerEdit },
data() {
return {
columns,
useYScroll: true,
title: '维修工管理',
loadingKeys: [],
toolbar: [
{
text: '新增',
handler: 'add'
}
]
}
},
methods: {
queryData: getPage,
add() {
this.$refs.ServiceWorkerEdit.show(null)
},
edit(id) {
this.$refs.ServiceWorkerEdit.show(id)
},
deleteRow(id) {
const _this = this
this.$confirm({
title: '提示',
content: '是否删除',
onOk() {
deleteWorker(id).then(({ code }) => {
if (code == 200) {
_this.$message.success('删除成功')
_this.reset()
}
})
}
})
}
}
}
</script>
\ No newline at end of file
...@@ -180,7 +180,6 @@ export default { ...@@ -180,7 +180,6 @@ export default {
this.$store this.$store
.dispatch("GenerateRoutes", initRouterTree(menuList)) .dispatch("GenerateRoutes", initRouterTree(menuList))
.then(() => { .then(() => {
console.info('this.$store.getters.addRouters', this.$store.getters.addRouters)
this.$router.addRoutes(this.$store.getters.addRouters); this.$router.addRoutes(this.$store.getters.addRouters);
let redirectPath = this.$route.query.redirect; let redirectPath = this.$route.query.redirect;
if (redirectPath) { if (redirectPath) {
......
...@@ -3,40 +3,58 @@ ...@@ -3,40 +3,58 @@
<a-form @submit="handleSubmit" :form="form" class="cust-detail-form"> <a-form @submit="handleSubmit" :form="form" class="cust-detail-form">
<header-tool-bar> <header-tool-bar>
<span class="cust-title" slot="title"> <span class="cust-title" slot="title">
<a-icon type="hdd"/>角色管理明细 <a-icon type="hdd" />角色管理明细
</span> </span>
<a-button-group slot="extra"> <a-button-group slot="extra">
<a-button type='primary' htmlType='submit'>保存</a-button> <a-button type="primary" htmlType="submit">保存</a-button>
<a-button type="primary" @click="back" ghost>返回</a-button> <a-button type="primary" @click="back" ghost>返回</a-button>
</a-button-group> </a-button-group>
</header-tool-bar> </header-tool-bar>
<a-card title="基础数据" class="cust-normal-card"> <a-card title="基础数据" class="cust-normal-card">
<a-row> <a-row>
<a-col :span="6"> <a-col :span="6">
<a-form-item <a-form-item v-bind="formItemLayout" label="编号">
v-bind="formItemLayout"
label='编号'>
<a-input <a-input
v-decorator="['sysRole.code', {initialValue:sysRole.code, rules: [{ required: true, message: '请输入编号' }]}]"/> v-decorator="[
'sysRole.code',
{
initialValue: sysRole.code,
rules: [{ required: true, message: '请输入编号' }]
}
]"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6">
<a-form-item <a-form-item v-bind="formItemLayout" label="名称">
v-bind="formItemLayout"
label='名称'>
<a-input <a-input
v-decorator="['sysRole.name', {initialValue:sysRole.name,rules: [{ required: true, message: '请输入名称' }]}]"/> v-decorator="[
'sysRole.name',
{
initialValue: sysRole.name,
rules: [{ required: true, message: '请输入名称' }]
}
]"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6">
<a-form-item <a-form-item v-bind="formItemLayout" label="状态">
v-bind="formItemLayout"
label='状态'>
<a-select <a-select
:disabled="this.id==1" :disabled="this.id == 1"
v-decorator="['sysRole.available', {initialValue:sysRole.available,rules: [{ required: true, message: '请选择状态' }]}]" v-decorator="[
'sysRole.available',
{
initialValue: sysRole.available,
rules: [{ required: true, message: '请选择状态' }]
}
]"
> >
<a-select-option v-for="item in typeList" :key="item.id" :value="item.valueInt">{{item.name}} <a-select-option
v-for="item in typeList"
:key="item.id"
:value="item.valueInt"
>{{ item.name }}
</a-select-option> </a-select-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
...@@ -44,12 +62,17 @@ ...@@ -44,12 +62,17 @@
</a-row> </a-row>
<a-row> <a-row>
<a-col :span="24"> <a-col :span="24">
<a-form-item <a-form-item v-bind="formmarkItemLayout" label="备注">
v-bind="formmarkItemLayout"
label='备注'>
<a-textarea <a-textarea
:autoSize="{ minRows: 2, maxRows: 6 }" :autoSize="{ minRows: 2, maxRows: 6 }"
v-decorator="['sysRole.remark', {initialValue:sysRole.remark,rules: [{ required: true, message: '请输入备注' }]}]"/> v-decorator="[
'sysRole.remark',
{
initialValue: sysRole.remark,
rules: [{ required: true, message: '请输入备注' }]
}
]"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
...@@ -63,11 +86,23 @@ ...@@ -63,11 +86,23 @@
:pagination="false" :pagination="false"
:defaultExpandAllRows="true" :defaultExpandAllRows="true"
class="cust-card-table" class="cust-card-table"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: updateSelect,onSelect:rowSelect,onSelectAll:rowSelectAll}" :scroll="{ y: $store.getters.size[1] - 450 }"
:rowSelection="{
selectedRowKeys: selectedRowKeys,
onChange: updateSelect,
onSelect: rowSelect,
onSelectAll: rowSelectAll
}"
bordered bordered
> >
<span slot="action" slot-scope="text, record"> <span slot="action" slot-scope="text, record">
<a-checkbox v-for="item in record.sysBusinessOperateList" :key="item.id" :checked="item.selected" @change="onChange(item,record)">{{item.name}}</a-checkbox> <a-checkbox
v-for="item in record.sysBusinessOperateList"
:key="item.id"
:checked="item.selected"
@change="onChange(item, record)"
>{{ item.name }}</a-checkbox
>
</span> </span>
</a-table> </a-table>
</a-card> </a-card>
...@@ -76,209 +111,233 @@ ...@@ -76,209 +111,233 @@
</template> </template>
<script> <script>
import HeaderToolBar from '@/components/page/HeaderToolBar' import HeaderToolBar from '@/components/page/HeaderToolBar'
import {getDetail, save} from '@/api/system/sysRole' import { getDetail, save } from '@/api/system/sysRole'
let listPathName = 'sysrolelist'; let listPathName = 'sysRoleList'
const columns = [ const columns = [
{title: '业务名称', width: 300, dataIndex: 'name'}, { title: '业务名称', width: 300, dataIndex: 'name' },
{title: '操作', key: 'operation', dataIndex: 'sysBusinessOperateList', scopedSlots: {customRender: 'action'}} {
] title: '操作',
key: 'operation',
dataIndex: 'sysBusinessOperateList',
scopedSlots: { customRender: 'action' }
}
]
export default { export default {
name: "SysRoleDetail", name: 'SysRoleDetail',
components: {HeaderToolBar}, components: { HeaderToolBar },
data() { data() {
return { return {
id: 0, id: 0,
checkedList: [], checkedList: [],
form: this.$form.createForm(this), form: this.$form.createForm(this),
sysRole: {}, sysRole: {},
itemList: [], itemList: [],
saveOperatedList: [], saveOperatedList: [],
typeList: [], typeList: [],
columns: columns, columns: columns,
currentEditDate: {}, currentEditDate: {},
selectedRowKeys: [], selectedRowKeys: [],
formItemLayout: { formItemLayout: {
labelCol: { labelCol: {
sm: {span: 8}, sm: { span: 8 }
},
wrapperCol: {
sm: {span: 16},
},
}, },
formmarkItemLayout: { wrapperCol: {
labelCol: { sm: { span: 16 }
sm: {span: 2}, }
}, },
wrapperCol: { formmarkItemLayout: {
sm: {span: 22}, labelCol: {
}, sm: { span: 2 }
},
wrapperCol: {
sm: { span: 22 }
} }
} }
}
},
activated() {
this.form.resetFields()
this.selectedRowKeys = []
this.initData()
},
deactivated() {
this.itemList = []
},
methods: {
onChange(item, record) {
item.selected = !item.selected
if (item.selected == true) {
if (
record.sysBusinessOperateList.filter((opt) => opt.selected != true)
.length == 0
) {
this.selectedRowKeys.push(item.businessId)
}
} else {
this.selectedRowKeys = this.selectedRowKeys.filter(
(key) => key != record.id
)
}
}, },
activated() { initData() {
this.form.resetFields() this.id = this.$route.query.id || 0
this.selectedRowKeys = [] getDetail(this.id).then((resp) => {
this.initData() if (resp && resp.code == SYS_CONST.REQUEST.SUCCEED) {
}, this.sysRole = resp.data.sysRole
deactivated() { this.sysRole.available = this.sysRole.available ? 1 : 0
this.itemList = [] this.itemList = []
}, if (resp.data.sysBusinessTreeList) {
methods: { this.itemList = resp.data.sysBusinessTreeList[0].children
onChange(item, record) {
item.selected = !item.selected
if (item.selected == true) {
if (record.sysBusinessOperateList.filter(opt => opt.selected != true).length == 0) {
this.selectedRowKeys.push(item.businessId)
} }
this.checkChildren(this.itemList)
this.checkSelectRow(this.itemList)
this.typeList = resp.data.codeMap[SYS_CONST.CODE.SYS_AVAILABLE_STATUS]
}
})
},
checkChildren(list) {
list.map((m) => {
if (m.children.length == 0) {
m.children = null
} else { } else {
this.selectedRowKeys = this.selectedRowKeys.filter(key => key != record.id) this.checkChildren(m.children)
} }
}, })
initData() { },
this.id = this.$route.query.id || 0 checkSelectRow(businessList) {
getDetail(this.id).then(resp => { let count = 0
if (resp && resp.code == SYS_CONST.REQUEST.SUCCEED) { businessList.map((m) => {
this.sysRole = resp.data.sysRole if (
this.sysRole.available = this.sysRole.available?1:0 m.children == null &&
this.itemList = [] m.sysBusinessOperateList.filter((opt) => opt.selected != true)
if (resp.data.sysBusinessTreeList) { .length == 0
this.itemList = resp.data.sysBusinessTreeList[0].children ) {
} this.selectedRowKeys.push(m.id)
this.checkChildren(this.itemList) count++
this.checkSelectRow(this.itemList) }
if (m.children != null) {
this.typeList = resp.data.codeMap[SYS_CONST.CODE.SYS_AVAILABLE_STATUS] let checkedCount = this.checkSelectRow(m.children)
} if (checkedCount === m.children.length) {
})
},
checkChildren(list){
list.map(m=>{
if (m.children.length==0) {
m.children = null
}else {
this.checkChildren(m.children)
}
})
},
checkSelectRow(businessList) {
let count = 0;
businessList.map(m => {
if (m.children == null && m.sysBusinessOperateList.filter(opt => opt.selected != true).length == 0) {
this.selectedRowKeys.push(m.id) this.selectedRowKeys.push(m.id)
count++; count++
} }
if (m.children != null) {
let checkedCount = this.checkSelectRow(m.children);
if (checkedCount === m.children.length){
this.selectedRowKeys.push(m.id);
count++;
}
}
})
return count;
},
handleSubmit(e) {
e.preventDefault();
this.getSelectedOperate();
if (this.saveOperatedList.length == 0) {
this.$notification.error({message: '系统提示', description: "请至少勾选一个业务操作", duration: 4,});
return
} }
this.form.validateFieldsAndScroll((err, values) => { })
if (!err) { return count
let saveData = { },
sysRole: this.$valueCopy(this.sysRole, values.sysRole), handleSubmit(e) {
saveOperatedList: this.saveOperatedList e.preventDefault()
} this.getSelectedOperate()
save(saveData).then(resp => { if (this.saveOperatedList.length == 0) {
if (resp && resp.code == SYS_CONST.REQUEST.SUCCEED) { this.$notification.error({
this.$notification.success({message: '系统提示', description: "保存成功", duration: 4,}); message: '系统提示',
this.$router.push({name: listPathName, query: {isModify: this.id != 0}}) description: '请至少勾选一个业务操作',
} duration: 4
})
}
})
},
updateSelect(selectedRowKeys) {
this.selectedRowKeys = selectedRowKeys
},
rowSelect(record, selected) {
let curList = this.getCurList(record.id, this.itemList);
curList.map(m => {
if (m.id == record.id) {
m.sysBusinessOperateList.map(o => {
o.selected = selected
})
if (m.children != null) {
this.selectOperateByBusiness(m.children, selected)
}
}
}) })
}, return
getCurList(curId, parantList) { }
let curList = [] this.form.validateFieldsAndScroll((err, values) => {
for (let i = 0; i < parantList.length; i++) { if (!err) {
let item = parantList[i] let saveData = {
if (item.id == curId) { sysRole: this.$valueCopy(this.sysRole, values.sysRole),
curList = parantList saveOperatedList: this.saveOperatedList
} else if (item.children != null) {
curList = this.getCurList(curId, item.children)
}
if (curList.length > 0) {
break;
} }
save(saveData).then((resp) => {
if (resp && resp.code == SYS_CONST.REQUEST.SUCCEED) {
this.$notification.success({
message: '系统提示',
description: '保存成功',
duration: 4
})
this.$router.push({
name: listPathName,
query: { isModify: this.id != 0 }
})
}
})
} }
return curList; })
}, },
selectOperateByBusiness(businessList, selected) { updateSelect(selectedRowKeys) {
businessList.map(m => { this.selectedRowKeys = selectedRowKeys
if (selected) { },
this.selectedRowKeys.push(m.id) rowSelect(record, selected) {
} else { let curList = this.getCurList(record.id, this.itemList)
this.selectedRowKeys = this.selectedRowKeys.filter(s => s != m.id) curList.map((m) => {
} if (m.id == record.id) {
m.sysBusinessOperateList.map(o => { m.sysBusinessOperateList.map((o) => {
o.selected = selected o.selected = selected
}) })
if (m.children != null) { if (m.children != null) {
this.selectOperateByBusiness(m.children, selected) this.selectOperateByBusiness(m.children, selected)
} }
}) }
}, })
rowSelectAll(selected) { },
this.selectOperateByBusiness(this.itemList, selected) getCurList(curId, parantList) {
}, let curList = []
back() { for (let i = 0; i < parantList.length; i++) {
this.$router.push({name: listPathName}) let item = parantList[i]
}, if (item.id == curId) {
modifyItem(type, item) { curList = parantList
if (type == SYS_CONST.OPT_TYPE.ADD) { } else if (item.children != null) {
this.itemList.push(item) curList = this.getCurList(curId, item.children)
}
if (curList.length > 0) {
break
}
}
return curList
},
selectOperateByBusiness(businessList, selected) {
businessList.map((m) => {
if (selected) {
this.selectedRowKeys.push(m.id)
} else { } else {
this.$valueCopy(this.currentEditDate, item) this.selectedRowKeys = this.selectedRowKeys.filter((s) => s != m.id)
} }
}, m.sysBusinessOperateList.map((o) => {
getSelectedOperate() { o.selected = selected
this.saveOperatedList = []
this.getSaveOperateByList(this.itemList)
},
getSaveOperateByList(businessList) {
businessList.map(m => {
m.sysBusinessOperateList.map(o => {
if (o.selected == true) {
this.saveOperatedList.push(o.id);
}
})
if (m.children != null) {
this.getSaveOperateByList(m.children)
}
}) })
if (m.children != null) {
this.selectOperateByBusiness(m.children, selected)
}
})
},
rowSelectAll(selected) {
this.selectOperateByBusiness(this.itemList, selected)
},
back() {
this.$router.push({ name: listPathName })
},
modifyItem(type, item) {
if (type == SYS_CONST.OPT_TYPE.ADD) {
this.itemList.push(item)
} else {
this.$valueCopy(this.currentEditDate, item)
} }
},
getSelectedOperate() {
this.saveOperatedList = []
this.getSaveOperateByList(this.itemList)
},
getSaveOperateByList(businessList) {
businessList.map((m) => {
m.sysBusinessOperateList.map((o) => {
if (o.selected == true) {
this.saveOperatedList.push(o.id)
}
})
if (m.children != null) {
this.getSaveOperateByList(m.children)
}
})
} }
}; }
}
</script> </script>
...@@ -75,7 +75,6 @@ ...@@ -75,7 +75,6 @@
</span> </span>
<span slot="tags" slot-scope="text, record"> <span slot="tags" slot-scope="text, record">
<a-switch <a-switch
:disabled="record.id==1"
checkedChildren="启用" checkedChildren="启用"
unCheckedChildren="禁用" unCheckedChildren="禁用"
@click="setStatus(record)" @click="setStatus(record)"
......
<template>
<keep-alive v-if="keepAlive">
<router-view/>
</keep-alive>
<router-view v-else/>
</template>
<script>
export default {
name: "SysRoleRouteView",
computed: {
keepAlive() {
return this.$route.meta.keepAlive
}
},
}
</script>
\ No newline at end of file
<template>
<a-card>
<div class="cust-list-cart" ref="code">
<a-form layout="horizontal" class="ant-advanced-search-form">
<div>
<a-row>
<a-col :span="6">
<a-form-item label="参数名称" :labelCol="{span: 8}" :wrapperCol="{span: 16}">
<a-input @pressEnter="search" style="width: 100%" v-model="query.name" placeholder="请输入"/>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item label="参数类型" :labelCol="{span: 8}" :wrapperCol="{span: 16}">
<a-select placeholder="请选择类型" v-model="query.type" :allowClear="true" @change="search">
<a-select-option v-for="type in types" v-bind:value="type.valueInt" v-bind:key="type.id">
{{ type.name }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
</div>
</a-form>
<a-table
size="middle"
@change="sortChange"
:columns="columns"
:dataSource="dataSource"
:pagination="false"
:rowKey="rowKey"
bordered
>
<div slot="title" slot-scope="data">
<span class="cust-title">
<a-icon type="hdd"/>{{listName}}{{data.none}}
</span>
<div class="cust-table-operator">
<a-button-group>
<a-button type="primary" @click="search">查询</a-button>
<a-button @click="reset">重置</a-button>
</a-button-group>
</div>
</div>
<div slot="footer" slot-scope="data">
{{data.none}}
<a-pagination
@change="pageChange"
:defaultPageSize="defaultPageSize"
:pageSizeOptions="$pageSizeOptions"
@showSizeChange="sizeChange"
class="cust-pagination"
size="small"
:total="total"
showSizeChanger
showQuickJumper
:showTotal="$showTotal"/>
</div>
<span slot="action" slot-scope="text, record">
<a @click="editRow(record)">编辑</a>
</span>
<span slot="tags" slot-scope="text">
<div v-for="option in types" :key="option.id">
<span v-if="text == option.valueInt" :key="text">{{ option.name }}</span>
</div>
</span>
<template slot="value" slot-scope="text, record">
<span>{{ getValue(record)}}</span>
</template>
</a-table>
<a-drawer
title="系统参数编辑"
placement="right"
:closable="false"
@close="onClose"
:visible="visible"
:width="drWidth"
wrapClassName="sys-param"
>
<div>
<a-row>
<a-col v-if="this.showType(this.richText)" :span="24" >
<a-form-item :label='drTitle' v-bind="formItemLayout">
<div class="editor">
<tinymce-editor v-if="showEditor" ref="te" v-model="valueLongtext">
</tinymce-editor>
</div>
</a-form-item>
</a-col>
<a-col v-if="this.showType(this.intValue)" :span="24" >
<a-form-item :label='drTitle' v-bind="formItemLayout">
<div class="pub-code-value" >
<a-input-number style="width: 100%" v-model="valueInt"/>
</div>
</a-form-item>
</a-col>
<a-col v-if="this.showType(this.strValue)" :span="24">
<a-form-item :label='drTitle' v-bind="formItemLayout">
<div class="pub-code-value">
<a-input style="" v-model="valueStr"/>
</div>
</a-form-item>
</a-col>
<a-col v-if="this.showType(this.imgValue)" :span="24">
<a-form-item :label='drTitle' v-bind="formItemLayout">
<div style="" class="pub-code-value">
<a-upload
style="width: 200px; height: 200px"
listType="picture-card"
:defaultFileList="fileList"
:fileList="fileList"
:action="getUploadImageUrl(business)"
:headers="uploadImageHeader"
@change="handleChangeImg"
@preview="handlePreview"
>
<div v-if="fileList.length < 1">
<a-icon type="plus"/>
<div class="ant-upload-text">上传</div>
</div>
</a-upload>
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
<img alt="example" style="width: 100%" :src="previewImage"/>
</a-modal>
</div>
</a-form-item>
</a-col>
<a-col v-if="this.showType(this.fileValue)" :span="24">
<a-form-item :label='drTitle' v-bind="formItemLayout">
<div style="" class="pub-code-value">
<a-upload
style="width: 200px; height: 200px"
:defaultFileList="fileList"
:fileList="fileList"
:action="getUploadAttachmentUrl(business)"
:headers="uploadImageHeader"
@change="handleChangeImg"
@preview="handlePreview"
>
<div v-if="fileList.length < 1">
<a-button>
<a-icon type="upload"/>
选择文件
</a-button>
</div>
</a-upload>
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
<img alt="example" style="width: 100%" :src="previewImage"/>
</a-modal>
</div>
</a-form-item>
</a-col>
</a-row>
<div class="drawer-button">
<a-button :style="{marginRight: '8px'}" @click="onClose">
返回
</a-button>
<a-button type='primary' class="save-botton" @click="saveForm(record)" :loading="loading" >保存</a-button>
</div>
</div>
</a-drawer>
</div>
</a-card>
</template>
<script>
import {getPage, save} from "@/api/base/sysParam";
import {getPageSaas, saveSaas} from "@/api/saas/sassParamTemplate";
import {formatDate, humpToLine, setOrder} from "@/util/util";
import {getCommonCode} from "@/api/system/sysCode";
import TinymceEditor from '@/components/richtext/tinymce-editor'
import {getUploadImageHeader, getUploadImageUrl, getUploadAttachmentUrl, isUpdateSuccess, getOneImageURL, isLoading} from "@/api/common/fileUpload";
const richText = 'rich';
const strValue = 'str';
const intValue = 'int';
const imgValue = 'img';
const fileValue = 'file';
const dataSource = [];
const columns = [
{title: '参数名称', dataIndex: 'name', width: 200},
{title: '参数类型', dataIndex: 'type', width: 100, scopedSlots: {customRender: 'tags'}},
{title: '参数值', key:'value', scopedSlots: {customRender: 'value'}},
{title: '备注', width: 100, dataIndex: 'remark'},
{title: '排序号', width: 83, dataIndex: 'showOrder', sorter: true},
{title: '修改人', width: 85, dataIndex: 'username'},
{
title: '修改时间',
dataIndex: 'lmDate',
width: 140,
sorter: true,
customRender: (text) => formatDate(new Date(text), 'yyyy-MM-dd hh:mm')
},
{title: '操作', key: 'operation', width: 90, scopedSlots: {customRender: 'action'}}
];
export default {
name: "SysParamcomponent",
components: {TinymceEditor},
props:['type','listName'],
data() {
return {
query: {
page: 1,
size: 10,
name: "",
type: "",
sort: ""
},
rowKey: "id",
total: 0,
loading: false,
columns: columns,
dataSource: dataSource,
isFirstLoad: true,
visible: false,
drWidth: '60%',
drTitle: '',
record: {},
previewVisible: false,
previewImage: '',
fileList: [],
business: 'SysParam',
uploadImageHeader: getUploadImageHeader(),
types: [],
valueLongtext: '',
valueStr: '',
valueInt: 0,
showEditor: false,
richText,strValue,intValue,imgValue,fileValue,
formItemLayout: {
labelCol: {
sm: {span: 4},
},
wrapperCol: {
sm: {span: 19},
},
},
}
},
methods: {
getUploadImageUrl,
getUploadAttachmentUrl,
isUpdateSuccess,
getOneImageURL,
isLoading,
reset() {
this.query.page = 1;
this.query.name = "";
this.query.type = "";
this.loadData();
},
handleChangeImg({fileList}) {
this.isUpdateSuccess(fileList);
this.loading = this.isLoading(fileList);
this.fileList = fileList
},
handleCancel() {
this.previewVisible = false
},
handlePreview(file) {
this.previewImage = file.url || file.thumbUrl;
this.previewVisible = true;
},
handleChange({fileList}) {
this.isUpdateSuccess(fileList);
this.fileList = fileList;
},
showDrawer() {
this.visible = true
},
onClose() {
this.visible = false;
this.record = {};
this.fileList = [];
this.valueLongtext = '';
this.valueStr = '';
this.valueInt = 0
},
loadData(size) {
if (size && !isNaN(size)) {
this.query.size = size
}
if (this.type === 'system') {
getPage(this.query).then(response => {
this.getDataThen(response);
});
} else {
getPageSaas(this.query).then(response => {
this.getDataThen(response);
});
}
},
getDataThen(response) {
if (response && response.code == SYS_CONST.REQUEST.SUCCEED) {
let respData = response.data;
this.dataSource = respData.list;
this.total = respData.total;
}
},
search() {
this.query.page = 1;
this.loadData();
},
saveForm(record) {
this.loading = true;
let flag = false;
if (record.type == SYS_CONST.TEMPLATE_PARAM_TYPE.IMG || record.type == SYS_CONST.TEMPLATE_PARAM_TYPE.FILE) {
record.valueStr = getOneImageURL(this.fileList)
flag = !record.valueStr;
} else if (record.type == SYS_CONST.TEMPLATE_PARAM_TYPE.INT) {
record.valueInt = this.valueInt;
flag = record.valueInt == null
} else if (record.type == SYS_CONST.TEMPLATE_PARAM_TYPE.STR) {
record.valueStr = this.valueStr;
flag = !record.valueStr;
} else if (record.type == SYS_CONST.TEMPLATE_PARAM_TYPE.RICH) {
record.valueLongtext = this.valueLongtext;
flag = !record.valueLongtext;
}
if (flag) {
this.loading = false;
this.$notification.error({message: '提示', description: "参数值不能为空", duration: 4,});
return;
}
if (this.type === 'system') {
save(record).then(resp => {
this.saveThen(resp);
});
} else {
saveSaas(record).then(resp => {
this.saveThen(resp);
});
}
},
saveThen(resp) {
this.loading = false;
if (resp && resp.code == SYS_CONST.REQUEST.SUCCEED) {
this.$notification.success({message: '系统提示', description: "保存成功", duration: 4,});
this.loadData()
this.onClose()
}
},
editRow(row) {
this.drTitle = row.name;
this.record = row;
// 单独赋值,避免不保存情况下修改到record的值
this.valueLongtext = this.record.valueLongtext;
this.valueStr = this.record.valueStr;
this.valueInt = this.record.valueInt;
if ((row.type == SYS_CONST.TEMPLATE_PARAM_TYPE.IMG || row.type == SYS_CONST.TEMPLATE_PARAM_TYPE.FILE) && row.valueStr) {
let strs = row.valueStr.split('/');
let image = {
uid: '-1',
name: strs[strs.length - 1],
status: 'done',
url: row.valueStr,
};
this.fileList.push(image)
}
this.showDrawer();
},
pageChange(page) {
this.query.page = page;
this.loadData();
},
sizeChange(current, size) {
this.query.size = size;
this.loadData();
},
sortChange(pagination, filters, sorter) {
this.query.sort = humpToLine(sorter.field);
this.query.order = setOrder(sorter.order);
this.loadData();
},
getTypes() {
getCommonCode([SYS_CONST.CODE.TEMPLATE_PARAM_TYPE]).then(response => {
if (response && response.code == SYS_CONST.REQUEST.SUCCEED) {
this.types = response.data[SYS_CONST.CODE.TEMPLATE_PARAM_TYPE];
}
})
},
showType(type) {
if(type == this.richText) {
return this.record.type == SYS_CONST.TEMPLATE_PARAM_TYPE.RICH;
}
if(type == this.strValue) {
return this.record.type == SYS_CONST.TEMPLATE_PARAM_TYPE.STR;
}
if(type == this.imgValue) {
return this.record.type == SYS_CONST.TEMPLATE_PARAM_TYPE.IMG;
}
if(type == this.fileValue) {
return this.record.type == SYS_CONST.TEMPLATE_PARAM_TYPE.FILE;
}
if(type == this.intValue) {
return this.record.type == SYS_CONST.TEMPLATE_PARAM_TYPE.INT;
}
},
getValue(record) {
if (record.type === SYS_CONST.TEMPLATE_PARAM_TYPE.RICH) {
return '[点击编辑查看]';
}
if (record.type === SYS_CONST.TEMPLATE_PARAM_TYPE.STR) {
return record.valueStr;
}
if (record.type === SYS_CONST.TEMPLATE_PARAM_TYPE.IMG) {
return record.valueStr;
}
if (record.type === SYS_CONST.TEMPLATE_PARAM_TYPE.INT) {
return record.valueInt;
}
if (record.type === SYS_CONST.TEMPLATE_PARAM_TYPE.FILE) {
return record.valueStr;
}
}
},
computed: {
defaultPageSize: function () {
return this.$defaultPageSize()
}
},
mounted() {
this.getTypes();
},
deactivated() {
this.showEditor = false;
},
activated() {
this.showEditor = true;
if (this.isFirstLoad == true) {
this.loadData(this.defaultPageSize)
this.isFirstLoad = false
} else {
let isModify = this.$route.query.isModify
if (isModify == true) {
this.loadData()
} else if (isModify != undefined) {
this.loadData()
}
}
}
}
</script>
<style scoped>
.drawer-button {
position: absolute;
right: 0;
top: 0;
padding: 10px 16px;
background: #fff;
text-align: right;
}
.sys-param .ant-upload.ant-upload-select.ant-upload-select-text {
height: 32px!important;
}
</style>
\ No newline at end of file
<template>
<a-drawer
title="系统参数编辑"
placement="right"
:closable="false"
@close="onClose"
:visible="visible"
width="30%"
wrapClassName="sys-param"
>
<a-form>
<a-row>
<a-col v-if="param.type == 4" :span="24">
<ImageUpload
:label="param.name"
decoration="image"
:formItemLayout="null"
ref="image"
/>
</a-col>
<a-col v-if="param.type == 3" :span="24">
<a-form-item :label="param.name" v-bind="formItemLayout">
<RichText ref="RichText" :height="600" />
</a-form-item>
</a-col>
<a-col v-if="param.type == 1" :span="24">
<a-form-item :label="param.name" v-bind="formItemLayout">
<a-input-number style="width: 180px" v-model="value" />
</a-form-item>
</a-col>
<a-col v-if="param.type == 2" :span="24">
<a-form-item :label="param.name" v-bind="formItemLayout">
<a-input v-model="value" />
</a-form-item>
</a-col>
</a-row>
</a-form>
<div class="drawer-form-bottom-toolbar">
<a-button :style="{ marginRight: '8px' }" @click="onClose">
返回
</a-button>
<a-button type="primary" @click="saveForm(record)"> 保存 </a-button>
</div>
</a-drawer>
</template>
<script>
import RichText from '@/components/richtext/richtext-editor'
import ImageUpload from '@/components/image-upload/ImageUpload'
import { save } from '@/api/base/sysParam'
export default {
name: 'SysParamEdit',
components: { RichText, ImageUpload },
data() {
return {
type: 1,
visible: false,
param: { value: null },
value: null
}
},
methods: {
show(row) {
this.param = row
this.visible = true
this.$nextTick(() => {
if (row.type == 3) {
this.$refs.RichText.setContent(row.value)
}
if (row.type == 4) {
this.$refs.image.setValue([row.value])
} else {
this.value = row.value
}
})
},
onClose() {
this.param = { value: null }
this.visible = false
},
saveForm() {
let value = null
if (this.param.type == 3) {
value = this.$refs.RichText.getContent()
} else if (this.param.type == 4) {
value = this.$refs.image.getValue()[0]
} else {
value = this.value
}
if (!value) {
this.loading = false
this.$notification.error({
message: '提示',
description: '参数值不能为空',
duration: 4
})
return
}
save({ id: this.param.id, value }).then(({ code }) => {
if (code == 200) {
this.$notification.success({
message: '系统提示',
description: '保存成功',
duration: 4
})
this.$emit('onSuccess')
this.onClose()
}
})
}
}
}
</script>
\ No newline at end of file
<template> <template>
<div> <table-template :soul="this">
<sys-param-component <template #action="{ record }">
:type="type" <a @click="editRow(record)">编辑</a>
:listName="listName" </template>
></sys-param-component> <template #tags="{ value }">
</div> <a-tag>{{ codeMapping['SYS0005'][value] }}</a-tag>
</template>
<template #value="{ record }">
<span>{{ getValue(record) }}</span>
</template>
<template #free>
<SysParamEdit ref="SysParamEdit" @onSuccess="reset" />
</template>
</table-template>
</template> </template>
<script> <script>
import SysParamComponent from './SysParamComponent' import dayjs from 'dayjs'
import { TableTemplate, TableScript, SearchType } from '@/components/table'
import { getPage } from '@/api/base/sysParam'
import SysParamEdit from './SysParamEdit.vue'
const columns = [
{
title: '参数名称',
dataIndex: 'name',
width: 200,
filter: { type: SearchType.STRING }
},
{
title: '参数类型',
dataIndex: 'type',
width: 100,
scopedSlots: { customRender: 'tags' },
filter: { type: SearchType.ENUM },
enum: 'SYS0005'
},
{ title: '参数值', key: 'value', scopedSlots: { customRender: 'value' } },
{ title: '备注', width: 100, dataIndex: 'remark' },
{ title: '排序号', width: 110, dataIndex: 'showOrder', sorter: true },
{ title: '修改人', width: 110, dataIndex: 'username' },
{
title: '修改时间',
dataIndex: 'lmDate',
width: 180,
sorter: true,
customRender: (text) => dayjs(text).format('YYYY-MM-DD HH:mm:ss')
},
{
title: '操作',
key: 'operation',
width: 90,
scopedSlots: { customRender: 'action' }
}
]
export default { export default {
name: 'SysParamList', name: 'SysParamList',
components: { SysParamComponent }, components: { TableTemplate, SysParamEdit },
mixins: [TableScript],
data() { data() {
return { return {
type: 'system', title: '系统参数',
listName: '总控系统参数列表' columns,
codes: [['SYS0005'], []]
} }
}, },
methods: {} methods: {
queryData: getPage,
getValue(record) {
if (record.type == 3) {
return '[点击编辑查看]'
}
return record.value
},
editRow(row) {
this.$refs.SysParamEdit.show(row)
}
}
} }
</script> </script>
...@@ -2,107 +2,83 @@ ...@@ -2,107 +2,83 @@
<div> <div>
<a-form @submit="handleSubmit" :form="form" class="cust-detail-form"> <a-form @submit="handleSubmit" :form="form" class="cust-detail-form">
<header-tool-bar> <header-tool-bar>
<span class="cust-title" slot="title"> <span class="cust-title" slot="title">
<a-icon type="hdd"/>系统用户详情 <a-icon type="hdd" />系统用户详情
</span> </span>
<a-button-group slot="extra"> <a-button-group slot="extra">
<a-button type='primary' htmlType='submit'>保存</a-button> <a-button type="primary" htmlType="submit">保存</a-button>
<a-button type="primary" @click="back" ghost>返回</a-button> <a-button type="primary" @click="back" ghost>返回</a-button>
</a-button-group> </a-button-group>
</header-tool-bar> </header-tool-bar>
<a-card title="用户基础数据" class="cust-normal-card"> <a-card title="用户基础数据" class="cust-normal-card">
<a-row :gutter="gutter"> <a-row :gutter="gutter">
<a-col :span="span"> <a-col :span="span">
<a-form-item <a-form-item v-bind="formItemLayout" label="用户名">
v-bind="formItemLayout"
label='用户名' >
<a-input <a-input
v-decorator="['username', {initialValue: userDate.username, rules: [{ required: true, message: '请输入用户名!' }]}]" v-decorator="[
'userName',
{
initialValue: userDate.userName,
rules: [{ required: true, message: '请输入用户名!' }]
}
]"
/> />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="span"> <a-col :span="span">
<a-form-item <a-form-item v-bind="formItemLayout" label="真实姓名">
v-bind="formItemLayout"
label='真实姓名' >
<a-input <a-input
v-decorator="['realName', {initialValue: userDate.realName, rules: [{ required: true, message: '请输入真实姓名!' }]}]" v-decorator="[
'realName',
{
initialValue: userDate.realName,
rules: [{ required: true, message: '请输入真实姓名!' }]
}
]"
/> />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="span"> <a-col :span="span">
<a-form-item <a-form-item v-bind="formItemLayout" label="联系电话">
v-bind="formItemLayout"
label='联系电话' >
<a-input <a-input
oninput = "value=value.replace(/[^\d]/g,'')" oninput="value=value.replace(/[^\d]/g,'')"
v-decorator="['mobile', {initialValue: userDate.mobile, rules: [{ required: true, message: '请输入电话!' }]}]" v-decorator="[
'phone',
{
initialValue: userDate.phone,
rules: [{ required: true, message: '请输入电话!' }]
}
]"
/> />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="span"> <a-col :span="span">
<a-form-item <a-form-item v-bind="formItemLayout" label="邮箱">
v-bind="formItemLayout"
label='邮箱' >
<a-input <a-input
v-decorator="['email', {initialValue: userDate.email, rules: [{ required: false, message: '请输入电话!' }]}]" v-decorator="[
'email',
{
initialValue: userDate.email,
rules: [{ required: false, message: '请输入电话!' }]
}
]"
/> />
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
<a-row>
<a-col :span="6">
<a-form-item
v-bind="formItemLayout"
label='所属分局: '>
<a-select
style='width: 100%'
v-decorator="['communityId', {initialValue: userDate.communityId, rules: [{ required: true, message: '选择分局' }]}]"
>
<a-select-option v-for="item in officeList" :key="item.id" :value="item.id">{{item.name}}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item
v-bind="formItemLayout"
label='所属科室: '>
<a-select
style='width: 100%'
v-decorator="['org', {initialValue: userDate.org, rules: [{ required: true, message: '选择科室' }]}]"
>
<a-select-option v-for="item in orgList" :key="item.id" :value="item.valueInt">{{item.name}}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item
v-bind="formItemLayout"
label='数据权限: '>
<a-select
style='width: 100%'
v-decorator="['dataAccessType', {initialValue: userDate.dataAccessType, rules: [{ required: true, message: '选择权限' }]}]"
>
<a-select-option v-for="item in authorityTypeList" :key="item.id" :value="item.valueInt">{{item.name}}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :utter="gutter"> <a-row :utter="gutter">
<a-col :span="6"> <a-col :span="6">
<a-form-item <a-form-item v-bind="formItemLayout" label="头像">
v-bind="formItemLayout"
label='头像' >
<a-upload <a-upload
:rows="3" :rows="3"
v-decorator="['avatar', { v-decorator="[
valuePropName: 'imageList', 'avatar',
getValueFromEvent: normFile, {
rules: [{ required: false, message: '请上传用户头像' }] valuePropName: 'imageList',
}]" getValueFromEvent: normFile,
rules: [{ required: false, message: '请上传用户头像' }]
}
]"
style="width: 100%" style="width: 100%"
:defaultFileList="imageList" :defaultFileList="imageList"
:fileList="imageList" :fileList="imageList"
...@@ -113,21 +89,35 @@ ...@@ -113,21 +89,35 @@
@preview="handlePreview" @preview="handlePreview"
> >
<div v-if="imageList.length < 1"> <div v-if="imageList.length < 1">
<a-icon type="plus"/> <a-icon type="plus" />
<div class="ant-upload-text">上传图片</div> <div class="ant-upload-text">上传图片</div>
</div> </div>
</a-upload> </a-upload>
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel"> <a-modal
<img alt="example" style="width: 100%" :src="previewImage"/> :visible="previewVisible"
:footer="null"
@cancel="handleCancel"
>
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal> </a-modal>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="12"> <a-col :span="12">
<a-form-item <a-form-item
:labelCol="{span: 4}" :labelCol="{ span: 4 }"
:wrapperCol="{span: 20}" :wrapperCol="{ span: 20 }"
label='备注' > label="备注"
<a-textarea :rows="3" v-decorator="['remark', {initialValue: userDate.remark, rules: [{ required: false, message: '' }]}]"/> >
<a-textarea
:rows="3"
v-decorator="[
'remark',
{
initialValue: userDate.remark,
rules: [{ required: false, message: '' }]
}
]"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
...@@ -140,7 +130,10 @@ ...@@ -140,7 +130,10 @@
size="middle" size="middle"
:pagination="false" :pagination="false"
class="cust-card-table" class="cust-card-table"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: updateSelect}" :rowSelection="{
selectedRowKeys: selectedRowKeys,
onChange: updateSelect
}"
bordered bordered
> >
</a-table> </a-table>
...@@ -150,151 +143,156 @@ ...@@ -150,151 +143,156 @@
</template> </template>
<script> <script>
import HeaderToolBar from '@/components/page/HeaderToolBar' import HeaderToolBar from '@/components/page/HeaderToolBar'
import {getDetail, save,} from '@/api/system/sysUserApi' import { getDetail, save } from '@/api/system/sysUserApi'
import {getCommonCode} from "@/api/system/sysCode"; import {
import { getOneImageURL,
getOneImageURL, getUploadImageHeader,
getUploadImageHeader, getUploadImageUrl,
getUploadImageUrl, isLoading,
isLoading, isUpdateSuccess
isUpdateSuccess } from '@/api/common/fileUpload'
} from "@/api/common/fileUpload"; import { getAll } from '@/api/system/sysRole'
let listPathName = 'sysuserlist'; let listPathName = 'sysUserList'
const columns = [ const columns = [
{title: '角色名称', dataIndex: 'name', width: 250}, { title: '角色名称', dataIndex: 'name', width: 250 },
{title: '角色Code', dataIndex: 'code',}, { title: '角色Code', dataIndex: 'code' },
{title: '备注', dataIndex: 'remark',}, { title: '备注', dataIndex: 'remark' }
] ]
export default { export default {
name: "SysUserDetail", name: 'SysUserDetail',
components: {HeaderToolBar}, components: { HeaderToolBar },
data() { data() {
return { return {
id: 0, id: 0,
form: this.$form.createForm(this), form: this.$form.createForm(this),
userDate: {}, userDate: {},
roleList: [], roleList: [],
typeList: [], typeList: [],
columns: columns, columns: columns,
currentEditDate: {}, currentEditDate: {},
selectedRowKeys: [], selectedRowKeys: [],
officeList:[], officeList: [],
visible: false, visible: false,
imageList:[], imageList: [],
orgList: [], orgList: [],
authorityTypeList: [], authorityTypeList: [],
loading: false, loading: false,
previewVisible: false, previewVisible: false,
previewImage: '', previewImage: '',
business: 'sys-user', business: 'sys-user',
uploadImageHeader: getUploadImageHeader(), uploadImageHeader: getUploadImageHeader(),
formItemLayout: { formItemLayout: {
labelCol: { labelCol: {
sm: { span: 8 }, sm: { span: 8 }
},
wrapperCol: {
sm: { span: 16 },
},
}, },
gutter: 8, wrapperCol: {
span: 6, sm: { span: 16 }
} }
}, },
activated() { gutter: 8,
this.getSysCode(); span: 6
}, }
deactivated() { },
this.form.resetFields() activated() {
this.userDate = {}; this.getSysCode()
this.selectedRowKeys = []; },
this.imageList = []; deactivated() {
}, this.form.resetFields()
methods: { this.userDate = {}
getUploadImageUrl, this.selectedRowKeys = []
isUpdateSuccess, this.imageList = []
isLoading, },
getOneImageURL, methods: {
initData() { getUploadImageUrl,
this.id = this.$route.query.id || 0; isUpdateSuccess,
getDetail(this.id).then(resp => { isLoading,
if (resp && resp.code == SYS_CONST.REQUEST.SUCCEED) { getOneImageURL,
this.userDate = resp.data.sysUserDetail; initData() {
this.roleList = resp.data.sysUserRoleList || []; this.id = this.$route.query.id || 0
this.officeList = resp.data.officeList || []; getDetail(this.id).then((resp) => {
this.selectedRowKeys = resp.data.sysUserCheckedRoleList || []; if (resp && resp.code == SYS_CONST.REQUEST.SUCCEED) {
this.userDate = resp.data.sysUserDetail
this.selectedRowKeys = resp.data.sysUserCheckedRoleList || []
if (this.userDate.avatar != null) { if (this.userDate.avatar != null) {
let image = { let image = {
uid: '-1', uid: '-1',
name: 'xxx.png', name: 'xxx.png',
status: 'done', status: 'done',
url: this.userDate.avatar, url: this.userDate.avatar
};
this.imageList.push(image);
} }
this.imageList.push(image)
} }
}) }
}, })
handleSubmit(e) { },
e.preventDefault(); handleSubmit(e) {
this.form.validateFieldsAndScroll((err, values) => { e.preventDefault()
if (!err) { this.form.validateFieldsAndScroll((err, values) => {
if (this.selectedRowKeys.length === 0) { if (!err) {
this.$notification.error({message: '系统提示', description: "至少勾选一个角色", duration: 4,}); if (this.selectedRowKeys.length === 0) {
return this.$notification.error({
} message: '系统提示',
values.avatar = getOneImageURL(this.imageList); description: '至少勾选一个角色',
let saveData = { duration: 4
sysUserDetail: this.$valueCopy(this.userDate, values),
sysUserCheckedRoleList: this.selectedRowKeys,
};
save(saveData).then(resp => {
if (resp && resp.code == SYS_CONST.REQUEST.SUCCEED) {
this.$notification.success({message: '系统提示', description: "保存成功", duration: 4,});
this.$router.push({name: listPathName, query: {isModify: this.id != 0}})
}
}) })
return
} }
}) values.avatar = getOneImageURL(this.imageList)
}, let saveData = {
updateSelect(selectedRowKeys) { sysUserDetail: this.$valueCopy(this.userDate, values),
this.selectedRowKeys = selectedRowKeys sysUserCheckedRoleList: this.selectedRowKeys
},
back() {
this.$router.push({name: listPathName})
},
normFile(e) {
if (Array.isArray(e)) {
return e
}
return e && e.fileList
},
handleChangeImg({fileList}) {
this.isUpdateSuccess(fileList);
this.loading = this.isLoading(fileList);
this.imageList = fileList;
},
handlePreview(file) {
this.previewImage = file.url || file.thumbUrl;
this.previewVisible = true;
},
handleCancel() {
this.previewVisible = false;
},
getSysCode() {
getCommonCode([SYS_CONST.CODE.UNIT_TYPE, SYS_CONST.CODE.AUTHORITY_TYPE]).then(response => {
if (response && response.code == SYS_CONST.REQUEST.SUCCEED) {
this.orgList = response.data.data[SYS_CONST.CODE.UNIT_TYPE];
this.authorityTypeList = response.data.data[SYS_CONST.CODE.AUTHORITY_TYPE];
} }
this.initData() save(saveData).then((resp) => {
}) if (resp && resp.code == SYS_CONST.REQUEST.SUCCEED) {
}, this.$notification.success({
message: '系统提示',
description: '保存成功',
duration: 4
})
this.$router.push({
name: listPathName,
query: { isModify: this.id != 0 }
})
}
})
}
})
},
updateSelect(selectedRowKeys) {
this.selectedRowKeys = selectedRowKeys
},
back() {
this.$router.push({ name: listPathName })
},
normFile(e) {
if (Array.isArray(e)) {
return e
}
return e && e.fileList
},
handleChangeImg({ fileList }) {
this.isUpdateSuccess(fileList)
this.loading = this.isLoading(fileList)
this.imageList = fileList
},
handlePreview(file) {
this.previewImage = file.url || file.thumbUrl
this.previewVisible = true
},
handleCancel() {
this.previewVisible = false
},
getSysCode() {
this.initData()
getAll().then(({ data }) => {
this.roleList = data
})
} }
}; }
}
</script> </script>
<template> <template>
<div> <table-template :soul="this">
<a-card class="cust-list-cart"> <template #tags="{ record }">
<div> <a-switch
<a-form layout="horizontal" class="ant-advanced-search-form"> :disabled="record.id == 1"
<div> checkedChildren="启用"
<a-row> unCheckedChildren="禁用"
<a-col :span="6"> @click="setStatus(record)"
<a-form-item label="用户名" v-bind="formItemLayout"> :checked="record.available"
<a-input @pressEnter="search" v-model="query.username" placeholder="请输入"/> />
</a-form-item> </template>
</a-col> <template #action="{ record }">
<a-col :span="6"> <a @click="editRow(record)" v-if="record.id != 1">编辑</a>
<a-form-item label="真实姓名" v-bind="formItemLayout"> <a-divider type="vertical" v-if="record.id != 1" />
<a-input <a @click="resetPwd(record)" v-if="record.id != 1">重置密码</a>
@pressEnter="search" </template>
style="width: 100%" </table-template>
v-model="query.realName"
placeholder="请输入"/>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item label="电话" v-bind="formItemLayout">
<a-input-number
@pressEnter="search"
style="width: 100%"
v-model="query.mobile"
placeholder="请输入"/>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item label="状态" v-bind="formItemLayout">
<a-select
placeholder="请选择状态"
v-model="query.available"
@change="this.onChangeStatus"
:allowClear="true">
<a-select-option
v-for="option in availabStatus"
v-bind:value="option.valueInt"
v-bind:key="option.id">
{{ option.name }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
</div>
</a-form>
</div>
<div>
<a-table
size="middle"
@change="sortChange"
:columns="columns"
:dataSource="dataSource"
:pagination="false"
:rowKey="rowKey"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: updateSelect}"
bordered
>
<div slot="title" slot-scope="data">
<span class="cust-title">
<a-icon type="hdd"/>系统用户{{data.none}}
</span>
<div class="cust-table-operator">
<a-button-group>
<a-button type="primary" @click="search">查询</a-button>
<a-button @click="reset">重置</a-button>
<a-button @click="addNew">新建</a-button>
</a-button-group>
</div>
</div>
<div slot="footer" slot-scope="data">
{{data.none}}
<a-pagination
@change="pageChange"
:defaultPageSize="defaultPageSize"
:pageSizeOptions="$pageSizeOptions"
@showSizeChange="sizeChange"
class="cust-pagination"
size="small"
:total="total"
showSizeChanger
showQuickJumper
:showTotal="$showTotal"/>
</div>
<span slot="action" slot-scope="text, record" v-if="record.id!=1">
<a @click="editRow(record)">编辑</a>
<a-divider type="vertical"/>
<a @click="resetPwd(record)">重置密码</a>
</span>
<span slot="tags" slot-scope="text, record">
<a-switch
:disabled="record.id == 1"
checkedChildren="启用"
unCheckedChildren="禁用"
@click="setStatus(record)"
:checked="record.available"
:key="record.id"/>
</span>
</a-table>
</div>
</a-card>
</div>
</template> </template>
<script> <script>
import { changeStatus,getPage, resetPwd} from "@/api/system/sysUserApi"; import { TableTemplate, TableScript, SearchType } from '@/components/table'
import {getCommonCode} from "@/api/system/sysCode"; import { changeStatus, getPage, resetPwd } from '@/api/system/sysUserApi'
import {formatDate, humpToLine, setOrder} from "@/util/util"; import dayjs from 'dayjs'
const dataSource = []
const columns = [
{title: '用户名', dataIndex: 'username', width: 120},
{title: '真实姓名', dataIndex: 'realName', width: 90},
{title: '联系电话', dataIndex: 'mobile', width: 100},
{title: '邮箱', dataIndex: 'email', width: 150},
{title: '备注', dataIndex: 'remark'},
// {title: '创建人', dataIndex: 'ct_user_name', width:70},
{
title: '创建时间',
dataIndex: 'ctDate',
width: 120,
sorter: true,
customRender: (text) => formatDate(new Date(text), 'yyyy-MM-dd hh:mm')
},
// {title: '修改人', dataIndex: 'lm_user_name',width:70},
{
title: '修改时间',
dataIndex: 'lmDate',
width: 140,
sorter: true,
customRender: (text) => formatDate(new Date(text), 'yyyy-MM-dd hh:mm')
},
{title: '状态', dataIndex: 'available', width: 80, scopedSlots: {customRender: 'tags'}},
// {title: '状态', dataIndex: 'available', width: 60, },
{title: '操作', key: 'operation', width: 130, scopedSlots: {customRender: 'action'}}
];
let detailPathName = 'sysuserdetail'
export default { const columns = [
name: 'SysUserList', {
data() { title: '用户名',
return { dataIndex: 'userName',
query: { width: 120,
page: 1, filter: { type: SearchType.STRING }
size: 10, },
username: "", {
realName: "", title: '真实姓名',
mobile: "", dataIndex: 'realName',
available: "", width: 90,
order: "", filter: { type: SearchType.STRING }
sort: "" },
}, {
total: 0, title: '联系电话',
rowKey: "id", dataIndex: 'phone',
columns: columns, width: 100,
dataSource: dataSource, filter: { type: SearchType.STRING }
selectedRowKeys: [], },
selectedRows: [], { title: '邮箱', dataIndex: 'email', width: 150 },
coachList: [], { title: '备注', dataIndex: 'remark' },
currentEditDate: {}, {
coachId: {}, title: '创建时间',
sysUserId: {}, dataIndex: 'ctDate',
rowDate: {}, width: 170,
availabStatus: {}, sorter: true,
customRender: (text) => dayjs(text).format('YYYY-MM-DD HH:mm:ss')
},
{
title: '修改时间',
dataIndex: 'lmDate',
width: 170,
sorter: true,
customRender: (text) => dayjs(text).format('YYYY-MM-DD HH:mm:ss')
},
{
title: '状态',
dataIndex: 'available',
width: 80,
align: 'center',
scopedSlots: { customRender: 'tags' },
enum: 'SYS0002',
filter: { type: SearchType.ENUM }
},
{
title: '操作',
key: 'operation',
width: 130,
scopedSlots: { customRender: 'action' }
}
]
formItemLayout: { export default {
labelCol: { name: 'SysUserList',
sm: {span: 8}, mixins: [TableScript],
}, components: { TableTemplate },
wrapperCol: { data() {
sm: {span: 16}, return {
}, title: '系统用户',
columns,
codes: [['SYS0002'], []],
toolbar: [
{
text: '新建',
handler: 'addNew'
} }
} ]
}, }
computed: { },
defaultPageSize: function () { methods: {
return this.$defaultPageSize() queryData: getPage,
}
},
methods: {
search() {
this.query.page = 1;
this.loadData();
},
reset() {
this.query.page = 1;
this.query.username = "";
this.query.realName = "";
this.query.mobile = "";
this.query.available = "";
this.loadData();
},
pageChange(page) {
this.query.page = page;
this.loadData();
},
sizeChange(current, size) {
this.query.size = size;
this.loadData();
},
loadData(pageSize) {
if (pageSize && !isNaN(pageSize)) {
this.query.size = pageSize
}
getPage(this.query).then(response => {
if (response && response.code == SYS_CONST.REQUEST.SUCCEED) {
let respData = response.data;
this.total = respData.total;
this.dataSource = respData.list;
}
});
},
sortChange(pagination, filters, sorter) {
this.query.sort = humpToLine(sorter.field);
this.query.order = setOrder(sorter.order);
this.loadData();
},
setStatus(record) {
changeStatus(record.id).then(response=> {
if (response && response.code == SYS_CONST.REQUEST.SUCCEED) {
this.loadData();
}
});
},
addNew() { addNew() {
this.editRow() this.editRow()
}, },
editRow(row) { editRow(row) {
this.$router.push({name: detailPathName, query: {id: row ? row.id : 0}}) this.$router.push({name: 'sysUserDetail', query: {id: row ? row.id : 0}})
},
updateSelect(selectedRowKeys) {
this.selectedRowKeys = selectedRowKeys
}, },
onChangeStatus() { setStatus(record) {
this.loadData(); changeStatus(record.id).then(({ code }) => {
}, if (code == 200) {
resetPwd(rowData) {
let _this = this;
let contText = '确定重置[' + rowData.realName + ']的密码?'
this.$confirm({
title: '提示',
content: contText,
onOk() {
resetPwd(rowData.id).then(response => {
if (response && response.code == SYS_CONST.REQUEST.SUCCEED) {
_this.$notification.success({
message: '系统提示',
description: "重置密码成功",
duration: 4,
});
}
})
},
onCancel() {
},
});
},
getavailable() {
getCommonCode([SYS_CONST.CODE.SYS_AVAILABLE_STATUS]).then(response => {
if (response && response.code == SYS_CONST.REQUEST.SUCCEED) {
this.availabStatus = response.data.data[SYS_CONST.CODE.SYS_AVAILABLE_STATUS];
}
})
},
},
mounted() {
// 查询状态下拉菜单
this.getavailable();
this.loadData(this.defaultPageSize);
},
activated() {
if (this.isFirstLoad == true) {
this.loadData(this.defaultPageSize)
this.isFirstLoad = false
} else {
let isModify = this.$route.query.isModify
if (isModify == true) {
this.loadData()
} else if (isModify != undefined) {
this.loadData() this.loadData()
} }
} })
},
resetPwd(rowData) {
let _this = this
let contText = '确定重置[' + rowData.realName + ']的密码?'
this.$confirm({
title: '提示',
content: contText,
onOk() {
resetPwd(rowData.id).then((response) => {
if (response && response.code == SYS_CONST.REQUEST.SUCCEED) {
_this.$notification.success({
message: '系统提示',
description: '重置密码成功',
duration: 4
})
}
})
},
onCancel() {}
})
} }
} }
</script> }
</script>
\ No newline at end of file
<template>
<keep-alive v-if="keepAlive">
<router-view />
</keep-alive>
<router-view v-else />
</template>
<script>
export default {
name: "SysUserRouteView",
computed: {
keepAlive () {
return this.$route.meta.keepAlive
}
},
}
</script>
\ No newline at end of file
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
<a-menu-item key="0"> 修改为 普通用户 </a-menu-item> <a-menu-item key="0"> 修改为 普通用户 </a-menu-item>
<a-menu-item key="1"> 修改为 客服 </a-menu-item> <a-menu-item key="1"> 修改为 客服 </a-menu-item>
<a-menu-item key="2"> 修改为 估价员 </a-menu-item> <a-menu-item key="2"> 修改为 估价员 </a-menu-item>
<a-menu-item key="3"> 修改为 销售 </a-menu-item>
</a-menu> </a-menu>
</a-dropdown> </a-dropdown>
</span> </span>
......
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