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_WEBSOCKET = 'ws://localhost:8297/websocket'
\ No newline at end of file
NODE_ENV=production
VUE_APP_URL = 'http://172.16.1.55:8297/'
VUE_APP_WEBSOCKET = 'ws://172.16.1.55:8297/websocket'
\ No newline at end of file
This diff is collapsed.
......@@ -15,7 +15,6 @@
"@antv/g2": "4.2.4",
"@babel/polyfill": "7.0.0",
"@babel/runtime": "7.2.0",
"@tinymce/tinymce-vue": "2.1.0",
"ant-design-vue": "1.7.8",
"axios": "0.18.0",
"dayjs": "1.7.7",
......@@ -25,12 +24,12 @@
"lodash.get": "4.4.2",
"lodash.pick": "4.4.0",
"nprogress": "0.2.0",
"tinymce": "5.0.8",
"simple-lightbox": "^2.1.0",
"vue": "2.6.11",
"vue-cropper": "0.4.4",
"vue-ls": "3.2.0",
"vue-router": "3.0.1",
"vuex": "3.0.1"
"vuex": "3.0.1",
"wangeditor": "^4.7.5"
},
"devDependencies": {
"@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
})
}
......@@ -43,3 +43,12 @@ export function saveOrUpdateSubClass(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 = {
getPage: '/sys/role/page',
......@@ -46,3 +46,11 @@ export function changeStatus(id) {
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 {
* @returns 图片url数组
* */
getValue() {
console.info(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 {
},
activated() {
mounted() {
// 初始化一些必要数据
// this.list.forEach();
// 计算修改量
......
......@@ -41,7 +41,7 @@ export default {
useSelection: true,
// 标题
title: '列表',
keep: false, // 保持状态
keep: true, // 保持状态
useSearch: true, // 显示搜索
customClass: '',
useTitle: true,
......@@ -134,7 +134,7 @@ export default {
}
}
this.loading = false
if(this.loadSuccess) {
if (this.loadSuccess) {
this.loadSuccess()
}
})
......@@ -226,6 +226,7 @@ export default {
}
},
onCollapse(gap) {
console.info('gap', gap)
this.searchHeight = gap
}
},
......
......@@ -79,7 +79,10 @@
</a-table>
<slot name="free" />
</div>
<span v-else>what the fuck?</span>
<div v-else>
what the fuck? <br />
where is my fucking page?
</div>
</template>
<script>
import SearchForm from './SearchForm'
......
......@@ -13,7 +13,7 @@ export default {
props: {
title: {
type: String,
default: '服务预约管理',
default: '城市匠人管理',
required: false
},
showTitle: {
......
......@@ -3,6 +3,7 @@ import Router from 'vue-router'
import { constantRouterMap, initRouterTree } from '@/router/router.config'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import 'simple-lightbox/dist/simpleLightbox.min.css' // progress bar style
import store from '@/store/index'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import notification from 'ant-design-vue/es/notification'
......
import Vue from 'vue'
import {getInfo, login} from "@/api/common/login"
import {ACCESS_TOKEN, BEARER} from "@/store/mutation-types"
import { getInfo, login } from "@/api/common/login"
import { ACCESS_TOKEN, BEARER } from "@/store/mutation-types"
import SocketService from '@/util/websocket'
const user = {
state: {
......@@ -12,6 +13,7 @@ const user = {
roles: [],
info: {},
buttons: null,
websocket: null,
},
mutations: {
......@@ -33,11 +35,14 @@ const user = {
SET_BUTTONS: (state, buttons) => {
state.buttons = buttons
},
SET_WEBSOCKET: (state, websocket) => {
state.websocket = websocket
}
},
actions: {
// 登录
Login({commit}, userInfo) {
Login({ commit }, userInfo) {
return new Promise((resolve, reject) => {
login(userInfo).then(response => {
if (response.code == SYS_CONST.REQUEST.SUCCEED) {
......@@ -57,7 +62,7 @@ const user = {
})
},
// 获取用户信息
GetInfo({commit}) {
GetInfo({ commit }) {
return new Promise((resolve, reject) => {
getInfo().then(response => {
let data = response.data;
......@@ -74,6 +79,9 @@ const user = {
commit('SET_AVATAR', data.userInfo.avatar);
commit('SET_BUTTONS', buttonAuthList);
SocketService.init()
resolve(response)
}).catch(error => {
reject(error)
......@@ -82,7 +90,7 @@ const user = {
},
// 登出
Logout({commit}) {
Logout({ commit }) {
return new Promise((resolve) => {
commit('SET_TOKEN', '');
commit('SET_ROLES', []);
......
......@@ -3,6 +3,7 @@
*/
import store from '@/store/index'
import {getCommonCode} from '@/api/system/sysCode'
import {getSubClassSelectable} from '@/api/serv'
export function triggerWindowResizeEvent() {
let event = document.createEvent('HTMLEvents')
......@@ -97,9 +98,11 @@ export function hasBtnPermission(permission) {
}
const bizCode = {
SUB_CLASSES: 'subClasses'
};
const bizCodeMapping = {
[bizCode.SUB_CLASSES]: () => getSubClassSelectable().then(({data}) => data)
};
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 @@
<a-space>
<template v-if="record.type == 1">
<a @click="add(record)">添加服务项</a>
<a @click="editCategory(record)">修改信息</a>
</template>
<template v-if="record.type == 2">
<a @click="edit(record)">修改信息</a>
......@@ -22,6 +23,7 @@
</template>
<template #free>
<SubClassEdit ref="SubClassEdit" :success="reset" />
<CategoryEdit ref="CategoryEdit" :success="reset" />
</template>
</table-template>
</template>
......@@ -29,6 +31,7 @@
import { TableTemplate, TableScript, SearchType } from '@/components/table'
import { getCategoryList, saveOrUpdateSubClass } from '@/api/serv'
import SubClassEdit from './SubClassEdit.vue'
import CategoryEdit from './CategoryEdit.vue'
import dayjs from 'dayjs'
const columns = [
......@@ -61,7 +64,7 @@ const columns = [
export default {
name: 'ServiceList',
mixins: [TableScript, {}],
components: { TableTemplate, SubClassEdit },
components: { TableTemplate, SubClassEdit, CategoryEdit },
data() {
return {
columns,
......@@ -76,7 +79,6 @@ export default {
methods: {
queryData: getCategoryList,
loadSuccess() {
console.info('xxxxxxxxxssssssssssss')
this.expandedRowKeys = this.dataSource.map((d) => d.id + '')
},
enableChange(record, index) {
......@@ -118,6 +120,9 @@ export default {
categoryId: record.id,
categoryName: record.serviceName
})
},
editCategory(record) {
this.$refs.CategoryEdit.show(record.id)
}
}
}
......
<template>
<a-drawer
:width="500"
:width="1000"
:visible="visible"
:title="id ? '编辑服务项' : '新增服务项'"
@close="close"
>
<a-form :form="form" layout="vertical">
<a-row>
<a-form-item :label="`服务大类: ${categoryName}`"> </a-form-item>
<a-col :span="11">
<a-form-item label="名称">
<a-input v-decorator="['serviceName']" />
</a-form-item>
</a-col>
<a-col :span="11" :offset="1">
<a-form-item label="次级标题">
<a-input v-decorator="['description']" />
</a-form-item>
</a-col>
<a-col :span="5">
<ImageUpload
label="图片"
decoration="img"
......@@ -18,9 +27,28 @@
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>
<div class="drawer-form-bottom-toolbar">
<a-button :style="{ marginRight: '8px' }" @click="close"> 取消 </a-button>
......@@ -31,10 +59,11 @@
<script>
import ImageUpload from '@/components/image-upload/ImageUpload'
import { saveOrUpdateSubClass, getSubDetails } from '@/api/serv'
import RichText from '@/components/richtext/richtext-editor'
export default {
name: 'SubClassEdit',
components: { ImageUpload },
components: { ImageUpload, RichText },
props: { success: Function },
data() {
return {
......@@ -55,6 +84,8 @@ export default {
getSubDetails(this.id).then(({ data }) => {
this.form.setFieldsValue(data)
this.$refs.image.setValue([data.img])
this.$refs.detailImg.setValue([data.detailImg])
this.$refs.RichText.setContent(data.textDescription)
})
}
},
......@@ -63,7 +94,9 @@ export default {
this.categoryId = null
this.categoryName = ''
this.$refs.image.reset()
this.$refs.detailImg.reset()
this.form.resetFields()
this.$refs.RichText.clear()
this.visible = false
},
submit() {
......@@ -74,8 +107,10 @@ export default {
const reqData = {
...values,
img: this.$refs.image.getValue()[0],
detailImg: this.$refs.detailImg.getValue()[0],
id: this.id,
categoryId: this.categoryId
categoryId: this.categoryId,
textDescription: this.$refs.RichText.getContent()
}
saveOrUpdateSubClass(reqData).then(({ code }) => {
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 {
this.$store
.dispatch("GenerateRoutes", initRouterTree(menuList))
.then(() => {
console.info('this.$store.getters.addRouters', this.$store.getters.addRouters)
this.$router.addRoutes(this.$store.getters.addRouters);
let redirectPath = this.$route.query.redirect;
if (redirectPath) {
......
This diff is collapsed.
......@@ -75,7 +75,6 @@
</span>
<span slot="tags" slot-scope="text, record">
<a-switch
:disabled="record.id==1"
checkedChildren="启用"
unCheckedChildren="禁用"
@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
This diff is collapsed.
<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>
<div>
<sys-param-component
:type="type"
:listName="listName"
></sys-param-component>
</div>
<table-template :soul="this">
<template #action="{ record }">
<a @click="editRow(record)">编辑</a>
</template>
<template #tags="{ value }">
<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>
<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 {
name: 'SysParamList',
components: { SysParamComponent },
components: { TableTemplate, SysParamEdit },
mixins: [TableScript],
data() {
return {
type: 'system',
listName: '总控系统参数列表'
title: '系统参数',
columns,
codes: [['SYS0005'], []]
}
},
methods: {
queryData: getPage,
getValue(record) {
if (record.type == 3) {
return '[点击编辑查看]'
}
return record.value
},
methods: {}
editRow(row) {
this.$refs.SysParamEdit.show(row)
}
}
}
</script>
This diff is collapsed.
This diff is collapsed.
<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 @@
<a-menu-item key="0"> 修改为 普通用户 </a-menu-item>
<a-menu-item key="1"> 修改为 客服 </a-menu-item>
<a-menu-item key="2"> 修改为 估价员 </a-menu-item>
<a-menu-item key="3"> 修改为 销售 </a-menu-item>
</a-menu>
</a-dropdown>
</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