dev-zcx
zcxee 2 years ago
parent a7606b1f20
commit bff5199726
  1. 21
      package.json
  2. 43
      src/api/sch/classType.js
  3. 27
      src/api/sch/place.js
  4. 36
      src/api/sch/school.js
  5. 7
      src/api/system/dept.js
  6. 42
      src/api/system/employee.js
  7. 9
      src/api/system/role.js
  8. 12
      src/api/system/user.js
  9. 0
      src/api/tool/common.js
  10. 0
      src/api/tool/map.js
  11. 186
      src/api/zs/clue.js
  12. 89
      src/api/zs/sign.js
  13. BIN
      src/assets/images/place/flag_black.png
  14. BIN
      src/assets/images/place/flag_blue.png
  15. BIN
      src/assets/images/place/flag_green.png
  16. BIN
      src/assets/images/place/flag_purple.png
  17. BIN
      src/assets/images/place/flag_red.png
  18. BIN
      src/assets/images/place/flag_yellow.png
  19. 278
      src/components/CustomColumnTable/index.vue
  20. 4
      src/global/components.js
  21. 2
      src/layout/components/AppMain.vue
  22. 29
      src/main.js
  23. 119
      src/router/index.js
  24. 23
      src/store/modules/permission.js
  25. 2
      src/utils/auth.js
  26. 13
      src/utils/ruoyi.js
  27. 491
      src/views/sch/classType.vue
  28. 130
      src/views/sch/components/schoolForm.vue
  29. 772
      src/views/sch/place.vue
  30. 121
      src/views/sch/school.vue
  31. 491
      src/views/system/employee/index.vue
  32. 157
      src/views/system/role/index.vue
  33. 209
      src/views/system/user/index.vue
  34. 784
      src/views/zs/clue.vue
  35. 73
      src/views/zs/components/batchUpdateForm.vue
  36. 650
      src/views/zs/components/clueForm.vue
  37. 95
      src/views/zs/components/distributeForm.vue
  38. 73
      src/views/zs/components/filterForm.vue
  39. 84
      src/views/zs/components/publicTable.vue
  40. 416
      src/views/zs/components/signForm.vue
  41. 0
      src/views/zs/sign.vue
  42. 29
      vue.config.js

@ -17,9 +17,20 @@
}
},
"lint-staged": {
"src/**/*.{js,vue}": ["eslint --fix", "git add"]
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
},
"keywords": ["vue", "admin", "dashboard", "element-ui", "boilerplate", "admin-template", "management-system"],
"keywords": [
"vue",
"admin",
"dashboard",
"element-ui",
"boilerplate",
"admin-template",
"management-system"
],
"repository": {
"type": "git",
"url": "https://gitee.com/y_project/RuoYi-Vue.git"
@ -42,6 +53,7 @@
"screenfull": "5.0.2",
"sortablejs": "1.10.2",
"vue": "2.6.12",
"vue-amap": "^0.5.10",
"vue-count-to": "1.0.13",
"vue-cropper": "0.5.5",
"vue-meta": "2.4.0",
@ -72,5 +84,8 @@
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"browserslist": ["> 1%", "last 2 versions"]
"browserslist": [
"> 1%",
"last 2 versions"
]
}

@ -0,0 +1,43 @@
import request from '@/utils/request'
// 查询班型列表
export function getClassTypeTableList(query) {
return request({
url: '/sch/classType/list',
method: 'get',
params: query
})
}
// 新增班型
export function insertClassType(params) {
return request({
url: '/sch/classType',
method: 'post',
data: params
})
}
// 修改班型
export function updateClassType(params) {
return request({
url: '/sch/classType',
method: 'put',
data: params
})
}
// 删除班型
export function deleteClassType(ids) {
return request({
url: '/sch/classType/' + ids,
method: 'delete'
})
}
//克隆班型
export function cloneClassType(data) {
return request({
url: '/sch/classType/clone',
method: 'post',
data: data
})
}

@ -0,0 +1,27 @@
import request from '@/utils/request'
// 获取地图数据
export function getMapData() {
return request({
url: '/sch/place/list',
method: 'get'
})
}
// 更新驾校状态
export async function updateSchoolStatus(data) {
return await request({
url: '/sch/place/updateSchool',
method: 'put',
data: data
})
}
// 保存场地状态
export function savePlace(data) {
return request({
url: '/sch/place',
method: 'post',
data: data
})
}

@ -0,0 +1,36 @@
import request from '@/utils/request'
export default {
pageList(data = {}) {
return request({
url: "/sch/school/list",
method: "get",
params: data,
});
},
getById(id) {
return request({
url: `/sch/school/${id}`,
method: "get",
});
},
add(data = {}) {
return request({
url: "/sch/school",
method: "post",
data,
});
},
update(data = {}) {
return request({
url: "/sch/school",
method: "put",
data,
});
},
delete(id) {
return request({
url: `/sch/school/${id}`,
method: "delete",
});
}
}

@ -50,3 +50,10 @@ export function delDept(deptId) {
method: 'delete'
})
}
// 查询部门下拉树结构
export function deptTreeSelect() {
return request({
url: '/system/dept/deptTree',
method: 'get'
})
}

@ -0,0 +1,42 @@
import request from '@/utils/request'
export default {
pageList(data = {}) {
return request({
url: "/system/employee/list",
method: "get",
params: data,
});
},
getById(id) {
return request({
url: `/system/employee/${id}`,
method: "get",
});
},
add(data = {}) {
return request({
url: "/system/employee",
method: "post",
data,
});
},
update(data = {}) {
return request({
url: "/system/employee",
method: "put",
data,
});
},
delete(id) {
return request({
url: `/system/employee/${id}`,
method: "delete",
});
},
getEmployee() {
return request({
url: "/system/employee/getEmployees",
method: "get"
});
}
}

@ -117,3 +117,12 @@ export function deptTreeSelect(roleId) {
method: 'get'
})
}
export function getRoleOptions() {
return request({
url: '/system/role/getRoles',
method: 'get'
})
}

@ -1,5 +1,7 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
import {
parseStrEmpty
} from "@/utils/ruoyi";
// 查询用户列表
export function listUser(query) {
@ -125,11 +127,3 @@ export function updateAuthRole(data) {
params: data
})
}
// 查询部门下拉树结构
export function deptTreeSelect() {
return request({
url: '/system/user/deptTree',
method: 'get'
})
}

@ -0,0 +1,186 @@
import request from '@/utils/request'
// 查询线索列表
export function getClueList(query) {
return request({
url: '/zs/clue/list',
method: 'get',
params: query
})
}
// 新增线索
export function addClue(data) {
return request({
url: '/zs/clue',
method: 'post',
data: data
})
}
// 修改线索
export function updateClue(data) {
return request({
url: '/zs/clue',
method: 'put',
data: data
})
}
//删除
export function deleteClue(data) {
return request({
url: '/zs/clue',
method: 'delete',
params: data
})
}
// 导出
export function exportData(query) {
return request({
url: '/zs/clue/export',
method: 'get',
params: query
})
}
// 导入模板
export function importTemplate(param) {
return request({
url: '/zs/clue/importTemplate',
method: 'get',
params: param
})
}
// 导入
export function importData(data) {
return request({
url: '/zs/clue/importData',
method: 'post',
data: data
})
}
//查询登记getSign
export function getSign(query) {
return request({
url: '/zs/clue/sign',
method: 'get',
params: query
})
}
//保存登记
export function saveSign(data) {
return request({
url: '/zs/clue/sign',
method: 'post',
data: data
})
}
//甩单
export function saveDistribute(data) {
return request({
url: '/zs/clue/distribute',
method: 'put',
data: data
})
}
//驳回
export function refuse(data) {
return request({
url: '/zs/clue/refuse',
method: 'put',
data: data
})
}
//查询甩单记录
export function getDistributeRecord(param) {
return request({
url: '/zs/clue/distributerecord',
method: 'get',
params: param
})
}
//查询跟踪记录
export function getFollowRecord(param) {
return request({
url: '/zs/clue/followrecord',
method: 'get',
params: param
})
}
//
export function getConsultRecord(param) {
return request({
url: '/zs/clue/consultrecord',
method: 'get',
params: param
})
}
// 获取已过期
export function getClueCountBadge() {
return request({
url: `/zs/clue/badgeCount`,
method: 'get'
})
}
// 批量更新
export function batchUpdate(data) {
return request({
url: `/zs/clue/batchUpdate`,
method: 'put',
data: data
})
}
//公海线索 getPublicList
export function getPublicList(param) {
return request({
url: `/zs/clue/public/list`,
method: 'get',
params: param
})
}
//拾取线索
export function pickupClue(data) {
return request({
url: `/zs/clue/public/pickup`,
method: 'put',
data: data
})
}
//丢弃线索
export function discardClue(data) {
return request({
url: `/zs/clue/public/discard`,
method: 'put',
data: data
})
}
//查询接收
export function getAccept() {
return request({
url: `/zs/clue/accept`,
method: 'get'
})
}
//丢弃线索
export function updateAccept(data) {
return request({
url: `/zs/clue/accept`,
method: 'put',
data: data
})
}

@ -0,0 +1,89 @@
import request from '@/utils/request'
// 查询线索列表
export function getSignList(query) {
return request({
url: '/zs/sign/list',
method: 'get',
params: query
})
}
// 导出
export function exportData(query) {
return request({
url: '/zs/sign/export',
method: 'get',
params: query
})
}
// 导入模板
export function importTemplate() {
return request({
url: '/zs/sign/importTemplate',
method: 'get'
})
}
// 导入
export function importData(data) {
return request({
url: '/zs/sign/importData',
method: 'post',
data: data
})
}
export function addSign(data) {
return request({
url: '/zs/sign',
method: 'post',
data: data
})
}
export function updateSign(data) {
return request({
url: '/zs/sign',
method: 'put',
data: data
})
}
export function getClues(param) {
return request({
url: '/zs/sign/clue',
method: 'get',
params: param
})
}
export function deleteSign(data) {
return request({
url: '/zs/sign',
method: 'delete',
params: data
})
}
//审核登记
export function checkSign(data) {
return request({
url: '/zs/sign/check',
method: 'put',
data: data
})
}
//审核记录
export function getCheckRecord(data) {
return request({
url: '/zs/sign/check',
method: 'get',
params: data
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

@ -0,0 +1,278 @@
<!--
组件方法
getlist: 将分页组件合并所以需要分页查询列表的数据的方法
selectRow选择行时触发 配合selectable使用
callFunc 操作按钮点击时触发 配合tableBtns使用 会传递按钮的方法名和行数据
clickColumn 点击表格列时触发 配合clickColumns使用 传递到父级时接受两个参数columnrow点击的列名行数据
clickRow: 点击表格行时触发 ps: 建议不要与点击表格列方法同时使用
changeSort: 表格列排序
-->
<template>
<div>
<div class="table-custom">
<span class="custom-table-btn" @click="showCustomClick">自定义列表</span>
<el-table v-loading="tableLoading" :data="tableList" border stripe max-height="500" @selection-change="handleSelectionChange" @sort-change="changeSort" @row-click="handleRowClick">
<el-table-column v-if="selectable" type="selection" width="60" />
<el-table-column type="index" :index="(index)=>((queryParams.pageNum - 1)*queryParams.pageSize + index + 1)" label="序号" width="60" />
<el-table-column v-for="(item, index) in tableColumns" :key="index" :label="item.label" :width="item.width" :prop="item.prop" :sortable="sortableColumns.includes(item.prop)" :min-width="clickColumns.includes(item.prop)?150:100">
<template slot-scope="{row}">
<el-button v-if="clickColumns.includes(item.prop)" type="text" size="mini" @click="$emit('clickColumn', item.prop, row)">{{ row[item.prop] }}</el-button>
<span v-else>{{ row[item.prop] }}</span>
</template>
</el-table-column>
<slot name="appendColumn" />
<el-table-column v-if="tableBtns.length > 0" label="操作" fixed="right" :width="getOpearateWidth()">
<template slot-scope="{row}">
<template v-if="tableBtns">
<template v-for="(item, index) in tableBtns.slice(0, 2)">
<el-button v-if="btnShow(row, item)" :key="index" type="text" @click.native.stop="call(item.buttonTrigger, row)">{{ item.buttonName }}</el-button>
</template>
<template v-if="tableBtns.length > 2">
<el-dropdown class="ml0" trigger="click">
<el-button type="primary" size="mini">
更多
<i class="el-icon-arrow-down el-icon--right" />
</el-button>
<el-dropdown-menu slot="dropdown">
<template v-for="(btn, idx) in tableBtns.slice(2, tableBtns.length)">
<el-dropdown-item v-if="btnShow(row, item)" :key="idx" @click.native.stop="call(btn.buttonTrigger, row)">{{ btn.buttonName }}</el-dropdown-item>
</template>
</el-dropdown-menu>
</el-dropdown>
</template>
</template>
</template>
</el-table-column>
</el-table>
</div>
<pagination :page-sizes="[10, 20, 30, 50, 100, 200]" :total="queryParams.total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="_getTableList" />
<el-dialog title="自定义字段配置" :visible.sync="columnsetDialogShow" append-to-body class="dialog500" width="60%">
<el-row :gutter="20">
<el-col :span="18">
<el-card shadow="never">
<div slot="header">
<el-checkbox v-model="columnCheckAll" @change="val => dialogSelectColumn = val ? tableAllFields.map(item=>item.prop):[] ">可选显示数据列</el-checkbox>
</div>
<el-checkbox-group v-model="dialogSelectColumn" style="line-height: 32px">
<el-checkbox v-for="item in tableAllFields" :key="item.prop" :label="item.prop">{{ item.label }}</el-checkbox>
</el-checkbox-group>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="never">
<div slot="header">
已选{{ dialogSelectColumn.length }}
<span class="ml0" style="font-size: 8px">(可拖动排序)</span>
</div>
<draggable :list="dialogSelectColumn" :animation="340" group="column">
<div v-for="item in dialogSelectColumn" :key="item" class="hover-pointer">
<div style="line-height: 24px;">{{ tableAllFields.find(column=> column.prop === item).label }}</div>
</div>
</draggable>
</el-card>
</el-col>
</el-row>
<span slot="footer">
<el-button @click="columnsetDialogShow = false">取消</el-button>
<el-button type="primary" @click="handleChangeColumns">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import draggable from 'vuedraggable'
export default {
components: { draggable },
props: {
tableList: {
type: Array,
default: () => [],
},
tableLoading: {
type: Boolean,
default: false,
},
queryParams: {
required: true,
type: Object,
default: () => ({
pageNum: 1,
pageSize: 10,
total: 0,
}),
},
//
tableBtns: {
type: Array,
default: () => [],
},
//
selectable: {
type: Boolean,
default: false,
},
/**
* 接口访问得到的所有表格列/或者写死的表格列格
* 格式是 { pror: '', label: '' }
*/
tableAllFields: {
required: true,
type: Array,
default: () => [],
},
/**
* 默认表格列
* 字符串数组 prop 对应值字段名
*/
defaultColumns: {
type: Array,
default: () => [],
},
tablename: {
type: String,
default: '',
},
//
clickColumns: {
type: Array,
default: () => [],
},
//
btnShowValid: {
type: Array,
default: () => [],
},
//
sortableColumns: {
type: Array,
default: () => [],
},
},
data() {
return {
columnsetDialogShow: false,
columnCheckAll: false,
dialogSelectColumn: [],
name: this.tablename || this.$route.name,
customColumns: [], //
tableColumns: [], //
}
},
watch: {
tableAllFields: {
handler(val) {
const localStr = localStorage.getItem(this.name)
const arr = localStr ? localStr.split(',') : []
if (this.isNullOrEmpty(arr)) {
this.tableColumns = val
.filter((item) => this.defaultColumns.includes(item.prop))
.sort(
(a, b) =>
this.defaultColumns.indexOf(a.prop) -
this.defaultColumns.indexOf(b.prop)
)
this.customColumns = this.defaultColumns
} else {
this.tableColumns = val
.filter((item) => arr.includes(item.prop))
.sort((a, b) => arr.indexOf(a.prop) - arr.indexOf(b.prop))
}
},
immediate: true,
deep: true,
},
},
created() {
if (this.isNullOrEmpty(this.customColumns)) {
const localStr = localStorage.getItem(this.name)
this.customColumns = localStr ? localStr.split(',') : []
}
},
methods: {
showCustomClick() {
this.columnsetDialogShow = true
this.dialogSelectColumn = [...this.customColumns]
},
handleChangeColumns() {
this.customColumns = this.dialogSelectColumn
this.tableColumns = this.tableAllFields
.filter((item) => this.customColumns.includes(item.prop))
.sort(
(a, b) =>
this.customColumns.indexOf(a.prop) -
this.customColumns.indexOf(b.prop)
)
localStorage.setItem(this.name, this.customColumns.join(','))
this.columnsetDialogShow = false
},
_getTableList() {
this.$emit('update:queryParams', this.queryParams)
this.$emit('getlist')
},
handleSelectionChange(row) {
this.selectable && this.$emit('selectRow', row)
},
changeSort(val) {
this.$emit('changeSort', val)
},
handleRowClick(row) {
this.$emit('clickRow', row)
},
call(funcName, row) {
this.$emit('callFunc', funcName, row)
},
getOpearateWidth() {
let width = 30
for (let index = 0; index < this.tableBtns.length; index++) {
if (index < 2) {
const column = this.tableBtns[index]
width += column.buttonName.length * 15
column.buttonColor !== 'text' && (width += 30)
} else {
width += 70 //
break
}
}
return width
},
btnShow(row, btn) {
if (this.isNullOrEmpty(this.btnShowValid)) {
return true
} else {
let show = true
for (let i = 0; i < this.btnShowValid.length; i++) {
const valid = this.btnShowValid[i]
if (row[valid.key] === valid.value) {
show = btn.buttonName !== valid.btnName
}
}
return show
}
},
},
}
</script>
<style scoped>
.table-custom {
width: calc(100% - 30px);
position: relative;
}
.custom-table-btn {
width: 30px;
display: block;
position: absolute;
right: -31px;
top: 0;
text-align: center;
color: cadetblue;
border: 1px solid #e6ebf5;
font-size: 14px;
padding: 5px;
box-sizing: border-box;
cursor: pointer;
}
</style>

@ -13,6 +13,8 @@ import ImageUpload from "@/components/ImageUpload";
import ImagePreview from "@/components/ImagePreview";
// 字典标签组件
import DictTag from "@/components/DictTag";
// 字典数据组件
import DictData from '@/components/DictData'
// 全局组件挂载
Vue.component("DictTag", DictTag);
@ -22,3 +24,5 @@ Vue.component("Editor", Editor);
Vue.component("FileUpload", FileUpload);
Vue.component("ImageUpload", ImageUpload);
Vue.component("ImagePreview", ImagePreview);
DictData.install()

@ -1,5 +1,5 @@
<template>
<section class="app-main bc-f7">
<section class="app-main">
<transition name="fade-transform" mode="out-in">
<keep-alive :include="cachedViews">
<router-view v-if="!$route.meta.link" :key="key" />

@ -19,9 +19,38 @@ import './global';
import './assets/icons'; // icon
import './permission'; // permission control
import {
download
} from '@/utils/request'
import {
getDicts
} from "@/api/system/dict/data";
import {
getConfigKey
} from "@/api/system/config";
import {
parseTime,
resetForm,
addDateRange,
selectDictLabel,
selectDictLabels,
handleTree
} from "@/utils/ruoyi";
// 头部标签组件
import VueMeta from 'vue-meta';
// 全局方法挂载
Vue.prototype.getDicts = getDicts
Vue.prototype.getConfigKey = getConfigKey
Vue.prototype.parseTime = parseTime
Vue.prototype.resetForm = resetForm
Vue.prototype.addDateRange = addDateRange
Vue.prototype.selectDictLabel = selectDictLabel
Vue.prototype.selectDictLabels = selectDictLabels
Vue.prototype.download = download
Vue.prototype.handleTree = handleTree
import Mixin from './mixins/Mixin';
Vue.mixin(Mixin);

@ -29,17 +29,14 @@ import Layout from '@/layout';
*/
// 公共路由
export const constantRoutes = [
{
export const constantRoutes = [{
path: '/redirect',
component: Layout,
hidden: true,
children: [
{
children: [{
path: '/redirect/:path(.*)',
component: () => import('@/views/redirect')
}
]
}]
},
{
path: '/login',
@ -65,108 +62,122 @@ export const constantRoutes = [
path: '',
component: Layout,
redirect: 'index',
children: [
{
children: [{
path: 'index',
component: () => import('@/views/index'),
name: 'Index',
meta: { title: '首页', icon: 'dashboard', affix: true }
}
]
},
{
path: '/demo',
component: Layout,
redirect: 'noredirect',
meta: { title: 'Demo', icon: 'xx' },
children: [
{
path: '/base-page',
component: () => import('@/views/demo/basePage/index'),
name: 'BasePage',
meta: { title: 'BasePage', icon: 'xx' }
},
{
path: '/base-components',
component: () => import('@/views/demo/baseComponents/index'),
name: 'BaseComponents',
meta: { title: 'BaseComponents', icon: 'xx' }
meta: {
title: '首页',
icon: 'dashboard',
affix: true
}
]
}]
},
// {
// path: '/demo',
// component: Layout,
// redirect: 'noredirect',
// meta: {
// title: 'Demo',
// icon: 'xx'
// },
// children: [{
// path: '/base-page',
// component: () => import('@/views/demo/basePage/index'),
// name: 'BasePage',
// meta: {
// title: 'BasePage',
// icon: 'xx'
// }
// },
// {
// path: '/base-components',
// component: () => import('@/views/demo/baseComponents/index'),
// name: 'BaseComponents',
// meta: {
// title: 'BaseComponents',
// icon: 'xx'
// }
// }
// ]
// },
{
path: '/user',
component: Layout,
hidden: true,
redirect: 'noredirect',
children: [
{
children: [{
path: 'profile',
component: () => import('@/views/system/user/profile/index'),
name: 'Profile',
meta: { title: '个人中心', icon: 'user' }
meta: {
title: '个人中心',
icon: 'user'
}
]
}]
}
];
// 动态路由,基于用户权限动态去加载
export const dynamicRoutes = [
{
export const dynamicRoutes = [{
path: '/system/user-auth',
component: Layout,
hidden: true,
permissions: ['system:user:edit'],
children: [
{
children: [{
path: 'role/:userId(\\d+)',
component: () => import('@/views/system/user/authRole'),
name: 'AuthRole',
meta: { title: '分配角色', activeMenu: '/system/user' }
meta: {
title: '分配角色',
activeMenu: '/system/user'
}
]
}]
},
{
path: '/system/role-auth',
component: Layout,
hidden: true,
permissions: ['system:role:edit'],
children: [
{
children: [{
path: 'user/:roleId(\\d+)',
component: () => import('@/views/system/role/authUser'),
name: 'AuthUser',
meta: { title: '分配用户', activeMenu: '/system/role' }
meta: {
title: '分配用户',
activeMenu: '/system/role'
}
]
}]
},
{
path: '/system/dict-data',
component: Layout,
hidden: true,
permissions: ['system:dict:list'],
children: [
{
children: [{
path: 'index/:dictId(\\d+)',
component: () => import('@/views/system/dict/data'),
name: 'Data',
meta: { title: '字典数据', activeMenu: '/system/dict' }
meta: {
title: '字典数据',
activeMenu: '/system/dict'
}
]
}]
},
{
path: '/monitor/job-log',
component: Layout,
hidden: true,
permissions: ['monitor:job:list'],
children: [
{
children: [{
path: 'index',
component: () => import('@/views/monitor/job/log'),
name: 'JobLog',
meta: { title: '调度日志', activeMenu: '/monitor/job' }
meta: {
title: '调度日志',
activeMenu: '/monitor/job'
}
]
}]
}
];
@ -178,6 +189,8 @@ Router.prototype.push = function push(location) {
export default new Router({
mode: 'history', // 去掉url中的#
scrollBehavior: () => ({ y: 0 }),
scrollBehavior: () => ({
y: 0
}),
routes: constantRoutes
});

@ -1,6 +1,11 @@
import auth from '@/plugins/auth';
import router, { constantRoutes, dynamicRoutes } from '@/router';
import { getRouters } from '@/api/menu';
import router, {
constantRoutes,
dynamicRoutes
} from '@/router';
import {
getRouters
} from '@/api/menu';
import Layout from '@/layout/index';
import ParentView from '@/components/ParentView';
import InnerLink from '@/layout/components/InnerLink';
@ -30,7 +35,9 @@ const permission = {
},
actions: {
// 生成路由
GenerateRoutes({ commit }) {
GenerateRoutes({
commit
}) {
return new Promise((resolve) => {
// 向后端请求路由数据
getRouters().then((res) => {
@ -39,11 +46,15 @@ const permission = {
const sidebarRoutes = filterAsyncRouter(sdata);
const rewriteRoutes = filterAsyncRouter(rdata, false, true);
const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true });
rewriteRoutes.push({
path: '*',
redirect: '/404',
hidden: true
});
router.addRoutes(asyncRoutes);
commit('SET_ROUTES', rewriteRoutes);
// commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes));
commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat([]));
commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes));
// commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat([]));
commit('SET_DEFAULT_ROUTES', sidebarRoutes);
commit('SET_TOPBAR_ROUTES', sidebarRoutes);
resolve(rewriteRoutes);

@ -1,6 +1,6 @@
import Cookies from 'js-cookie';
const TokenKey = 'Admin-Token';
const TokenKey = 'DM-Manage-Token';
export function getToken() {
return Cookies.get(TokenKey);

@ -240,3 +240,16 @@ export async function blobValidate(data) {
return true;
}
}
export function isNullOrEmpty(val) {
if (val === null || val === undefined) {
return true
} else if (val === {} || Object.keys(val).length === 0) {
return true
} else if (val.length === 0) {
return true
} else {
return false
}
}

@ -0,0 +1,491 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<el-col :span="6">
<div class="head-container">
<el-input v-model="searchName" placeholder="请输入驾校名称" clearable prefix-icon="el-icon-search" style="margin-bottom: 20px" />
</div>
<div class="head-container" style="max-height: 700px;overflow-y: auto">
<el-tree ref="tree" :data="schoolOption.filter(item => item.label.includes(searchName))" accordion node-key="id" :default-expanded-keys="selectNodes.map(item => item.id)" @node-click="handleNodeClick" />
</div>
</el-col>
<el-col :span="18">
<el-row :gutter="20">
<el-form ref="queryForm" :model="queryParams" :inline="true">
<el-form-item>
<el-input v-model="queryParams.typeName" placeholder="请输入班型名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-select v-model="queryParams.licenseType" clearable placeholder="选择驾照类型">
<el-option v-for="item in licenseTypeOption" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
</el-select>
</el-form-item>
<el-form-item>
<el-select v-model="queryParams.status" placeholder="班型状态" clearable>
<el-option v-for="dict in statusOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
<el-button type="primary" icon="el-icon-plus" @click="handleAdd" v-hasPermi="['sch:classType:add']">新增</el-button>
<el-button type="danger" icon="el-icon-delete" @click="handleDelete" :disabled="multiple" v-hasPermi="['sch:classType:remove']">删除</el-button>
<el-button type="primary" icon="el-icon-copy" @click="handleClone" :disabled="multiple" v-hasPermi="['sch:classType:clone']">克隆</el-button>
</el-form-item>
</el-form>
</el-row>
<el-table v-loading="loading.tableLoading" :data="tableDataList" stripe border @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column type="index" width="50" />
<el-table-column label="驾校" prop="schoolName" />
<el-table-column label="场地" prop="placeName" />
<el-table-column label="班型名称" prop="typeName" />
<el-table-column label="驾照类型" prop="licenseType" :formatter="licenseTypeFormat" width="80" />
<!-- <el-table-column label="原价" prop="originalPrice" /> -->
<el-table-column label="报价" prop="currentPrice" width="60" />
<el-table-column label="底价" prop="minPrice" width="60" />
<el-table-column label="描述" prop="description" />
<el-table-column label="状态" prop="status" :formatter="statusFormat" width="80" />
<el-table-column label="创建时间" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="130">
<template slot-scope="scope">
<el-button v-hasPermi="['sch:classType:edit']" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button v-hasPermi="['sch:classType:remove']" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getPageList" />
</el-col>
</el-row>
<el-dialog title="班型设置" :visible.sync="modalVisible" width="500px" append-to-body :close-on-click-modal="false">
<el-form ref="modalForm" :model="modalForm" :rules="modalRules" label-width="80px">
<el-row>
<el-col :span="12">
<el-form-item label="驾校">
<el-input v-model="modalForm.schoolName" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="场地">
<el-input v-model="modalForm.placeName" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="班型名称" prop="typeName">
<el-input v-model="modalForm.typeName" placeholder="请输入班型名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="驾照类型" prop="licenseType">
<el-select v-model="modalForm.licenseType" placeholder="选择驾照类型">
<el-option v-for="item in licenseTypeOption" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="报价" prop="currentPrice">
<el-input v-model="modalForm.currentPrice" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="底价" prop="minPrice">
<el-input v-model="modalForm.minPrice" placeholder="请输入" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="甩单低价" prop="orderMinPrice">
<el-input v-model="modalForm.orderMinPrice" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="入账低价" prop="enterMinPrice">
<el-input v-model="modalForm.enterMinPrice" placeholder="请输入" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="公司低价" prop="companyMinPrice">
<el-input v-model="modalForm.companyMinPrice" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="员工低价" prop="employeeMinPrice">
<el-input v-model="modalForm.employeeMinPrice" placeholder="请输入" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="排序" prop="orderNum">
<el-input v-model="modalForm.orderNum" placeholder="请输入排序" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态" prop="currentPrice">
<el-radio-group v-model="modalForm.status">
<el-radio v-for="dict in statusOptions" :key="dict.dictValue" :label="dict.dictValue">{{ dict.dictLabel }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<!-- <el-row>
<el-col :span="24">
<el-form-item label="是否克隆到场地" prop="currentPrice">
<el-radio-group v-model="modalForm.clone">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</el-form-item>
<span>克隆到场地该班型则不统一管理</span>
</el-col>
</el-row> -->
<el-row>
<el-form-item label="描述" prop="description">
<el-input v-model="modalForm.description" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }" placeholder="请输入描述" />
</el-form-item>
</el-row>
</el-form>
<span slot="footer">
<el-button @click="modalVisible = false"> </el-button>
<el-button v-loading="loading.modalSaveLoading" type="primary" @click="handleSave"> </el-button>
</span>
</el-dialog>
<el-dialog title="克隆班型" :visible.sync="cloneOpen" width="780px" append-to-body :v-loading="loading.cloneLoading">
<el-form ref="clonForm" :model="clonForm" :rules="modalRules" label-width="80px">
<el-row>
<el-col :span="24">
<el-form-item label="场地" prop="placeIdList">
<el-select v-model="clonForm.placeIds" placeholder="请选择" size="small" multiple filterable clearable>
<el-option v-for="dict in placeOption" :key="dict.placeId" :label="dict.name" :value="dict.placeId" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer" style="padding-top:20px">
<el-button type="primary" @click="cloneSave"> </el-button>
<el-button @click="cloneOpen = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
getClassTypeTableList,
updateClassType,
insertClassType,
deleteClassType,
cloneClassType
} from '@/api/sch/classType'
import { validateMoney } from '@/utils/validate'
import { getMapData } from '@/api/sch/place'
export default {
name: 'Classtype',
data() {
return {
searchName: '',
queryParams: {
pageNum: 1,
pageSize: 10,
typeName: undefined,
status: undefined,
schoolId: this.$store.getters.schoolId,
licenseType: undefined,
},
loading: {
tableLoading: false,
modalSaveLoading: false,
cloneLoading: false
},
tableDataList: [],
total: 0,
statusOptions: [],
licenseTypeOption: [],
modalVisible: false,
modalForm: {},
modalRules: {
typeName: {
required: true,
message: '班型名称不为空',
trigger: 'blur',
},
originalPrice: {
required: true,
validator: validateMoney,
trigger: 'blur',
},
currentPrice: {
required: true,
validator: validateMoney,
trigger: 'blur',
},
minPrice: { required: true, validator: validateMoney, trigger: 'blur' },
placeIds: {
required: true,
message: '场地不为空',
trigger: 'change',
},
},
schoolOption: [],
placeOption: [],
selectNodes: [],
multiple: true,
single: true,
cloneOpen: false,
clonForm: {}
}
},
created() {
this.getDicts('sys_normal_disable').then((response) => {
this.statusOptions = response.data
})
this.getDicts('license_type').then((response) => {
this.licenseTypeOption = response.data
})
this._getSchoolTree()
this.getPageList()
this.deptId = this.$store.getters.schoolId
},
methods: {
//
handleQuery() {
this.queryParams.page = 1
this.getPageList()
},
getPageList() {
this.loading.tableLoading = true
const params = {
...this.queryParams,
schoolId:
this.selectNodes.length > 0 ? this.selectNodes[0].id : undefined,
placeId:
this.selectNodes.length == 2 ? this.selectNodes[1].id : undefined,
}
this.tableDataList = []
getClassTypeTableList(params).then(
(response) => {
this.tableDataList = response.rows
this.total = response.total
this.loading.tableLoading = false
}
)
},
//
resetQuery() {
this.queryParams.typeName = ''
this.queryParams.status = undefined
this.queryParams.schoolId = undefined
this.queryParams.placeId = undefined
this.queryParams.licenseType = undefined
this.handleQuery()
},
//
_getSchoolTree() {
getMapData().then((resp) => {
if (resp.code == 200) {
let sList = resp.data.schoolList.filter((item) => item.showInMap)
const pList = resp.data.placeList.filter((item) => item.showInMap)
sList = sList.map((item) => ({
id: item.schoolId,
label: item.schoolName,
level: 1,
children: pList
.filter((place) => item.schoolId === place.schoolId)
.map((place) => ({
id: place.placeId,
label: place.name,
level: 2,
})),
}))
this.schoolOption = sList
this.placeOption = resp.data.placeList
}
})
},
//
handleAdd() {
if (this.selectNodes.length < 1) {
this.msgError('请选择左侧驾校或场地')
return
}
this.resetForm('modalForm')
this.modalVisible = true
this.modalForm = {
typeName: '',
status: '0',
originalPrice: undefined,
licenseType: 'C1',
description: '',
currentPrice: undefined,
typeId: undefined,
schoolId: this.selectNodes[0].id,
schoolName: this.selectNodes[0].name,
clone: false,
orderMinPrice: undefined,
enterMinPrice: undefined,
companyMinPrice: undefined,
employeeMinPrice: undefined
}
if (this.selectNodes.length > 1) {
this.$set(this.modalForm, "placeId", this.selectNodes[1].id);
this.$set(this.modalForm, "placeName", this.selectNodes[1].name);
}
},
//
handleUpdate(listItem) {
this.resetForm('modalForm')
this.modalForm = {
...listItem
}
if (listItem.placeId) {
this.$set(
this.modalForm,
"placeName",
this.placeOption.find(item => item.placeId == listItem.placeId).name
);
}
this.modalVisible = true
},
//
handleSave() {
this.$refs.modalForm.validate((valid) => {
if (valid) {
this.loading.modalSaveLoading = true
if (this.modalForm.typeId) {
updateClassType(this.modalForm).then((resp) => {
if (resp.code === 200) {
this.$message.success('修改成功')
this.modalVisible = false
this.loading.modalSaveLoading = false
this.getPageList()
} else {
this.$message.error('修改失败:' + resp.message)
this.loading.modalSaveLoading = false
}
})
} else {
if (!this.modalForm.schoolId) {
this.$set(this.modalForm, 'schoolId', this.$store.getters.schoolId)
}
insertClassType(this.modalForm).then((resp) => {
if (resp.code === 200) {
this.$message.success('新增成功')
this.modalVisible = false
this.loading.modalSaveLoading = false
this.getPageList()
} else {
this.$message.error('新增失败:' + resp.message)
this.loading.modalSaveLoading = false
}
})
}
}
})
},
//
statusFormat(row, column) {
return this.selectDictLabel(this.statusOptions, row.status)
},
//
placeFormat(row, column) {
if (row.placeId) {
return this.placeOption.length > 0
? this.placeOption.find((item) => item.placeId == row.placeId).name
: ''
}
},
//
licenseTypeFormat(row, column) {
return this.selectDictLabel(this.licenseTypeOption, row.licenseType)
},
handleNodeClick(data, node) {
if (data.level === 1) {
this.selectNodes = [{ id: data.id, name: data.label }]
} else {
this.selectNodes = [
{ id: node.parent.data.id, name: node.parent.data.label },
{ id: data.id, name: data.label },
]
}
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.typeId);
this.nos = selection.map(item => item.productNo);
this.single = selection.length != 1;
this.multiple = !selection.length;
},
/** 删除按钮操作 */
handleDelete(item) {
const typeId = item.typeId || this.ids;
this.$confirm(
'是否确认删除?',
'警告',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then((res) => {
deleteClassType(typeId).then((resp) => {
if (resp.code === 200) {
this.$message.success('删除成功')
this.getPageList()
}
})
})
.catch(function () { })
},
handleClone() {
this.cloneOpen = true;
this.clonForm = {
typeIds: this.ids,
placeIds: undefined
}
},
cloneSave() {
this.$refs.clonForm.validate((valid) => {
if (valid) {
this.loading.cloneLoading = true
cloneClassType(this.clonForm).then((resp) => {
if (resp.code === 200) {
this.$message.success('克隆成功')
this.cloneOpen = false
this.getPageList()
}
this.loading.cloneLoading = false
})
}
})
}
},
}
</script>

@ -0,0 +1,130 @@
<template>
<el-dialog title="驾校信息" :close-on-click-modal="false" append-to-body :visible.sync="visible" width="600px" @close="closeDialog">
<div>
<el-form :model="dialogForm" :rules="dataRule" label-position="top" ref="dialogForm" @keyup.enter.native="dialogFormSubmit()">
<el-form-item label="驾校名称" prop="schoolName">
<el-input v-model="dialogForm.schoolName" maxlength="100" placeholder="请输入" clearable></el-input>
</el-form-item>
<el-form-item label="负责人" prop="leader">
<el-input v-model="dialogForm.leader" maxlength="100" placeholder="请输入" clearable></el-input>
</el-form-item>
<el-form-item label="联系方式" prop="phone">
<el-input v-model="dialogForm.phone" maxlength="11" placeholder="请输入" clearable></el-input>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="dialogForm.status">
<el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="dialogForm.remark" maxlength="300" placeholder="请输入" clearable></el-input>
</el-form-item>
</el-form>
</div>
<span slot="footer" class="dialog-footer">
<el-button plain @click="(visible=false)">取消</el-button>
<el-button type="primary" v-jclick :disabled="!canSubmit" @click="dialogFormSubmit()">确定</el-button>
</span>
</el-dialog>
</template>
<script>
import api from '@/api/sch/school';
import { mapGetters } from 'vuex';
export default {
dicts: ['sys_normal_disable'],
props: {
},
computed: {
...mapGetters(['userInfo'])
},
data() {
return {
visible: false,
canSubmit: true,
dialogForm: {
schoolId: undefined,
schoolName: undefined,
leader: undefined,
phone: undefined,
remark: undefined,
status: '0'
},
dataRule: {
schoolName: [{ required: true, message: '驾校名称不能为空', trigger: 'blur' }],
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
}
};
},
created() { },
methods: {
init(info = undefined) {
// debugger
this.visible = true;
this.$nextTick(() => {
this.resetDialogForm();
this.$refs['dialogForm'].resetFields();
if (info) {
this.dialogForm = this.deepClone(info);
}
});
},
resetDialogForm() {
this.dialogForm = {
schoolId: undefined,
schoolName: undefined,
leader: undefined,
phone: undefined,
remark: undefined
}
},
closeDialog() {
this.$emit('update:dialogVisible', false);
},
//
dialogFormSubmit() {
this.$refs.dialogForm.validate((valid) => {
if (valid) {
this.canSubmit = false;
if (this.dialogForm.schoolId) {
//
api
.update(this.dialogForm)
.then((resp) => {
this.canSubmit = true;
if (resp.code == 200) {
this.$message.success('保存成功');
this.$emit('refreshDataList');
this.visible = false;
}
})
.catch(() => {
this.canSubmit = true;
});
} else {
api
.add(this.dialogForm)
.then((resp) => {
this.canSubmit = true;
if (resp.code == 200) {
this.$message.success('保存成功');
this.$emit('refreshDataList');
this.visible = false;
}
})
.catch(() => {
this.canSubmit = true;
});
}
}
})
},
}
};
</script>

@ -0,0 +1,772 @@
<template>
<div class="amap-page-container">
<div id="map" class="amap-cavans" />
<el-input id="search" v-model="searchBody" class="search-body" placeholder="请输入..." @keyup.enter.native="submitSearch">
<el-button slot="append" icon="el-icon-search" @click="submitSearch" />
</el-input>
<div class="asider" :class="showSchool ? '':'hidden-school'">
<el-card class="box-card" :body-style="{ flex: 1,'overflow-y': 'scroll', padding: 0 }">
<div slot="header" class="clearfix">
<div class="map-card-title">驾校列表</div>
</div>
<div v-for="school in schoolList" :key="school.schoolId" style="margin:10px;" :class="currentdeptId == school.schoolId?'actived-school':''">
<el-card :body-style="{ padding: '10px' }">
<div slot="header" class="clearfix">
<div class="map-card-title">{{ school.schoolName }}</div>
<el-switch v-model="school.showInMap" class="add-icon" active-text="展示" inactive-text="隐藏" @change="changeSchoolStatus(school)" v-hasPermi="['sch:place:edit']" />
</div>
<el-button @click="handleClickSchool(school)">{{ `数据管理(${getCount(school.schoolId)})` }}</el-button>
<el-tooltip content="新增场地" placement="left" effect="dark" v-hasPermi="['sch:place:add']">
<el-button icon="el-icon-plus" class="add-place-btn" @click="handleInsertPlace(school.schoolId)" />
</el-tooltip>
</el-card>
</div>
</el-card>
<div class="asider-sub">
<el-tooltip content="放大" placement="left" effect="dark">
<el-button icon="el-icon-plus" class="is-circle" :disabled="zomm >= 18" @click="bigger" />
</el-tooltip>
<el-tooltip content="缩小" placement="left" effect="dark">
<el-button icon="el-icon-minus" class="is-circle" :disabled="zomm <= 8" @click="smaller" />
</el-tooltip>
<div class="mt10">
<el-tooltip content="驾校" placement="left" effect="dark">
<el-button icon="el-icon-school" class="is-circle" @click="toggleSchool" />
</el-tooltip>
<el-tooltip content="定位" placement="left" effect="dark">
<el-button icon="el-icon-help" class="is-circle" @click="geolocation" />
</el-tooltip>
<el-tooltip content="测距" placement="left" effect="dark">
<el-button icon="el-icon-thumb" class="is-circle" @click="ranging" />
</el-tooltip>
<el-tooltip content="分享" placement="left" effect="dark">
<el-button icon="el-icon-share" class="is-circle" />
</el-tooltip>
</div>
</div>
</div>
<el-card v-if="placeDialogShow" class="place-dialog" :body-style="{ padding: '10px' }">
<div slot="header" class="clearfix">
<div class="map-card-title">场地设置</div>
<el-tooltip content="取点" placement="right" effect="dark">
<el-button icon="el-icon-location" class="add-icon" @click="getPoint" />
</el-tooltip>
</div>
<el-form ref="placeForm" :model="placeForm" label-width="70px">
<el-form-item label="所属驾校" prop="schoolId">
<el-select v-model="placeForm.schoolId" placeholder="请选择" clearable>
<el-option v-for="dict in schoolList" :key="dict.schoolId" :label="dict.schoolName" :value="dict.schoolId" />
</el-select>
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="placeForm.name" placeholder="输入名称" />
</el-form-item>
<el-form-item label="旗子颜色" prop="flagColor">
<el-radio-group v-model="placeForm.flagColor">
<el-radio v-for="(item, index) in colorOptions" :key="index" :label="item">
<img :src="require(`@/assets/images/place/flag_${item}.png`)" width="20px" />
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input v-model="placeForm.address" placeholder="输入地址" />
</el-form-item>
<el-form-item label="经度" prop="lng">
<el-input v-model="placeForm.lng" placeholder="输入经度" />
</el-form-item>
<el-form-item label="纬度" prop="lat">
<el-input v-model="placeForm.lat" placeholder="输入纬度" />
</el-form-item>
<el-form-item label="所属区域" prop="area">
<el-select v-model="placeForm.area" placeholder="请选择" clearable size="small">
<el-option v-for="dict in areaOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
</el-select>
</el-form-item>
<el-form-item label="电话" prop="phone">
<el-input v-model="placeForm.phone" placeholder="输入电话" />
</el-form-item>
<el-form-item label="负责人" prop="contact">
<el-input v-model="placeForm.contact" placeholder="输入负责人" />
</el-form-item>
<el-form-item label="是否推荐" prop="contact">
<el-radio v-model="placeForm.recommend" :label="true"></el-radio>
<el-radio v-model="placeForm.recommend" :label="false"></el-radio>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="placeForm.remark" placeholder="输入备注" type="textarea" :autosize="{ minRows: 2, maxRows: 4}" />
</el-form-item>
<el-form-item style="text-align:right;">
<el-button type="primary" @click="onSubmit" v-hasPermi="['sch:place:edit']">保存</el-button>
<el-button @click="closePlaceDialog">取消</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card :class="placeListDialogShow ? '':'hidden-place-list'" class="place-list-dialog" :style="{ right: showSchool ? '300px' : '0', top : fullScreenPlaceList?'0px':'420px' }" :body-style="{ padding: '10px', height: 'calc(100% - 52px)' }">
<div slot="header" class="clearfix">
<div class="map-card-title">
{{ placeListDialogTitle }}
<el-input v-model="tableSearch" placeholder="请输入搜索的内容" clearable />
</div>
<el-tooltip content="全屏" placement="top" effect="dark">
<el-button icon="el-icon-full-screen" class="add-icon" @click="fullScreenPlaceList = !fullScreenPlaceList" />
</el-tooltip>
<el-tooltip content="关闭" placement="top" effect="dark">
<el-button icon="el-icon-close" class="add-icon" @click="() => { placeListDialogShow = false;fullScreenPlaceList = false }" />
</el-tooltip>
</div>
<el-table :data="placeTableData" border stripe class="place-table-list" height="100%">
<el-table-column label="序号" type="index" fixed="left" width="50" />
<el-table-column prop="name" label="名称" min-width="100" />
<el-table-column prop="phone" label="电话" width="120" />
<el-table-column prop="contact" label="负责人" width="120" />
<el-table-column prop="address" label="地址" min-width="100" />
<el-table-column prop="lng" label="经度" width="110" />
<el-table-column prop="lat" label="纬度" width="110" />
<el-table-column prop="area" label="所属区域" width="110" />
<el-table-column label="展示" width="100">
<template slot-scope="scope">
<el-switch v-model="scope.row.showInMap" @change="changePlaceStatus(scope.row)" v-hasPermi="['sch:place:edit']" />
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template slot-scope="scope">
<el-tooltip content="编辑" placement="top" effect="dark" v-hasPermi="['sch:place:edit']">
<el-button icon="el-icon-edit" type="primary" style="padding: 4px 8px;" @click="handleEditPlace(scope.row)" />
</el-tooltip>
</template>
</el-table-column>
</el-table>
</el-card>
<div v-if="isPointing || isRanging" class="map-tip" :style="{ transform: 'translate3D(' + (tipPostion.x + 15) +'px,' + (tipPostion.y - 10) + 'px, 0)' }">{{ mapHelpText }}</div>
<i v-if="isPointing" class="el-icon-s-flag circle" :style="{ transform: 'translate3D(' + tipPostion.x +'px,' + tipPostion.y + 'px, 0)' }" />
</div>
</template>
<script>
import { getMapData, savePlace, updateSchoolStatus } from '@/api/sch/place'
export default {
name: 'Place',
data() {
return {
aMap: null,
zomm: 12,
showSchool: true,
isRanging: false,
aMapLocation: null,
aMouseTool: null,
searchBody: '',
placeSearch: null,
placeDialogShow: false,
isPointing: false,
placeForm: {
lat: undefined,
lng: undefined,
name: undefined,
address: undefined,
remark: undefined,
phone: undefined,
flagColor: 'red',
},
colorOptions: ['red', 'yellow', 'blue', 'green', 'purple', 'black'],
mapHelpText: '',
tipPostion: {
x: 0,
y: 0,
},
geocoder: null,
locationMarker: null,
selectMarker: null,
placeListDialogShow: false,
placeListDialogTitle: '',
fullScreenPlaceList: false,
tableSearch: '',
tableData: [],
schoolList: [],
currentdeptId: undefined,
placeMarkerList: [],
areaOptions: [],
}
},
computed: {
placeTableData: function () {
if (this.tableSearch) {
return this.tableData.filter((dataNews) => {
return (
dataNews.schoolId === this.currentdeptId &&
Object.keys(dataNews).some((key) => {
return (
String(dataNews[key]).toLowerCase().indexOf(this.tableSearch) >
-1
)
})
)
})
}
return this.tableData.filter(
(dataNews) => dataNews.schoolId === this.currentdeptId
)
},
},
mounted() {
this.initMap()
this.getDicts('dm_area').then((response) => {
this.areaOptions = response.data
})
},
methods: {
initMap() {
window.onLoad = () => {
this.aMap = new AMap.Map('map', {
zoom: this.zomm,
zooms: [8, 18],
})
//
this.aMap.on('zoomend', () => {
this.zomm = this.aMap.getZoom()
this.$message('当前缩放等级:' + this.zomm)
})
//
this.aMap.on('click', (ev) => {
if (this.isPointing) {
this.placeForm.lat = ev.lnglat.lat
this.placeForm.lng = ev.lnglat.lng
this.regeoCode()
if (this.selectMarker) {
this.selectMarker.setPosition([
this.placeForm.lng,
this.placeForm.lat,
])
} else {
this.locationMarker.setPosition([
this.placeForm.lng,
this.placeForm.lat,
])
this.aMap.add(this.locationMarker)
}
this.isPointing = false
}
})
//
this.aMap.on('mousemove', (ev) => {
if (this.isRanging) {
this.mapHelpText =
'左键单击选点,双击/右键单击完成选点,再次点击测距按钮可退出测距模式,并清除测距结果'
this.tipPostion = {
x: ev.pixel.x,
y: ev.pixel.y,
}
} else if (this.isPointing) {
this.mapHelpText = '点击地图添加标注'
this.tipPostion = {
x: ev.pixel.x,
y: ev.pixel.y,
}
}
})
//
AMap.plugin(
[
'AMap.Scale',
'AMap.Geolocation',
'AMap.MouseTool',
'AMap.PlaceSearch',
'AMap.Autocomplete',
'AMap.Geocoder',
],
() => {
this.aMap.addControl(new AMap.Scale())
const geoLoca = new AMap.Geolocation({
showButton: false,
})
this.aMapLocation = geoLoca
this.aMap.addControl(geoLoca)
this.aMouseTool = new AMap.MouseTool(this.aMap)
const auto = new AMap.Autocomplete({
input: 'search', //
})
this.placeSearch = new AMap.PlaceSearch({
map: this.aMap,
})
AMap.event.addListener(auto, 'select', this.select)
this.geocoder = new AMap.Geocoder()
this.locationMarker = new AMap.Marker({
icon: require(`@/assets/images/place/flag_red.png`),
})
}
)
this.getPageData()
}
this.importMap()
},
//
importMap() {
const url =
'https://webapi.amap.com/maps?v=1.4.15&key=124646b0e6076de9d801400f833ac986&callback=onLoad'
var jsapi = document.createElement('script')
jsapi.charset = 'utf-8'
jsapi.src = url
document.head.appendChild(jsapi)
},
toggleSchool() {
this.showSchool = !this.showSchool
},
// ->
regeoCode() {
this.geocoder.getAddress(
[this.placeForm.lng, this.placeForm.lat],
(status, result) => {
if (status === 'complete' && result.regeocode) {
this.placeForm.address = result.regeocode.formattedAddress
} else {
console.log('根据经纬度查询地址失败')
}
}
)
},
//
geolocation() {
this.aMapLocation.getCurrentPosition()
},
//
ranging() {
this.isPointing = false
this.isRanging = !this.isRanging
if (this.isRanging) {
this.aMap.setDefaultCursor('crosshair')
this.drawLine()
} else {
this.aMap.setDefaultCursor('default')
this.aMouseTool.close(true)
}
},
// 线
drawLine() {
this.aMouseTool.rule({
startMarkerOptions: {
//
icon: new AMap.Icon({
size: new AMap.Size(19, 31), //
imageSize: new AMap.Size(19, 31),
image: 'https://webapi.amap.com/theme/v1.3/markers/b/start.png',
}),
},
endMarkerOptions: {
//
icon: new AMap.Icon({
size: new AMap.Size(19, 31), //
imageSize: new AMap.Size(19, 31),
image: 'https://webapi.amap.com/theme/v1.3/markers/b/end.png',
}),
offset: new AMap.Pixel(-9, -31),
},
midMarkerOptions: {
//
icon: new AMap.Icon({
size: new AMap.Size(19, 31), //
imageSize: new AMap.Size(19, 31),
image: 'https://webapi.amap.com/theme/v1.3/markers/b/mid.png',
}),
offset: new AMap.Pixel(-9, -31),
},
lineOptions: {
//
strokeStyle: 'solid',
strokeColor: '#FF33FF',
strokeOpacity: 1,
strokeWeight: 2,
},
tmpLineOptions: {
strokeStyle: 'dashed',
strokeColor: '#FF33FF',
strokeOpacity: 1,
strokeWeight: 2,
},
})
},
//
select(e) {
this.placeSearch.setCity(e.poi.adcode)
this.placeSearch.search(e.poi.name) //
},
// /
submitSearch() {
this.placeSearch.search(this.searchBody)
},
//
bigger() {
this.zomm++
this.aMap.setZoom(this.zomm)
},
smaller() {
this.zomm--
this.aMap.setZoom(this.zomm)
},
//
handleClickSchool(item) {
this.placeListDialogShow = true
this.placeListDialogTitle = `数据管理 [${item.schoolName}]`
this.currentdeptId = item.schoolId
},
//
handleInsertPlace(schoolId) {
if (this.selectMarker) {
this.selectMarker.setAnimation('AMAP_ANIMATION_NONE')
this.selectMarker = null
}
this.placeDialogShow = true
this.aMap.setDefaultCursor('default')
this.isRanging = false
this.placeForm = {
lat: undefined,
lng: undefined,
name: undefined,
address: undefined,
remark: undefined,
phone: undefined,
schoolId: schoolId,
showInMap: true,
flagColor: 'red',
}
},
//
handleEditPlace(item) {
this.placeDialogShow = true
this.aMap.setDefaultCursor('default')
if (this.selectMarker) {
this.selectMarker.setAnimation('AMAP_ANIMATION_NONE')
}
this.isRanging = false
this.placeForm = Object.assign({}, item)
this.selectMarker = this.placeMarkerList.filter(
(marker) => marker.getExtData().placeId === item.placeId
)[0]
this.selectMarker &&
this.selectMarker.setAnimation('AMAP_ANIMATION_BOUNCE')
this.aMap.setCenter([item.lng, item.lat])
},
getPoint() {
this.isPointing = !this.isPointing
},
//
async onSubmit() {
//
if (this.checkPlaceFormValidate()) {
// 访idplaceForm
const resp = await savePlace(this.placeForm)
if (resp.code != 200) {
return
} else {
this.$message.success('操作成功');
}
if (!this.placeForm.placeId && resp.data) {
this.$set(this.placeForm, 'placeId', resp.data)
}
//
this.aMap.remove(this.locationMarker)
// formmarker
const tmpMarker = new AMap.Marker({
map: this.aMap,
position: [this.placeForm.lng, this.placeForm.lat],
icon: require(`@/assets/images/place/flag_${this.placeForm.flagColor}.png`),
label: {
content: this.placeForm.name,
direction: 'right',
},
extData: this.placeForm,
})
// marker
tmpMarker.on('click', this.handleClickMarker)
// marker
if (this.selectMarker) {
//
this.aMap.remove(this.selectMarker)
this.selectMarker = null
}
//
this.placeDialogShow = false
this.isPointing = false
//
const tmpArr = this.tableData.filter(
(item) => item.placeId !== this.placeForm.placeId
)
//
tmpArr.push(this.placeForm)
//
this.tableData = tmpArr
// marker marker marker
const tmpArr1 = this.placeMarkerList.filter(
(item) => item.getExtData().placeId !== this.placeForm.placeId
)
tmpArr1.push(tmpMarker)
this.placeMarkerList = tmpArr1
}
},
checkPlaceFormValidate() {
const valid = []
if (!this.placeForm.name) {
valid.push('名称')
}
if (!this.placeForm.address) {
valid.push('地址')
}
if (!this.placeForm.lng) {
valid.push('经度')
}
if (!this.placeForm.lat) {
valid.push('纬度')
}
if (!this.placeForm.phone) {
valid.push('电话')
}
if (valid.length == 0) {
return true
} else {
this.$message.error(`请将以下填写完整: ${valid.join(',')}`)
return false
}
},
//
closePlaceDialog() {
this.placeDialogShow = false
this.isPointing = false
this.aMap.remove(this.locationMarker)
if (this.selectMarker) {
this.selectMarker.setAnimation('AMAP_ANIMATION_NONE')
this.selectMarker = null
}
},
handleClickMarker(ev) {
if (this.selectMarker) {
this.selectMarker.setAnimation('AMAP_ANIMATION_NONE')
}
this.placeForm = ev.target.getExtData()
this.placeDialogShow = true
ev.target.setAnimation('AMAP_ANIMATION_BOUNCE')
this.selectMarker = ev.target
},
getPageData() {
getMapData().then((resp) => {
if (resp.code == 200) {
this.schoolList = resp.data.schoolList
this.tableData = resp.data.placeList
this.currentdeptId = this.schoolList[0].schoolId
this.createMarkersInMap()
}
})
},
getCount(schoolId) {
return this.tableData.filter((item) => item.schoolId === schoolId).length
},
// markers
resetMarkers() {
this.aMap.clearMap()
this.createMarkersInMap()
},
// markers
createMarkersInMap() {
for (let i = 0; i < this.tableData.length; i++) {
const element = this.tableData[i]
const tempSchool = this.schoolList.filter(
(item) => item.schoolId === element.schoolId
)[0]
if (!tempSchool.showInMap || !element.showInMap) {
continue
}
const tmpMarker = new AMap.Marker({
map: this.aMap,
position: [element.lng, element.lat],
icon: require(`@/assets/images/place/flag_${element.flagColor}.png`),
label: {
content: element.name,
direction: 'right',
},
extData: element,
})
tmpMarker.on('click', this.handleClickMarker)
this.placeMarkerList.push(tmpMarker)
}
},
//
changeSchoolStatus(item) {
// 访markers
updateSchoolStatus(item).then((resp) => {
if (resp.code == 200) {
this.$message.success('操作成功');
// this.aMap.clearMap()
// this.getPageData()
this.resetMarkers()
}
})
},
//
async changePlaceStatus(item) {
const resp = await savePlace(item)
if (resp.code == 200) {
this.resetMarkers()
}
},
},
}
</script>
<style scoped>
.amap-page-container {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.amap-cavans {
width: 100%;
height: 100%;
}
.asider {
position: absolute;
right: 0;
top: 0;
width: 300px;
height: 100%;
transition: 0.3s;
z-index: 9;
}
.box-card {
display: flex;
flex-direction: column;
height: 100%;
}
/deep/ .el-card__header {
padding: 10px 15px;
}
.clearfix {
display: flex;
}
.clearfix .map-card-title {
flex: 1;
line-height: 30px;
}
.clearfix .add-icon {
width: auto;
height: 30px;
}
.asider-sub {
position: absolute;
top: 40px;
left: -45px;
padding: 10px 10px 0 0;
z-index: 900;
}
.asider-sub .is-circle {
display: block;
margin: 0;
padding: 10px;
color: #464646;
border-radius: 0;
font-size: 16px;
box-shadow: 2px 2px 2px rgba(80, 80, 80, 0.67);
}
.mt10 {
margin-top: 10px;
}
.hidden-school {
transform: translateX(300px);
}
.search-body {
position: absolute;
top: 20px;
left: 20px;
width: 400px;
}
.add-place-btn {
float: right;
border: none;
font-size: 16px;
color: #409eff;
}
/deep/.place-dialog {
position: absolute;
left: 20px;
top: 60px;
width: 350px;
}
.map-tip {
position: absolute;
left: 0;
top: 0;
max-width: 150px;
padding: 5px;
border-radius: 2px;
background: #000;
color: #fff;
opacity: 0.7;
font-size: 12px;
transition-duration: 1ms;
}
.circle {
position: absolute;
left: -8px;
top: -25px;
font-size: 24px;
color: red;
transition-duration: 1ms;
}
.place-dialog .el-form .el-form-item {
margin-bottom: 8px;
}
.place-list-dialog {
position: absolute;
top: 420px;
left: 0;
bottom: 0;
transition: 0.3s;
z-index: 151;
background: #e2e5ea;
}
.place-list-dialog .add-icon {
font-size: 18px;
border: none;
}
.hidden-place-list {
transform: translateY(100%);
}
.place-list-dialog .clearfix .map-card-title {
font-weight: bold;
}
.place-list-dialog .clearfix .map-card-title .el-input {
margin-left: 20px;
width: 240px;
}
.actived-school {
border: 2px solid #409eff !important;
}
/deep/ .el-radio__label {
vertical-align: middle;
}
</style>

@ -0,0 +1,121 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<el-form ref="queryForm" :model="queryParams" :inline="true">
<el-form-item>
<el-input v-model="queryParams.schoolName" placeholder="请输入驾校名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
<el-button type="primary" icon="el-icon-plus" @click="addOrUpdateHandle(undefined)" v-hasPermi="['sch:school:add']">新增</el-button>
<!-- <el-button type="danger" icon="el-icon-delete" @click="handleDelete" :disabled="multiple" v-hasPermi="['sch:school:remove']">删除</el-button> -->
</el-form-item>
</el-form>
</el-row>
<el-table v-loading="loading.tableLoading" :data="tableDataList" stripe>
<!-- <el-table-column type="selection" width="50" align="center" /> -->
<el-table-column label="序号" type="index" width="50" />
<el-table-column label="驾校名称" prop="schoolName" />
<el-table-column label="负责人" prop="leader" />
<el-table-column label="联系方式" prop="phone" />
<el-table-column label="备注" prop="remark" />
<el-table-column label="创建时间" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="130">
<template slot-scope="scope">
<el-button v-hasPermi="['sch:school:edit']" type="text" icon="el-icon-edit" @click="addOrUpdateHandle(scope.row)">修改</el-button>
<el-button v-hasPermi="['sch:school:remove']" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getPageList" />
<!-- 驾校弹框 -->
<school-form v-if="dialogVisible" :dialogVisible="dialogVisible" ref="dialogForm" @refreshDataList="getPageList" />
</div>
</template>
<script>
import schoolForm from './components/schoolForm.vue'
import schoolApi from '@/api/sch/school'
import { appendFile } from 'fs'
export default {
name: 'School',
components: {
schoolForm
},
data() {
return {
total: 0,
queryParams: {
schoolName: undefined,
pageNum: 1,
pageSize: 10
},
tableDataList: [],
loading: {
tableLoading: false
},
dialogVisible: false,
}
},
created() {
//
this.getPageList()
},
methods: {
//
getPageList() {
schoolApi.pageList(this.queryParams).then(resp => {
if (resp.code == 200) {
this.tableDataList = resp.rows
this.total = resp.total
}
})
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getPageList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.queryParams = {
schoolName: undefined,
pageNum: 1,
pageSize: 10
},
this.handleQuery();
},
//
addOrUpdateHandle(item) {
this.dialogVisible = true;
this.$nextTick(() => {
this.$refs.dialogForm.init(item);
});
},
//
handleDelete(item) {
this.$modal.confirm('删除驾校信息,同时会删除该驾校下的场地信息和班型信息,是否确认名称为"' + item.schoolName + '"的数据项?').then(function () {
return schoolApi.delete(item.schoolId);
}).then((resp) => {
if (resp.code == 200) {
this.getPageList();
this.$modal.msgSuccess("删除成功");
}
}).catch(() => { });
},
},
}
</script>

@ -0,0 +1,491 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<!--部门数据-->
<el-col :span="4" :xs="24">
<div class="head-container">
<el-input v-model="deptName" placeholder="请输入部门名称" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px" />
</div>
<div class="head-container">
<el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode" ref="tree" default-expand-all highlight-current @node-click="handleNodeClick" />
</div>
</el-col>
<!--用户数据-->
<el-col :span="20" :xs="24">
<el-form ref="queryForm" :model="queryParams" :inline="true" label-width="68px">
<el-form-item prop="userOrPhone">
<el-input v-model="queryParams.employeeName" placeholder="请输入姓名/手机号" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item prop="status">
<el-select v-model="queryParams.status" placeholder="用户状态" clearable>
<el-option v-for="dict in statusOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
</el-select>
</el-form-item>
<el-form-item label="入职时间">
<el-date-picker v-model="queryParams.hiredate" style="width: 240px" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
<el-button v-hasPermi="['system:employee:add']" type="primary" icon="el-icon-plus" @click="handleAdd">新增</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="userList">
<el-table-column label="姓名" prop="employeeName" />
<el-table-column label="手机号" prop="phone" />
<el-table-column label="部门" prop="orgName" />
<el-table-column label="上级领导" prop="leaderName" />
<el-table-column label="入职时间" prop="hiredate" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.hiredate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="260">
<template slot-scope="scope">
<el-button v-hasPermi="['system:employee:edit']" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
<!-- <el-button
v-hasPermi="['system:employee:resetPwd']"
type="text"
icon="el-icon-key"
@click="handleReset(scope.row)"
>重置密码</el-button>-->
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
</el-col>
</el-row>
<!-- 添加或修改参数配置对话框 -->
<el-dialog :title="title" :visible.sync="open" width="700px" custom-class="dialog500" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="12">
<el-form-item label="姓名" prop="employeeName">
<el-input v-model="form.employeeName" placeholder="请输入员工姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手机号" prop="phone">
<el-input v-model="form.phone" placeholder="请输入手机号码" maxlength="11" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="角色" prop="roleIdList">
<el-select v-model="form.roleIdList" multiple placeholder="请选择">
<el-option v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" :disabled="item.status == 1" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="归属部门" prop="orgId">
<treeselect v-model="form.orgId" :options="deptOptions" :disable-branch-nodes="true" :show-count="true" placeholder="请选择归属部门" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="所属区域" prop="areaList">
<el-select v-model="form.areaList" multiple placeholder="请选择">
<el-option v-for="dict in areaOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="权重" prop="weight">
<el-input v-model="form.weight" placeholder="权重,1-100" type="number"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="用户性别">
<el-select v-model="form.sex" placeholder="请选择">
<el-option v-for="dict in sexOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="入职日期">
<el-date-picker v-model="form.hiredate" :editable="false" type="date" value-format="yyyy-MM-dd" placeholder="请选择入职时间" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="上级领导">
<el-select v-model="form.leader" placeholder="请选择">
<el-option v-for="dict in userOptions" :key="dict.id" :label="dict.name" :value="dict.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in statusOptions" :key="dict.dictValue" :label="dict.dictValue">{{ dict.dictLabel }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="是否释放线索">
<el-radio-group v-model="form.discardClue">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最大线索数">
<el-input v-model="form.maxClueNum"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="是否考勤">
<el-radio-group v-model="form.checkin">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否参与统计">
<el-radio-group v-model="form.count">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<!-- <el-row>
<el-col :span="12">
<el-form-item label="小程序权限">
<el-radio-group v-model="form.hasStudent">
<el-radio :label="true">开通</el-radio>
<el-radio :label="false">关闭</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="管理系统权限">
<el-radio-group v-model="form.hasSys">
<el-radio :label="true">开通</el-radio>
<el-radio :label="false">关闭</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row> -->
<el-row>
<el-col :span="24">
<el-form-item label="备注">
<!-- <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input> -->
<editor v-model="form.remark" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import empAPi from '@/api/system/employee'
import { deptTreeSelect } from "@/api/system/dept";
import { getRoleOptions } from '@/api/system/role'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import editor from '@/components/Editor'
export default {
name: 'Employee',
components: { Treeselect, editor },
data() {
return {
//
loading: true,
userId: localStorage.getItem('userId'),
//
total: 0,
//
userList: null,
//
title: '',
//
deptOptions: undefined,
//
open: false,
//
deptName: undefined,
//
initPassword: undefined,
//
statusOptions: [],
//
sexOptions: [],
//
roleOptions: [],
//
form: {},
defaultProps: {
children: 'children',
label: 'label',
},
//
queryParams: {
pageNum: 1,
pageSize: 10,
nameOrPhone: undefined,
status: '0',
orgId: undefined,
roleId: undefined,
hiredate: [],
},
//
rules: {
employeeName: [
{ required: true, message: '姓名不能为空', trigger: 'blur' },
],
roleIdList: [
{
required: true,
type: 'array',
message: '角色不能为空',
trigger: 'blur,change',
},
],
orgId: [
{
required: true,
message: '归属部门不能为空',
trigger: 'blur,change',
},
],
areaList: [
{
required: true,
message: '所属区域不能为空',
trigger: 'blur,change',
},
],
weight: [
{
required: true,
message: '权重不能为空',
trigger: 'blur,change',
},
],
phone: [
{ required: true, message: '手机号码不能为空', trigger: 'blur' },
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: '请输入正确的手机号码',
trigger: 'blur',
},
],
},
userOptions: [],
areaOptions: [],
}
},
watch: {
//
deptName(val) {
this.$refs.tree.filter(val)
},
},
created() {
this.getList()
this.getDeptTree();
this._getRoleOptions()
this.getDicts('sys_normal_disable').then((response) => {
this.statusOptions = response.data
})
this.getDicts('sys_user_sex').then((response) => {
this.sexOptions = response.data
})
this.getDicts('dm_area').then((response) => {
this.areaOptions = response.data
})
this.getConfigKey('sys.user.initPassword').then((response) => {
this.initPassword = response.msg
})
empAPi.getEmployee().then((resp) => {
if (resp.code === 200) {
this.userOptions = resp.data
// this.userOptions.push({
// id: '6ce3239c8c154f83befb9eb7441a01c7',
// name: 'DM',
// })
}
})
},
methods: {
/** 查询用户列表 */
getList() {
this.loading = true
empAPi.pageList(this.queryParams).then(
(response) => {
this.userList = response.rows
this.total = response.total
this.loading = false
}
)
},
_getRoleOptions() {
getRoleOptions().then((resp) => {
this.roleOptions = resp.data
})
},
/** 查询部门下拉树结构 */
getDeptTree() {
deptTreeSelect().then(response => {
this.deptOptions = response.data;
});
},
//
filterNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
//
handleNodeClick(data) {
this.queryParams.orgId = data.id
this.getList()
},
//
handleStatusChange(row) {
const text = row.status === '0' ? '启用' : '停用'
this.$confirm(
'确认要"' + text + '""' + row.userName + '"用户吗?',
'警告',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(function () {
let model = {
employeeId: row.employeeId,
status: row.status
}
return empAPi.update(model)
})
.then(() => {
this.msgSuccess(text + '成功')
})
.catch(function () {
row.status = row.status === '0' ? '1' : '0'
})
},
//
cancel() {
this.open = false
this.reset()
},
//
reset() {
this.form = {
orgId: undefined,
employeeName: undefined,
phone: undefined,
sex: '0',
status: '0',
remark: undefined,
roleIdList: [],
hiredate: undefined,
leader: this.userId,
discardClue: false,
maxPublicClue: undefined,
checkin: true,
areaList: [],
weight: undefined,
count: true
}
this.resetForm('form')
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.page = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm')
this.handleQuery()
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.getDeptTree();
this.open = true
this.title = '添加员工'
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
this.getDeptTree();
this.form = Object.assign({}, row)
this.open = true
this.title = '修改员工'
},
/** 重置密码按钮操作 */
handleReset(row) {
resetUserPwd({ employeeId: row.employeeId }).then((response) => {
if (response.code === 200) {
this.msgSuccess('重置密码成功!')
}
})
},
/** 提交按钮 */
submitForm: function () {
this.$refs['form'].validate((valid) => {
if (valid) {
this.$set(this.form, 'deptId', this.$store.getters.schoolId)
if (this.form.employeeId) {
empAPi.update(this.form).then((response) => {
if (response.code === 200) {
this.$message.success('修改成功');
this.open = false
this.getList()
}
})
} else {
empAPi.add(this.form).then((response) => {
if (response.code === 200) {
this.$message.success('新增成功');
this.open = false
this.getList()
}
})
}
}
})
},
},
}
</script>
<style>
.el-dropdown-link {
cursor: pointer;
color: #409eff;
}
.el-icon-arrow-down {
font-size: 12px;
}
</style>

@ -2,48 +2,18 @@
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
<el-form-item label="角色名称" prop="roleName">
<el-input
v-model="queryParams.roleName"
placeholder="请输入角色名称"
clearable
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
<el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="权限字符" prop="roleKey">
<el-input
v-model="queryParams.roleKey"
placeholder="请输入权限字符"
clearable
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
<el-input v-model="queryParams.roleKey" placeholder="请输入权限字符" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="角色状态"
clearable
style="width: 240px"
>
<el-option
v-for="dict in dict.type.sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
<el-select v-model="queryParams.status" placeholder="角色状态" clearable style="width: 240px">
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="dateRange"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
@ -53,46 +23,16 @@
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:role:add']"
>新增</el-button>
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:role:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:role:edit']"
>修改</el-button>
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['system:role:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:role:remove']"
>删除</el-button>
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:role:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:role:export']"
>导出</el-button>
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['system:role:export']">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@ -105,12 +45,7 @@
<el-table-column label="显示顺序" prop="roleSort" width="100" />
<el-table-column label="状态" align="center" width="100">
<template slot-scope="scope">
<el-switch
v-model="scope.row.status"
active-value="0"
inactive-value="1"
@change="handleStatusChange(scope.row)"
></el-switch>
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
@ -119,43 +54,23 @@
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope" v-if="scope.row.roleId !== 1">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:role:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:role:remove']"
>删除</el-button>
<el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['system:role:edit']">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:role:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['system:role:remove']">删除</el-button>
<!-- <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['system:role:edit']">
<span class="el-dropdown-link">
<i class="el-icon-d-arrow-right el-icon--right"></i>更多
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="handleDataScope" icon="el-icon-circle-check"
v-hasPermi="['system:role:edit']">数据权限</el-dropdown-item>
<el-dropdown-item command="handleAuthUser" icon="el-icon-user"
v-hasPermi="['system:role:edit']">分配用户</el-dropdown-item>
<el-dropdown-item command="handleDataScope" icon="el-icon-circle-check" v-hasPermi="['system:role:edit']">数据权限</el-dropdown-item>
<el-dropdown-item command="handleAuthUser" icon="el-icon-user" v-hasPermi="['system:role:edit']">分配用户</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-dropdown> -->
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
<!-- 添加或修改角色配置对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
@ -177,27 +92,14 @@
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in dict.type.sys_normal_disable"
:key="dict.value"
:label="dict.value"
>{{dict.label}}</el-radio>
<el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="菜单权限">
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
<el-tree
class="tree-border"
:data="menuOptions"
show-checkbox
ref="menu"
node-key="id"
:check-strictly="!form.menuCheckStrictly"
empty-text="加载中,请稍候"
:props="defaultProps"
></el-tree>
<el-tree class="tree-border" :data="menuOptions" show-checkbox ref="menu" node-key="id" :check-strictly="!form.menuCheckStrictly" empty-text="加载中请稍候" :props="defaultProps"></el-tree>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
@ -220,29 +122,14 @@
</el-form-item>
<el-form-item label="权限范围">
<el-select v-model="form.dataScope" @change="dataScopeSelectChange">
<el-option
v-for="item in dataScopeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
<el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="数据权限" v-show="form.dataScope == 2">
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
<el-tree
class="tree-border"
:data="deptOptions"
show-checkbox
default-expand-all
ref="dept"
node-key="id"
:check-strictly="!form.deptCheckStrictly"
empty-text="加载中,请稍候"
:props="defaultProps"
></el-tree>
<el-tree class="tree-border" :data="deptOptions" show-checkbox default-expand-all ref="dept" node-key="id" :check-strictly="!form.deptCheckStrictly" empty-text="加载中请稍候" :props="defaultProps"></el-tree>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">

@ -4,74 +4,28 @@
<!--部门数据-->
<el-col :span="4" :xs="24">
<div class="head-container">
<el-input
v-model="deptName"
placeholder="请输入部门名称"
clearable
size="small"
prefix-icon="el-icon-search"
style="margin-bottom: 20px"
/>
<el-input v-model="deptName" placeholder="请输入部门名称" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px" />
</div>
<div class="head-container">
<el-tree
:data="deptOptions"
:props="defaultProps"
:expand-on-click-node="false"
:filter-node-method="filterNode"
ref="tree"
default-expand-all
highlight-current
@node-click="handleNodeClick"
/>
<el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode" ref="tree" default-expand-all highlight-current @node-click="handleNodeClick" />
</div>
</el-col>
<!--用户数据-->
<el-col :span="20" :xs="24">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input
v-model="queryParams.phonenumber"
placeholder="请输入手机号码"
clearable
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="用户状态"
clearable
style="width: 240px"
>
<el-option
v-for="dict in dict.type.sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="dateRange"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
@ -81,56 +35,19 @@
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:user:add']"
>新增</el-button>
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:user:edit']"
>修改</el-button>
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['system:user:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:user:remove']"
>删除</el-button>
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-upload2"
size="mini"
@click="handleImport"
v-hasPermi="['system:user:import']"
>导入</el-button>
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:user:export']"
>导出</el-button>
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row>
@ -144,12 +61,7 @@
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
<el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
<template slot-scope="scope">
<el-switch
v-model="scope.row.status"
active-value="0"
inactive-value="1"
@change="handleStatusChange(scope.row)"
></el-switch>
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
@ -157,49 +69,24 @@
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
width="160"
class-name="small-padding fixed-width"
>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope" v-if="scope.row.userId !== 1">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:user:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:user:remove']"
>删除</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']">删除</el-button>
<el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['system:user:resetPwd', 'system:user:edit']">
<span class="el-dropdown-link">
<i class="el-icon-d-arrow-right el-icon--right"></i>更多
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="handleResetPwd" icon="el-icon-key"
v-hasPermi="['system:user:resetPwd']">重置密码</el-dropdown-item>
<el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check"
v-hasPermi="['system:user:edit']">分配角色</el-dropdown-item>
<el-dropdown-item command="handleResetPwd" icon="el-icon-key" v-hasPermi="['system:user:resetPwd']">重置密码</el-dropdown-item>
<el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check" v-hasPermi="['system:user:edit']">分配角色</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
</el-col>
</el-row>
@ -246,51 +133,34 @@
<el-col :span="12">
<el-form-item label="用户性别">
<el-select v-model="form.sex" placeholder="请选择性别">
<el-option
v-for="dict in dict.type.sys_user_sex"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
<el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in dict.type.sys_normal_disable"
:key="dict.value"
:label="dict.value"
>{{dict.label}}</el-radio>
<el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="岗位">
<el-select v-model="form.postIds" multiple placeholder="请选择岗位">
<el-option
v-for="item in postOptions"
:key="item.postId"
:label="item.postName"
:value="item.postId"
:disabled="item.status == 1"
></el-option>
</el-select>
<el-form-item label="是否管理员">
<el-radio-group v-model="form.admin">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
<!-- <el-select v-model="form.postIds" multiple placeholder="请选择岗位">
<el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId" :disabled="item.status == 1"></el-option>
</el-select> -->
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="角色">
<el-select v-model="form.roleIds" multiple placeholder="请选择角色">
<el-option
v-for="item in roleOptions"
:key="item.roleId"
:label="item.roleName"
:value="item.roleId"
:disabled="item.status == 1"
></el-option>
<el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == 1"></el-option>
</el-select>
</el-form-item>
</el-col>
@ -311,18 +181,7 @@
<!-- 用户导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload
ref="upload"
:limit="1"
accept=".xlsx, .xls"
:headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport"
:disabled="upload.isUploading"
:on-progress="handleFileUploadProgress"
:on-success="handleFileSuccess"
:auto-upload="false"
drag
>
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
@ -342,7 +201,8 @@
</template>
<script>
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user";
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus } from "@/api/system/user";
import { deptTreeSelect } from "@/api/system/dept";
import { getToken } from "@/utils/auth";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
@ -523,7 +383,8 @@ export default {
status: "0",
remark: undefined,
postIds: [],
roleIds: []
roleIds: [],
admin: false
};
this.resetForm("form");
},

@ -0,0 +1,784 @@
<template>
<div class="app-container">
<el-row>
<el-form ref="queryForm" :model="queryParams" inline>
<el-row>
<el-form-item>
<el-input v-model="queryParams.name" placeholder="姓名/联系方式" clearable style="width: 200px" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-select v-model="queryParams.source" placeholder="选择线索来源" clearable @change="handleQuery">
<el-option v-for="dict in sourceOptions" :key="dict.dictValue" :value="dict.dictValue" />
</el-select>
</el-form-item>
<el-form-item>
<el-select v-model="queryParams.intentionState" placeholder="选择意向状态" clearable @change="handleQuery">
<el-option v-for="dict in intentionOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue">
<i class="el-icon-star-on" :style="dict.cssClass" />
<span style="float: right; color: #8492a6; font-size: 13px">{{ dict.dictValue }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-select v-model="queryParams.followUser2" placeholder="选择跟进人员" filterable clearable @change="handleQuery">
<el-option v-for="dict in userOptions" :key="dict.id" :label="dict.name" :value="dict.id" />
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker v-model="queryParams.createTime" style="width: 240px" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="handleQuery" />
</el-form-item>
</el-row>
<el-row>
<el-form-item label-width="80">
<template slot="label">
<el-button type="text" @click="handleFilter">筛选</el-button>
</template>
<el-checkbox-group v-model="queryParams.etc" @change="etcChange">
<el-checkbox v-if="filterItems.myCreate" label="myCreate">我创建的</el-checkbox>
<el-checkbox v-if="filterItems.myValid" label="myValid">我的有效</el-checkbox>
<el-checkbox v-if="filterItems.valid" label="valid">有效线索</el-checkbox>
<el-checkbox v-if="filterItems.todayValid" label="todayValid">今日有效线索</el-checkbox>
<el-checkbox v-if="filterItems.todayFollow" label="todayFollow">今日跟踪</el-checkbox>
<el-checkbox v-if="filterItems.outtime" label="outtime">
<el-badge :value="expireCount" type="danger">过期线索</el-badge>
</el-checkbox>
<el-checkbox v-if="filterItems.relate" label="relate">相关线索</el-checkbox>
<el-checkbox v-if="filterItems.reSign" label="reSign">撞单线索</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item class="m20">
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增</el-button>
<el-button type="primary" @click="handlePublicClue">公海</el-button>
<el-dropdown trigger="click">
<el-button type="primary">
更多
<i class="el-icon-arrow-down el-icon--right" />
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="handleImport(false)">导入</el-dropdown-item>
<el-dropdown-item @click.native="handleImport(true)">一点通导入</el-dropdown-item>
<el-dropdown-item v-if="admin == 'true'" @click.native="handleExport">导出</el-dropdown-item>
<el-dropdown-item v-if="admin == 'true'" @click.native="handleBatChUpdate()">批量修改</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-form-item>
<!-- <el-button type="primary" v-if="admin != 'true' && accept" @click="handleAccept(false)">停止接收</el-button>
<el-button type="primary" v-if="admin != 'true' && !accept" @click="handleAccept(true)">启动接收</el-button> -->
</el-row>
</el-form>
</el-row>
<CustomColumnTable v-if="!queryParams.reSign" :table-list="tableDataList" :table-loading="tableLoading" :query-params.sync="queryParams" :default-columns="tableAllFields.map(item=>item.prop)" :sortable-columns="tableAllFields.map(item=>item.prop)" :table-all-fields="tableAllFields" :selectable="true" @getlist="getPageList" @changeSort="changeSort" @clickRow="handleRowClick" @selectRow="selectRow">
<template v-slot:appendColumn>
<!-- <el-table-column label="备注" prop="clueMemo" sortable min-width="140" show-overflow-tooltip=true v-if="!queryParams.reSign" /> -->
<el-table-column label="意向状态" prop="intentionState" sortable fixed="right" min-width="100" v-if="!queryParams.reSign">
<template slot-scope="{ row }">
<el-tag effect="dark" style="border: none" :color="tagColorMap[row.intentionState]">{{ row.intentionState }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="320" v-if="!queryParams.reSign">
<template slot-scope="scope">
<el-button type="text" icon="el-icon-edit" @click.native.stop="handleUpdate(scope.row)" v-if="admin == 'true' || scope.row.followUser2 == userId">编辑</el-button>
<el-button v-if="(admin == 'true' || scope.row.followUser2 == userId ) && scope.row.refuse" type="text" icon="el-icon-edit" @click.native.stop="handleRefuse(scope.row)">甩单驳回</el-button>
<el-button v-if="(admin == 'true' || scope.row.followUser2 == userId ) &&!scope.row.refuse" type="text" icon="el-icon-edit" :style="{ color: `${scope.row.offlineReceiver?'#26A69A':'#409EFF'}` }" @click.native.stop="handleDistribute(scope.row)">甩单</el-button>
<el-button v-if="(admin == 'true' || scope.row.followUser2 == userId ) &&scope.row.state" type="text" icon="el-icon-edit" style="color:#26A69A;" @click.native.stop="handleSign1(scope.row)">已登记</el-button>
<el-button v-if="(admin == 'true' || scope.row.followUser2 == userId ) &&!scope.row.state" type="text" icon="el-icon-edit" @click.native.stop="handleSign1(scope.row)">未登记</el-button>
<el-button v-if="(admin == 'true' || scope.row.followUser2 == userId ) " type="text" icon="el-icon-delete" @click.native.stop="handleDelete(scope.row)">删除</el-button>
<el-button v-if="(admin == 'true' || scope.row.followUser2 == userId ) " type="text" icon="el-icon-delete" @click.native.stop="handleDiscard(scope.row)">释放</el-button>
</template>
</el-table-column>
</template>
</CustomColumnTable>
<CustomColumnTable v-else :table-list="tableDataList" :table-loading="tableLoading" :query-params.sync="queryParams" :default-columns="tableAllFields.filter(item => item.show).map(item=>item.prop)" :sortable-columns="tableAllFields.filter(item => item.show).map(item=>item.prop)" :table-all-fields="tableAllFields.filter(item => item.show)" :selectable="true" @getlist="getPageList" @changeSort="changeSort" @clickRow="handleRowClick" @selectRow="selectRow">
</CustomColumnTable>
<el-drawer :visible.sync="clueVisible" size="90%" append-to-body destroy-on-close>
<div slot="title">
<div v-if="clueInfo.consultCount && clueInfo.consultCount < 2">
学员信息
<span v-if="clueInfo.name">-{{ clueInfo.name }}</span>
</div>
<el-popover v-else placement="top-start" trigger="hover">
<el-table :data="consultRecord">
<el-table-column width="120" prop="consultTime" label="咨询日期" />
<el-table-column width="100" prop="consultUserName" label="咨询人" />
</el-table>
<el-badge slot="reference" :value="clueInfo.consultCount">
<span>
学员信息
<span v-if="clueInfo.name">-{{ clueInfo.name }}</span>
</span>
</el-badge>
</el-popover>
</div>
<clue-form v-if="clueVisible" ref="clueInfo" v-model="clueInfo" :options="{ userOptions: userOptions2, sourceOptions: sourceOptions, intentionOptions: intentionOptions, placeInfo: placeInfo }" />
<div class="drawer-form__footer">
<div style="flex: 1;text-align: right;">
<template v-if="saveNextShow">
<el-checkbox v-model="saveNext" />
<span class="ml5">保存后继续创建下一条</span>
</template>
</div>
<div class="ml0" style="width: 60%; display: flex;">
<el-button class="footer_button" @click="clueVisible = false"> </el-button>
<el-button class="footer_button" type="primary" :loading="modalSaveLoading" @click="handleSaveClue"> </el-button>
</div>
</div>
</el-drawer>
<el-dialog :title="dialogTitle" :visible.sync="dialogShow" custom-class="dialog500" :width="dialogWidth">
<component :is="componentName" v-if="dialogShow" ref="form" v-model="form" :options="dialogFormOptions" />
<span v-if="dialogFooterShow" slot="footer">
<el-button @click="dialogShow = false">取消</el-button>
<el-button type="primary" :loading="dialogSaving" @click="handleDialogConfirm">确定</el-button>
</span>
</el-dialog>
<!-- 用户导入对话框 -->
<el-dialog title="学员信息导入" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload action="#" accept=".xlsx, .xls" :show-file-list="false" :http-request="handleUpload" :disabled="upload.isUploading" drag>
<i class="el-icon-upload" />
<div class="el-upload__text">
将文件拖到此处
<em>点击上传</em>
</div>
<div slot="tip" class="el-upload__tip">
<el-link type="info" style="font-size:12px" @click="importTemplate">下载模板</el-link>
</div>
<div slot="tip" class="el-upload__tip" style="color:red">提示仅允许导入xlsxlsx格式文件</div>
</el-upload>
</el-dialog>
</div>
</template>
<script>
import {
getClueList,
exportData,
importTemplate,
deleteClue,
refuse,
getClueCountBadge,
addClue,
updateClue,
getSign,
saveSign,
getConsultRecord,
saveDistribute,
batchUpdate,
discardClue,
updateAccept,
getAccept
} from '@/api/zs/clue'
import { getEmployee, getAllPlaces, importData } from '@/api/tool/common'
export default {
name: 'Clue',
components: {
CustomColumnTable: () => ({
component: import('@/components/CustomColumnTable'),
}),
ClueForm: () => ({ component: import('./components/clueForm') }),
DistributeForm: () => ({ component: import('./components/distributeForm.vue') }),
SignForm: () => ({ component: import('./components/signForm') }),
BatchUpdateForm: () => ({ component: import('./components/batchUpdateForm') }),
FilterForm: () => ({ component: import('./components/filterForm') }),
PublicTable: () => ({ component: import('./components/publicTable') }),
},
data() {
return {
admin: localStorage.getItem('admin'),
userId: localStorage.getItem('userId'),
tagColorMap: {
A高意向: '#ff7043',
B中意向: '#26a69a',
C无意向: '#5c6bc0',
D未知意向: '#ef5350',
报名成功: '#ffa726',
报名他校: '#afaeb0',
无效线索: '#afaeb0',
},
dialogShow: false,
dialogFooterShow: false,
componentName: undefined,
dialogTitle: '',
dialogWidth: '50%',
form: {},
dialogSaving: false,
dialogFormOptions: [],
clueVisible: false,
distributeVisible: false,
queryParams: {
pageNum: 1,
pageSize: 10,
createTime: [],
name: undefined,
intentionState: undefined,
followUser2: undefined,
source: undefined,
etc: [],
total: 0,
},
tableAllFields: [
{ prop: 'createTime', label: '创建时间', show: true },
{ prop: 'source', label: '线索来源', show: true },
{ prop: 'name', label: '姓名', show: true },
{ prop: 'phone', label: '联系方式', show: true },
{ prop: 'address', label: '位置', show: true },
{ prop: 'requirement', label: '学员诉求', show: true },
{ prop: 'licenseType', label: '咨询车型', show: true },
{ prop: 'followTime', label: '下次跟进时间', width: 140, show: true },
{ prop: 'firstFollowUserName', label: '首次跟进人员', width: 140, show: true },
{ prop: 'followUserName', label: '跟进人员', show: true },
{ prop: 'recentLook', label: '是否近期看场地', width: 140 },
{ prop: 'offlineReceiverName', label: '线下接待人员', width: 140, show: true },
{ prop: 'clueMemo', label: '备注', show: true },
],
tableLoading: false,
tableDataList: [],
upload: {
open: false,
isUploading: false,
// 线
ydtData: false,
},
sourceOptions: [],
intentionOptions: [],
userOptions: [],
clueInfo: {},
expireCount: undefined,
placeInfo: [],
consultRecord: [],
modalSaveLoading: false,
saveNextShow: false,
saveNext: false,
clueIds: [],
filterItems: {
myCreate: true,
myValid: true,
valid: true,
todayValid: true,
todayFollow: true,
outtime: true,
relate: false,
reSign: false
},
accept: false,
employeeId: undefined,
userOptions2: [],
}
},
created() {
// 线
this.getDicts('dm_source').then((response) => {
this.sourceOptions = response.data
})
//
this.getDicts('dm_intention_state').then((response) => {
this.intentionOptions = response.data
})
this._getClueCountBadge()
this.getPageList()
this.getEmployee()
//
this.getAllPlace()
if (localStorage.getItem(this.userId + '-filterItems')) {
this.filterItems = JSON.parse(
localStorage.getItem(this.userId + '-filterItems')
)
}
this.getAccept();
},
methods: {
//
handleQuery() {
this.queryParams.pageNum = 1
this.getPageList()
},
getAccept() {
getAccept().then(resp => {
if (resp.code == 200) {
this.accept = resp.data.accept;
this.employeeId = resp.data.employeeId;
}
})
},
getPageList() {
this.tableLoading = true
const params = { ...this.queryParams, etc: undefined }
getClueList(this.opearateRequestParams(params)).then((response) => {
this.tableDataList = response.rows
this.queryParams.total = response.total
this.tableLoading = false
})
},
//
async _getClueCountBadge() {
const resp = await getClueCountBadge()
if (resp.code === 200) {
this.expireCount = resp.data
}
},
//
resetQuery() {
this.queryParams = {
pageNum: 1,
pageSize: 10,
createTime: [],
name: undefined,
intentionState: undefined,
followUser2: undefined,
source: undefined,
etc: [],
total: 0,
}
this.handleQuery()
},
etcChange(val) {
this.$set(this.queryParams, 'myCreate', undefined)
this.$set(this.queryParams, 'myValid', undefined)
this.$set(this.queryParams, 'valid', undefined)
this.$set(this.queryParams, 'todayValid', undefined)
this.$set(this.queryParams, 'todayFollow', undefined)
this.$set(this.queryParams, 'outtime', undefined)
this.$set(this.queryParams, 'relate', undefined)
this.$set(this.queryParams, 'reSign', undefined)
if (!this.isNullOrEmpty(val)) {
val.length > 1 &&
this.$set(this.queryParams, 'etc', [val[val.length - 1]])
this.$set(this.queryParams, val[val.length - 1], true)
}
if (this.queryParams.reSign) {
this.tableAllFields = this.tableAllFields.map(item => {
if (item.prop == 'clueMemo') {
item.show = false;
}
return item;
})
} else {
this.tableAllFields = this.tableAllFields.map(item => {
if (item.prop == 'clueMemo') {
item.show = true;
}
return item;
})
}
this.handleQuery()
},
resetForm() {
this.clueInfo = {
clueId: undefined,
createTime: this.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}'),
consultTime: undefined,
source: undefined,
name: undefined,
phone: undefined,
address: undefined,
intentionState: undefined,
followInfo: undefined,
followTime: undefined,
followUser: undefined,
signupInfo: undefined,
requirement: undefined,
licenseType: undefined,
}
this.dialogFormOptions = {
userOptions: this.userOptions,
sourceOptions: this.sourceOptions,
intentionOptions: this.intentionOptions,
placeInfo: this.placeInfo,
}
},
//
handleAdd() {
this.resetForm()
this.clueVisible = true
this.saveNextShow = true
this.saveNext = false
this.getEmployee2();
},
//
handleUpdate(listItem) {
this.clueVisible = true
this.clueInfo = listItem
this.saveNextShow = false
this.saveNext = false
this.getEmployee2()
//
this.getConsultRecord(listItem.clueId)
},
//
getConsultRecord(clueId) {
getConsultRecord({ clueId }).then((resp) => {
if (resp && resp.code === 200 && resp.data) {
this.consultRecord = resp.data
}
})
},
handleRowClick(row) {
if (!this.queryParams.reSign) {
this.handleUpdate(row)
}
},
//
handleDelete(item) {
this.$confirm(
'是否确认删除该条线索(“' + item.name + '/' + item.phone + '”)?',
'警告',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then((res) => {
deleteClue({ clueId: item.clueId }).then((resp) => {
if (resp.code === 200) {
this.$message.success('删除成功')
this.getPageList()
}
})
})
.catch(function () { })
},
/** 导出按钮操作 */
handleExport() {
this.$confirm('是否确认导出所有学员信息项?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
const resp = await exportData(
this.opearateRequestParams(this.queryParams)
)
this.download(resp.msg)
})
},
/** 导入按钮操作 */
handleImport(ydtData) {
this.upload.open = true
this.upload.ydtData = ydtData
},
/** 下载模板操作 */
importTemplate() {
importTemplate({ ydtData: this.upload.ydtData }).then((response) => {
this.download(response.msg)
})
},
async handleUpload(data) {
const formData = new FormData()
formData.append('file', data.file)
this.upload.isUploading = true
importData(this.upload.ydtData, formData).then(resp => {
this.upload.isUploading = false
if (resp.code === 200) {
this.$alert(resp.msg, '导入结果', {
dangerouslyUseHTMLString: true
});
this.upload.open = false
this.getList()
}
})
},
getEmployee() {
getEmployee({ coach: false }).then((resp) => {
if (resp.code === 200) {
this.userOptions = resp.data
}
})
},
//线
getEmployee2() {
getEmployee({ coach: false }).then((resp) => {
if (resp.code === 200) {
this.userOptions2 = resp.data
this.userOptions2 = this.userOptions2.filter(item => {
return item.accept;
})
}
})
},
changeSort(val) {
if (val.order) {
this.queryParams.orderName = val.prop
if (val.order === 'ascending') {
this.queryParams.orderType = 'asc'
} else {
this.queryParams.orderType = 'desc'
}
} else {
this.queryParams.orderName = undefined
this.queryParams.orderType = undefined
}
this.getPageList()
},
handleDistribute(item) {
this.dialogTitle = '甩单'
this.dialogWidth = '700px'
this.componentName = 'DistributeForm'
this.dialogFormOptions = {
userOptions: this.userOptions,
offlineReceiver: item.offlineReceiver,
}
this.dialogFooterShow = true
this.form = {
clueId: item.clueId,
offlineReceiverName: item.offlineReceiverName,
offlineReceiver: undefined,
memo: item.memo,
}
this.dialogShow = true
},
handleRefuse(item) {
refuse({ clueId: item.clueId }).then((resp) => {
if (resp.code === 200) {
this.$message.success('驳回成功')
this.getPageList()
}
})
},
resetSignForm() {
this.form = {
dealDate: this.parseTime(new Date(), '{y}-{m}-{d}'),
signSchool: undefined,
schoolName: undefined,
signPlace: undefined,
placeName: undefined,
signClass: undefined,
className: undefined,
signPrice: undefined,
schoolPeople: undefined,
schoolPay: undefined,
alipay: undefined,
profit: undefined,
percentage: undefined,
detail: undefined,
dealState: undefined,
extraPayType: undefined,
extraPay: undefined,
percentageState: undefined,
memo: undefined,
createTime: undefined,
updateTime: undefined,
state: true,
commission: undefined,
}
this.dialogFormOptions = {
userOptions: this.userOptions,
sourceOptions: this.sourceOptions,
placeInfo: this.placeInfo,
}
},
async handleSign1(item) {
this.dialogTitle = '成交登记'
this.dialogWidth = '800px'
this.componentName = 'SignForm'
this.dialogFooterShow = true
this.resetSignForm()
const resp = await getSign({ clueId: item.clueId })
if (resp.code === 200) {
const {
clueId,
consultTime,
name,
phone,
source,
followUser,
followUser2,
followUserName,
offlineReceiver,
offlineReceiver2,
offlineReceiverName,
} = item
this.form = Object.assign({}, this.form, {
clueId,
consultTime,
name,
phone,
source,
followUser,
followUser2,
followUserName,
offlineReceiver,
offlineReceiver2,
offlineReceiverName,
})
if (resp.data) {
this.form = { ...this.form, ...resp.data }
this.dialogFooterShow = this.form.signEdit
}
this.dialogShow = true
}
},
getAllPlace() {
getAllPlaces({ status: '0' }).then((resp) => {
this.placeInfo = resp.data.filter(
(item) => item.schoolShow && item.showInMap
)
})
},
handleSaveClue() {
this.$refs.clueInfo.validateForm().then(async (valid) => {
if (valid) {
this.modalSaveLoading = true
let resp
if (this.clueInfo.clueId) {
resp = await updateClue(this.clueInfo)
this.modalSaveLoading = false
if (resp.code === 200) {
this.$message.success('修改成功')
this.getPageList()
this.clueVisible = false
}
} else {
resp = await addClue(this.clueInfo)
this.modalSaveLoading = false
if (resp.code === 200) {
this.$message.success('新增成功')
if (this.saveNext) {
this.resetForm()
} else {
this.getPageList()
this.clueVisible = false
}
}
}
}
})
},
handleDialogConfirm() {
this.$refs.form.validate().then(async (valid) => {
if (valid) {
let resp
this.dialogSaving = true
if (this.componentName === 'SignForm') {
//
this.form.checkState = 1
resp = await saveSign(this.form)
} else if (this.componentName === 'DistributeForm') {
resp = await saveDistribute(this.form)
} else if (this.componentName === 'BatchUpdateForm') {
resp = await batchUpdate(this.form)
} else if (this.componentName === 'FilterForm') {
this.filterItems = { ...this.form }
localStorage.setItem(
this.userId + '-filterItems',
JSON.stringify(this.filterItems)
)
this.$message.success('操作成功')
this.dialogShow = false
}
this.dialogSaving = false
if (resp && resp.code === 200) {
this.$message.success('操作成功')
this.dialogShow = false
this.getPageList()
}
}
})
},
//
selectRow(val) {
console.log(val)
this.clueIds = []
if (val && val.length > 0) {
this.clueIds = val.map((item) => item.clueId)
}
},
//
handleBatChUpdate() {
this.getEmployee2()
//
if (!this.clueIds || this.clueIds.length <= 0) {
//
this.$message.error('请至少选择一条数据!')
} else {
//
this.dialogTitle = '批量修改'
this.dialogWidth = '500px'
this.componentName = 'BatchUpdateForm'
this.dialogFormOptions = {
userOptions: this.userOptions2,
}
this.dialogFooterShow = true
this.form = {
followUsers: [],
clueIds: this.clueIds,
}
this.dialogShow = true
}
},
//
handleFilter() {
//
this.dialogTitle = '筛选配置'
this.dialogWidth = '500px'
this.componentName = 'FilterForm'
this.dialogFormOptions = {
userOptions: this.userOptions,
}
this.dialogFooterShow = true
this.form = { ...this.filterItems }
this.dialogShow = true
},
handlePublicClue() {
//
this.dialogTitle = '公海线索'
this.dialogWidth = '900px'
this.componentName = 'PublicTable'
this.dialogFormOptions = {
userOptions: this.userOptions,
}
this.dialogFooterShow = false
this.form = {}
this.dialogShow = true
},
handleDiscard(item) {
discardClue(item).then((resp) => {
if (resp && resp.code == 200) {
this.$message.success('释放成功')
this.getPageList()
}
})
},
//线
handleAccept(accept) {
updateAccept({ employeeId: this.employeeId, accept: accept }).then(resp => {
if (resp.code == 200) {
this.$message.success(accept ? '启动成功' : '停止成功')
this.accept = accept;
}
})
},
},
}
</script>
<style scoped>
.drawer-form__footer {
border-top: 1px solid rgba(69, 74, 91, 0.1);
position: absolute;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
height: 50px;
line-height: 50px;
z-index: 2;
background: #fff;
}
.footer_button {
width: 49%;
margin: auto;
}
</style>

@ -0,0 +1,73 @@
<template>
<el-form
ref="form"
:model="form"
:rules="rules"
label-width="110px"
:disabled="form.signId != undefined"
>
<el-row>
<el-col :span="24">
<el-form-item label="跟进人员" prop="followUsers">
<el-select v-model="form.followUsers" multiple placeholder="请选择" clearable>
<el-option
v-for="dict in options.userOptions"
:key="dict.id"
:label="dict.name"
:value="dict.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
export default {
name: 'BatchUpdateForm',
model: {
prop: 'info',
event: 'update',
},
props: {
info: {
type: Object,
default: () => {},
},
options: {
type: Object,
default: () => ({
userOptions: [],
}),
},
},
data() {
return {
admin: JSON.parse(localStorage.getItem('admin')),
form: JSON.parse(JSON.stringify(this.info)),
rules: {
followUsers: {
required: true,
message: '跟进人员不能为空',
trigger: 'blur',
},
},
}
},
watch: {
form: {
handler(val) {
this.$emit('update', val)
},
deep: true,
immediate: true,
},
},
methods: {
validate() {
return this.$refs.form.validate()
},
},
}
</script>

@ -0,0 +1,650 @@
<template>
<div style="margin-bottom: 50px">
<el-form ref="form" :model="form" :rules="rules" label-width="110px">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="创建时间" prop="createTime">
<el-date-picker v-model="form.createTime" value-format="yyyy-MM-dd HH:mm" format="yyyy-MM-dd HH:mm" type="datetime" :disabled="admin!='true'" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="线索来源" prop="source">
<el-select v-model="form.source" placeholder="请选择" clearable>
<el-option v-for="dict in options.sourceOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="跟进人员" prop="followUser">
<el-select v-model="form.followUser" multiple clearable :disabled="admin != 'true' && form.clueId != undefined">
<el-option v-for="dict in options.userOptions" :key="dict.id" :label="dict.name" :value="dict.id" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" placeholder="请输入姓名" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系方式" prop="phone">
<el-input v-model="form.phone" placeholder="请输入联系方式" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="意向状态" prop="intentionState">
<el-select v-model="form.intentionState" placeholder="请选择" clearable>
<el-option v-for="dict in options.intentionOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue">
<i class="el-icon-star-on" :style="dict.cssClass" />
<span style="float: right; color: #8492a6; font-size: 13px">
{{
dict.dictValue
}}
</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="下次跟进时间" prop="followTime">
<el-date-picker v-model="form.followTime" value-format="yyyy-MM-dd HH:mm" format="yyyy-MM-dd HH:mm" type="datetime" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="是否近期看场地" prop="recentLook">
<el-radio v-model="form.recentLook" label="是"></el-radio>
<el-radio v-model="form.recentLook" label="否"></el-radio>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="显示场地">
<el-radio-group v-model="mapPlaceType" @change="createMarkersInMap">
<el-radio :label="0">自营场地</el-radio>
<el-radio :label="1">全部场地</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="备注" prop="clueMemo">
<el-input v-model="form.clueMemo" type="textarea" :rows="2" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20 plr20" style="position: relative">
<div id="map" class="amap-cavans" />
<el-collapse class="box-card">
<el-collapse-item title="附近驾校">
<div style="padding: 10px">
<div slot="header">附近驾校</div>
<div v-if="nearbySchoolSearching">正在搜索中...</div>
<template v-else>
<div v-for="p in nearbySchoolList" :key="p.index">
<div class="hover-pointer" style="font-size: 14px; color: blue" @click="getClassType(p)">
<i v-if="p.recommend" class="el-icon-star-off" />
驾校: {{ p.deptName }}-{{ p.name }}
</div>
<div class="mt5">地址{{ p.address }}</div>
<div class="mt5">
直线距离: {{ p.distance }} 公里;
<span class="ml0">步行距离{{ p.walkdistance }}</span>
</div>
<el-divider />
</div>
</template>
</div>
</el-collapse-item>
</el-collapse>
<div class="address">
<el-form-item label="位置" prop="address" label-width="80px">
<el-input v-model="form.address" placeholder="请输入位置" disabled>
<el-button slot="append" class="p10" icon="el-icon-location-information" @click="handleMapEdit" />
<el-button slot="append" class="p10" icon="el-icon-delete-solid" @click="handleRemovePosition" />
</el-input>
</el-form-item>
</div>
</el-col>
</el-row>
<el-row style="margin-bottom: 20px">
<el-col :span="24">
<el-form-item label="跟进情况">
<el-timeline v-if="folowInfos != undefined && folowInfos.length > 0" style="max-height: 200px; overflow-y: auto">
<el-timeline-item v-for="item in folowInfos" :key="item.record" :timestamp="item.operateTime" placement="top" style="padding: 5px !important">
<el-card>
<div style="font-weight: bold">用户 {{ item.operateUserName }}</div>
<div style="padding-left: 10px" v-html="item.centent" />
</el-card>
</el-timeline-item>
</el-timeline>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-dialog width="800px" title="地图编辑" :visible.sync="mapDialogShow" append-to-body @opened="initDialogMap()">
<div id="dialogMap" class="dialog-map" />
<!-- <el-input id="search" v-model="searchBody" class="search-body" placeholder="请输入..." /> -->
<el-autocomplete popper-class="my-autocomplete" class="search-body" placeholder="请输入..." v-model="searchBody" :trigger-on-focus="false" :fetch-suggestions="querySearch" @select="handleSelect">
<template slot-scope="{ item }">
<span class="name">{{ item.name }}</span>
<span class="addr">{{ item.district }}</span>
</template>
</el-autocomplete>
<span slot="footer" class="dialog-footer">
<el-button @click="mapDialogShow = false"> </el-button>
<el-button type="primary" @click="handleMapSave"> </el-button>
</span>
</el-dialog>
<el-dialog width="40%" :title="innerTitle" :visible.sync="innerVisible" append-to-body>
<div v-if="classType == undefined || classType.length == 0">无班型数据</div>
<el-table v-else :data="classType" style="height: 300px; overflow-y: auto">
<el-table-column label="班型">
<template slot-scope="scope">
<span>{{ scope.row.licenseType }}-{{ scope.row.dictLabel }}</span>
</template>
</el-table-column>
<el-table-column property="currentPrice" label="报价" />
<el-table-column property="minPrice" label="底价" />
<el-table-column property="description" label="描述" />
</el-table>
</el-dialog>
</div>
</template>
<script>
import { getFollowRecord } from '@/api/zs/clue';
import { getClassTypes } from '@/api/tool/common';
import { inputtips, regeo, walking } from '@/api/tool/map';
// import AMap from 'AMap';
export default {
model: {
prop: 'info',
event: 'update'
},
props: {
info: {
type: Object,
default: () => { }
},
options: {
type: Object,
default: () => ({
userOptions: [],
sourceOptions: [],
intentionOptions: [],
placeInfo: []
})
}
},
data() {
return {
admin: localStorage.getItem('admin'),
userId: localStorage.getItem('userId'),
form: JSON.parse(JSON.stringify(this.info)),
mapDialogShow: false,
map: null,
locationMarker: null,
dialogMap: null, //
currentPoint: {}, //
marker: null, //
placeSearch: null,
geocoder: null,
searchBody: '',
nearbySchoolList: [],
folowInfos: [],
nearbySchoolSearching: false, //
rules: {
name: {
required: true,
message: '姓名不为空',
trigger: 'blur'
},
phone: {
required: true,
message: '联系方式不为空',
trigger: 'blur'
},
createTime: {
required: true,
message: '创建时间不为空',
trigger: 'blur,change'
},
consultTime: {
required: true,
message: '咨询时间不为空',
trigger: 'blur,change'
},
source: {
required: true,
message: '线索来源不为空',
trigger: 'blur,change'
},
address: {
required: true,
message: '位置不为空',
trigger: 'blur'
},
intentionState: {
required: true,
message: '意向状态不为空',
trigger: 'blur,change'
}
},
innerTitle: '',
classType: [],
innerVisible: false,
consultRecord: [],
mapPlaceType: 0 // 0 1
};
},
watch: {
form: {
handler(val) {
this.$emit('update', val);
},
deep: true,
immediate: true
}
},
created() {
if (this.form.clueId) {
this.handleUpdate();
}
},
mounted() {
this.initMap();
},
beforeDestroy() {
this.geocoder = null;
this.locationMarker = null;
this.marker = null;
this.placeSearch = null;
this.map.clearMap();
this.map && this.map.destroy();
this.map = null;
this.dialogMap && this.dialogMap.destroy();
this.dialogMap = null;
},
methods: {
//
getClassType(item) {
this.classType = [];
this.innerTitle = item.deptName + '-' + item.name + '-班型报价';
getClassTypes({
schoolId: item.deptId,
placeId: item.placeId,
status: '0'
}).then((resp) => {
if (resp && resp.code === 200 && resp.data) {
this.classType = resp.data;
this.innerVisible = true;
}
});
},
//
handleUpdate() {
//
getFollowRecord({ clueId: this.form.clueId }).then((resp) => {
this.folowInfos = resp.data;
});
},
initMap() {
if (!this.map) {
this.map = new AMap.Map('map', {
zoom: 12,
center: [117.226095, 31.814372],
resizeEnable: true
});
}
//
if (this.form.lat && this.form.lng) {
this.locationMarker = new AMap.Marker({
position: [this.form.lng, this.form.lat],
icon: require(`@/assets/images/place/flag_red.png`)
});
this.map.add(this.locationMarker);
this.map.setCenter([this.form.lng, this.form.lat]);
this.map.setZoom(14);
}
this.getNearbySchool();
this.createMarkersInMap();
},
// markers
createMarkersInMap() {
let arr = this.options.placeInfo;
if (this.mapPlaceType === 0) {
arr = arr.filter((item) => item.recommend);
}
this.map && this.map.clearMap();
this.locationMarker && this.map.add(this.locationMarker);
for (let i = 0; i < arr.length; i++) {
const element = arr[i];
const tmpMarker = new AMap.Marker({
map: this.map,
position: [element.lng, element.lat],
label: {
content: element.name,
direction: 'left'
},
icon: require(`@/assets/images/position_${element.flagColor}.png`),
extData: element,
clickable: true
});
tmpMarker.on('click', (ev) =>
this.getClassType(ev.target.getExtData())
);
}
},
handleMapEdit() {
this.searchBody = '';
this.mapDialogShow = true;
if (this.form.lat && this.form.lng) {
this.currentPoint.lat = this.form.lat;
this.currentPoint.lng = this.form.lng;
}
this.dialogMap && this.dialogMap.clearMap();
},
handleRemovePosition() {
this.form.lng = undefined;
this.form.lat = undefined;
this.form.address = undefined;
},
initDialogMap() {
if (!this.dialogMap) {
this.dialogMap = new AMap.Map('dialogMap', {
zoom: 12,
resizeEnable: true,
center: [117.283042, 31.86119]
});
this.dialogMap.on('click', (ev) => {
this.currentPoint.lat = ev.lnglat.lat;
this.currentPoint.lng = ev.lnglat.lng;
this.regeoCode();
this.marker && this.dialogMap.remove(this.marker);
this.marker = new AMap.Marker({
position: [this.currentPoint.lng, this.currentPoint.lat],
icon: require(`@/assets/images/place/flag_red.png`)
});
this.dialogMap.add(this.marker);
});
this.dialogMap.addControl(new AMap.Scale());
// const auto = new AMap.Autocomplete({
// input: 'search', //
// })
// this.placeSearch = new AMap.PlaceSearch({
// map: this.dialogMap,
// pageSize: 1, //
// pageIndex: 1, //
// autoFitView: true, // 使 Marker
// })
// AMap.event.addListener(auto, 'select', this.select)
this.geocoder = new AMap.Geocoder();
}
//
if (this.form.lat && this.form.lng) {
this.searchBody = this.form.address;
this.marker = new AMap.Marker({
map: this.dialogMap,
position: [this.form.lng, this.form.lat],
icon: require(`@/assets/images/place/flag_red.png`)
});
this.dialogMap.setCenter([this.form.lng, this.form.lat]);
this.dialogMap.setZoom(14);
}
},
handleMapSave() {
if (this.currentPoint.lat && this.currentPoint.lng) {
this.form.lng = this.currentPoint.lng;
this.form.lat = this.currentPoint.lat;
this.$set(this.form, 'address', this.currentPoint.address);
this.locationMarker && this.map.remove(this.locationMarker);
this.locationMarker = new AMap.Marker({
map: this.map,
position: [this.currentPoint.lng, this.currentPoint.lat],
icon: require(`@/assets/images/place/flag_red.png`)
});
this.map.setCenter([this.currentPoint.lng, this.currentPoint.lat]);
this.map.setZoom(14);
this.getNearbySchool();
this.mapDialogShow = false;
} else {
this.$message.error('请在地图上选择位置后保存!');
}
},
//
select(e) {
this.placeSearch.setCity(e.poi.adcode);
this.placeSearch.search(e.poi.name, (status, result) => {
// result
if (
result &&
result.info &&
result.info === 'OK' &&
result.poiList &&
result.poiList.pois &&
result.poiList.pois.length > 0
) {
this.currentPoint.lat = result.poiList.pois[0].location.lat;
this.currentPoint.lng = result.poiList.pois[0].location.lng;
this.currentPoint.address = e.poi.name;
this.dialogMap.clearMap();
this.marker && this.dialogMap.remove(this.marker);
this.marker = new AMap.Marker({
map: this.dialogMap,
position: [this.currentPoint.lng, this.currentPoint.lat],
icon: require(`@/assets/images/place/flag_red.png`)
});
this.dialogMap.setZoom(14);
this.dialogMap.setCenter([
this.currentPoint.lng,
this.currentPoint.lat
]);
}
});
},
// ->
regeoCode() {
// this.geocoder.getAddress(
// [this.currentPoint.lng, this.currentPoint.lat],
// (status, result) => {
// if (status === 'complete' && result.regeocode) {
// this.currentPoint.address = result.regeocode.formattedAddress;
// this.searchBody = result.regeocode.formattedAddress;
// }
// }
// );
if (this.currentPoint.lng && this.currentPoint.lat) {
regeo({
key: 'f2f35d6adc4a16bb879d303cead56237',
location: this.currentPoint.lng + "," + this.currentPoint.lat
}).then(resp => {
if (resp.status == '1') {
this.currentPoint.address = resp.regeocode.formatted_address;
this.searchBody = resp.regeocode.formatted_address;
}
});
}
},
// ·
getNearbySchool() {
if (this.form.lng && this.form.lat) {
this.nearbySchoolList = [];
this.nearbySchoolSearching = true;
//
let places1 = [];
//
let places2 = [];
const p2 = [this.form.lng, this.form.lat];
for (let i = 0; i < this.options.placeInfo.length; i++) {
const element = this.options.placeInfo[i];
const p1 = [element.lng, element.lat];
// 线
element.distance = (
window.AMap.GeometryUtil.distance(p1, p2) / 1000
).toFixed(2);
element.recommend ? places1.push(element) : places2.push(element);
}
// 线
//
if (places1.length > 1) {
places1 = places1.sort((a, b) => a.distance - b.distance);
}
//
if (places2.length > 1) {
places2 = places2.sort((a, b) => a.distance - b.distance);
}
// ,
this.nearbySchoolList = [];
for (let i = 0; i < 4; i++) {
places1.length > i && this.nearbySchoolList.push(places1[i]);
places2.length > i && this.nearbySchoolList.push(places2[i]);
if (this.nearbySchoolList.length === 4) {
break;
}
}
//
this.nearbySchoolList.map(async (item) => {
const p1 = [item.lng, item.lat];
const resp = await this.getWalkingDistance(p1, p2);
item.walkdistance = resp;
this.$forceUpdate();
});
this.nearbySchoolSearching = false;
}
},
//
async getWalkingDistance(start, end) {
if (start && end) {
const resp = await walking({
key: 'f2f35d6adc4a16bb879d303cead56237',
origin: start[0] + "," + start[1],
destination: end[0] + "," + end[1],
});
if (resp.status === '1') {
let num = resp.route.paths[0].distance;
return num > 1000 ? `${(num / 1000).toFixed(2)} 公里` : `${num}`
} else {
return '步行数据无法确定';
}
}
// return new Promise((resolve, reject) => {
// })
// return new Promise((resolve, reject) => {
// window.AMap.plugin('AMap.Walking', () => {
// const walking = new AMap.Walking();
// let num = 0;
// walking.search(start, end, (status, result) => {
// debugger
// if (status === 'complete') {
// result.routes.forEach((item) => {
// num += item.distance;
// });
// resolve(
// num > 1000 ? `${(num / 1000).toFixed(2)} ` : `${num} `
// );
// } else {
// resolve('');
// }
// });
// });
// });
},
validateForm() {
return this.$refs.form.validate();
},
async querySearch(queryString, cb) {
if (queryString) {
const resp = await inputtips({
key: 'f2f35d6adc4a16bb879d303cead56237',
keywords: queryString
});
cb(resp.tips);
}
},
handleSelect(item) {
this.currentPoint.lat = item.location.split(',')[1];
this.currentPoint.lng = item.location.split(',')[0];
this.currentPoint.address = item.name;
this.searchBody = item.district + item.name;
this.dialogMap.clearMap();
this.marker && this.dialogMap.remove(this.marker);
this.marker = new AMap.Marker({
map: this.dialogMap,
position: [this.currentPoint.lng, this.currentPoint.lat],
icon: require(`@/assets/images/place/flag_red.png`)
});
this.dialogMap.setZoom(14);
this.dialogMap.setCenter([this.currentPoint.lng, this.currentPoint.lat]);
}
}
};
</script>
<style lang="scss" scoped>
.amap-cavans {
width: 100%;
height: 600px;
}
.dialog-map {
width: 100%;
height: 400px;
}
.address {
position: absolute;
left: 30px;
top: 10px;
width: 400px;
background: #fff;
}
.box-card {
position: absolute;
right: 30px;
top: 10px;
width: 400px;
}
.search-body {
position: absolute;
top: 90px;
left: 25px;
width: 300px;
}
.el-divider--horizontal {
margin: 6px 0;
}
li {
padding: 6px;
.name {
font-size: 12px;
line-height: 16px;
text-overflow: ellipsis;
overflow: hidden;
}
.addr {
line-height: 16px;
font-size: 10px;
color: #b4b4b4;
}
.highlighted .addr {
color: #ddd;
}
}
</style>

@ -0,0 +1,95 @@
<template>
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-row>
<el-col :span="24">
<el-form-item label="线下接待人员" prop="offlineReceiver">
<el-input v-if="form.offlineReceiverName" v-model="form.offlineReceiverName" disabled />+
<el-select v-model="form.offlineReceiver" multiple filterable placeholder="请选择" style="width:97%; padding-top:5px;">
<el-option v-for="dict in options.userOptions.filter(item => !options.offlineReceiver || !options.offlineReceiver.includes(item.id))" :key="dict.id" :label="dict.name" :value="dict.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="memo">
<el-input v-model="form.memo" type="textarea" :rows="4" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col v-if="distributeRecord != undefined && distributeRecord.length > 0" :span="24">
<el-form-item label="甩单记录">
<el-timeline style="max-height:260px;overflow-y:auto;">
<el-timeline-item v-for="item in distributeRecord" :key="item.record" :timestamp="item.operateTime" placement="top" style="padding:5px !important;">
<el-card>
<span style="display:block;font-weight: bold; font-size:13px;">用户 {{ item.operateUserName }}</span>
<span style="display:block;padding-left: 10px; font-size:13px;" v-html="item.centent" />
</el-card>
</el-timeline-item>
</el-timeline>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import { getDistributeRecord } from '@/api/zs/clue'
export default {
name: 'DistributeForm',
model: {
prop: 'info',
event: 'update',
},
props: {
info: {
type: Object,
default: () => { },
},
options: {
type: Object,
default: () => ({
userOptions: [],
offlineReceiver: [],
}),
},
},
data() {
return {
form: JSON.parse(JSON.stringify(this.info)),
rules: {
offlineReceiver: {
required: true,
message: '线下接待人员不为空',
trigger: 'change',
},
},
distributeRecord: [],
}
},
watch: {
form: {
handler(val) {
this.$emit('update', val)
},
deep: true,
immediate: true,
},
},
created() {
this.handleDistribute()
},
methods: {
validate() {
return this.$refs.form.validate()
},
handleDistribute() {
//
getDistributeRecord({ clueId: this.form.clueId }).then((resp) => {
if (resp.code === 200) {
this.distributeRecord = resp.data
}
})
},
},
}
</script>

@ -0,0 +1,73 @@
<template>
<el-form ref="form" :model="form" :rules="rules">
<el-row>
<el-col :span="8">
<el-checkbox v-model="form.myCreate" label="myCreate">我创建的</el-checkbox>
</el-col>
<el-col :span="8">
<el-checkbox v-model="form.myValid" label="myValid">我的有效</el-checkbox>
</el-col>
<el-col :span="8">
<el-checkbox v-model="form.valid" label="valid">有效线索</el-checkbox>
</el-col>
<el-col :span="8">
<el-checkbox v-model="form.todayValid" label="todayValid">今日有效线索</el-checkbox>
</el-col>
<el-col :span="8">
<el-checkbox v-model="form.todayFollow" label="todayFollow">今日跟踪</el-checkbox>
</el-col>
<el-col :span="8">
<el-checkbox v-model="form.outtime" label="outtime">过期线索</el-checkbox>
</el-col>
<el-col :span="8">
<el-checkbox v-model="form.relate" label="relate">相关线索</el-checkbox>
</el-col>
<el-col :span="8">
<el-checkbox v-model="form.reSign" label="reSign">撞单线索</el-checkbox>
</el-col>
</el-row>
</el-form>
</template>
<script>
export default {
name: 'FilterForm',
model: {
prop: 'info',
event: 'update',
},
props: {
info: {
type: Object,
default: () => { },
},
options: {
type: Object,
default: () => ({
userOptions: [],
}),
},
},
data() {
return {
form: JSON.parse(JSON.stringify(this.info)),
rules: {},
}
},
watch: {
form: {
handler(val) {
this.$emit('update', val)
},
deep: true,
immediate: true,
},
},
methods: {
validate() {
return this.$refs.form.validate()
},
},
}
</script>

@ -0,0 +1,84 @@
<template>
<div>
<el-button type="text" icon="el-icon-refresh" style="margin-bottom:10px;" @click="handleQuery">刷新</el-button>
<el-table v-loading="loading" :data="publicList" border :row-class-name="tableRowClassName">
<el-table-column label="创建时间" prop="consultTime" width="100">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.consultTime) }}</span>
</template>
</el-table-column>
<el-table-column label="线索来源" prop="source" width="100" />
<el-table-column label="姓名" prop="name" width="100" />
<el-table-column label="位置" prop="address" min-width="160" />
<el-table-column label="意向状态" prop="intentionState" width="100" />
<el-table-column label="备注" prop="clueMemo" min-width="150" />
<el-table-column label="操作" fixed="right" width="80">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handlePickup(scope.row)">获取</el-button>
</template>
</el-table-column>
</el-table>
<pagination :total="queryParams.total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" :page-sizes="[50, 100]" @pagination="getList" />
</div>
</template>
<script>
import { getPublicList, pickupClue } from '@/api/zs/clue'
export default {
name: 'PublicTable',
data() {
return {
publicList: [],
loading: true,
queryParams: {
pageNum: 1,
pageSize: 100,
total: 0,
},
}
},
mounted() {
this.getList()
// this.timer = setInterval(() => {
// this.getList()
// }, 5000)
},
methods: {
getList() {
this.loading = true
getPublicList(this.queryParams).then((resp) => {
if (resp && resp.code == 200) {
this.publicList = resp.rows
this.loading = false
this.queryParams.total = resp.total
}
})
},
handlePickup(item) {
pickupClue(item).then((resp) => {
if (resp && resp.code == 200) {
this.$message.success('拾取成功')
this.getList()
}
})
},
tableRowClassName({ row, rowIndex }) {
if (row.followUser2 || row.followUser) {
return 'warning-row'
} else {
return ''
}
},
handleQuery() {
this.loading = true
this.getList()
},
},
}
</script>
<style scope>
.el-table .warning-row {
background: oldlace;
}
</style>

@ -0,0 +1,416 @@
<template>
<el-form ref="form" :model="form" :rules="rules" label-width="110px" :disabled="form.signId != undefined && !form.signEdit">
<el-row>
<el-col :span="12">
<el-form-item label="学员姓名">
<el-input v-model="form.name" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="学员联系方式">
<el-input v-model="form.phone" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="线索来源">
<el-select v-model="form.source" disabled>
<el-option v-for="dict in options.sourceOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否全款" prop="state">
<el-radio-group v-model="form.state">
<el-radio :label="true">全款</el-radio>
<el-radio :label="false">非全款</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="成交日期" prop="dealDate">
<el-date-picker v-model="form.dealDate" :picker-options="dateControl" value-format="yyyy-MM-dd" format="yyyy-MM-dd" type="date" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="报名价格(元)" prop="signPrice">
<el-input v-model="form.signPrice" placeholder="学员报名时需要交纳总共的钱" @blur="priceChange" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="报名驾校" prop="signSchool">
<el-select v-model="form.signSchool" filterable placeholder="请选择" @change="schoolChange">
<el-option v-for="dict in schoolOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="报名场地" prop="signPlace">
<el-select v-model="form.signPlace" filterable placeholder="请选择" @change="placeChange">
<el-option v-for="dict in options.placeInfo.filter(item =>item.deptId === form.signSchool)" :key="dict.placeId" :label="dict.name" :value="dict.placeId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="报名班型" prop="signClass">
<el-select v-model="form.signClass" filterable placeholder="请选择" @change="priceChange">
<el-option v-for="dict in classTypeOptions.filter(item =>((!item.placeId && item.deptId === form.signSchool) || item.placeId === form.signPlace))" :key="dict.typeId" :label="`${dict.licenseType}-${dict.typeName}`" :value="dict.typeId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="对接人" prop="schoolPeople">
<el-input v-model="form.schoolPeople" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="驾校支付" prop="schoolPay">
<el-input v-model="form.schoolPay" type="number" placeholder="请输入驾校支付金额" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="驾考宝典款" prop="alipay">
<el-input v-model="form.alipay" placeholder="请输入驾考宝典款金额" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="额外支出" prop="extraPayType">
<el-select v-model="form.extraPayTypes" filterable placeholder="请选择" multiple clearable>
<el-option v-for="dict in extraPayTypeOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="额外支出金额" prop="extraPay">
<el-input v-model="form.extraPay" placeholder="请输入额外支出金额" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="归属人员" prop="followUser">
<el-select v-model="form.followUser" multiple placeholder="请选择" clearable :disabled="true">
<el-option v-for="dict in options.userOptions" :key="dict.id" :label="dict.name" :value="dict.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属区域" prop="area">
<el-select v-model="form.area" placeholder="请选择" clearable>
<el-option v-for="dict in areaOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
</el-select>
</el-form-item>
</el-col>
<el-col v-if="admin" :span="12">
<el-form-item label="佣金明细" prop="commission">
<el-select v-model="form.commission" placeholder="请选择" clearable>
<el-option v-for="dict in commissionOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="memo">
<el-input v-model="form.memo" type="textarea" :rows="2" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-form-item label="凭据" prop="evidence">
<el-upload action="#" class="evidence-uploader" :http-request="handleUploadFile" accept="image/*" :show-file-list="false" multiple>
<i class="el-icon-plus evidence-uploader-icon" />
</el-upload>
<div v-for="(item, index) in form.fileList" :key="index" class="pr dib">
<el-image class="image-list-item" fit="contain" :src="preUrl + item" :preview-src-list="form.fileList.map(url => preUrl + url)" lazy />
<i class="el-icon-close btn-close" @click="handleRemoveImage(index,item)" />
</div>
</el-form-item>
</el-row>
<el-row v-if="checkRecord && checkRecord.length > 0">
<el-col :span="24">
<el-form-item label="审核记录">
<el-timeline style="max-height:260px;overflow-y:auto;">
<el-timeline-item v-for="item in checkRecord" :key="item.record" :timestamp="item.operateTime" placement="top" style="padding:5px !important;">
<el-card>
<span style="display:block;font-weight: bold; font-size:13px;">用户 {{ item.operateUserName }}</span>
<span style="display:block;padding-left: 10px; font-size:13px;" v-html="item.centent" />
</el-card>
</el-timeline-item>
</el-timeline>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import { validateMoney } from '@/utils/validate'
import {
getSchools,
getClassTypeInfo,
uploadEvidence,
deleteFile,
} from '@/api/tool/common'
import { getCheckRecord } from '@/api/zs/sign'
export default {
name: 'SignForm',
model: {
prop: 'info',
event: 'update',
},
props: {
info: {
type: Object,
default: () => { },
},
options: {
type: Object,
default: () => ({
userOptions: [],
sourceOptions: [],
placeInfo: [],
}),
},
},
data() {
return {
admin: JSON.parse(localStorage.getItem('admin')),
preUrl: process.env.VUE_APP_BASE_API,
form: JSON.parse(JSON.stringify(this.info)),
rules: {
area: {
required: true,
message: '所属区域不为空',
trigger: 'blur',
},
dealDate: {
required: true,
message: '成交时间不为空',
trigger: 'blur,change',
},
state: {
required: true,
message: '是否权限必选',
trigger: 'blur,change',
},
followUser: {
required: true,
message: '归属人员不为空',
trigger: 'blur,change',
},
signSchool: {
required: true,
message: '报名驾校不为空',
trigger: 'blur,change',
},
signPlace: {
required: true,
message: '报名场地不为空',
trigger: 'blur,change',
},
signClass: {
required: true,
message: '报名班型不为空',
trigger: 'blur,change',
},
dealState: {
required: true,
message: '结算情况不为空',
trigger: 'blur,change',
},
signPrice: {
required: true,
validator: validateMoney,
trigger: 'blur',
},
},
schoolOptions: [],
placeOptions: [],
classTypeOptions: [],
areaOptions: [],
commissionOptions: [],
extraPayTypeOptions: [],
dateControl: undefined,
checkRecord: [],
}
},
watch: {
form: {
handler(val) {
this.$emit('update', val)
},
deep: true,
immediate: true,
},
},
created() {
if (!this.form.fileList) {
this.$set(this.form, 'fileList', [])
}
this.initData()
},
methods: {
initData() {
//
this.getDicts('dm_commission').then((response) => {
this.commissionOptions = response.data
})
//
this.getDicts('dm_extra_pay').then((response) => {
this.extraPayTypeOptions = response.data
})
//
this.getDicts('dm_area').then((response) => {
this.areaOptions = response.data
})
//
getSchools().then((resp) => {
this.schoolOptions = resp.data
})
//
getClassTypeInfo({ status: '0' }).then((resp) => {
this.classTypeOptions = resp.data
})
//
this.form.signId &&
getCheckRecord({
signId: this.form.signId,
type: 1,
}).then((resp) => {
this.checkRecord = resp.data
})
//
if (!this.form.signId) {
let start = new Date()
// 1
start.setDate(1)
// 5
if (new Date().getDate() < 5) {
if (start.getMonth() > 0) {
start.setMonth(start.getMonth() - 1)
} else {
start.setFullYear(start.getFullYear() - 1)
start.setMonth(11)
}
}
// new Date()
start = start.getTime() - 24 * 60 * 60 * 1000
this.dateControl = {
disabledDate: (time) => {
return time.getTime() < start || time.getTime() > new Date()
},
}
}
},
validate() {
return this.$refs.form.validate()
},
// change
schoolChange() {
this.$set(this.form, 'signPlace', undefined)
this.$set(this.form, 'signClass', undefined)
},
placeChange() {
this.$set(this.form, 'signClass', undefined)
this.$set(
this.form,
'schoolPeople',
this.options.placeInfo.find(
(item) => item.placeId === this.form.signPlace
).contact
)
this.$set(
this.form,
'area',
this.options.placeInfo.find(
(item) => item.placeId === this.form.signPlace
).area
)
// this.form.schoolPeople = this.options.placeInfo.find(
// (item) => item.placeId === this.form.signPlace
// ).contact
},
async handleUploadFile(data) {
if (data.file) {
const size = data.file.size
const limitSize = 20 * 1024 * 1024 // 20M
if (size < limitSize) {
const formData = new FormData()
formData.append('file', data.file)
const resp = await uploadEvidence(formData)
if (resp.code === 200) {
this.form.fileList.push(resp.data)
}
} else {
this.msgInfo('文件过大')
}
}
},
handleRemoveImage(index, item) {
deleteFile(item).then((resp) => {
if (resp && resp.data)
//
this.form.fileList.splice(index, 1)
})
},
priceChange() {
// -
if (this.form.signClass && this.form.signPrice) {
let minprice
this.classTypeOptions.some((item) => {
if (item.typeId == this.form.signClass) {
minprice = item.minPrice
return item
}
})
if (minprice) {
this.$set(this.form, 'schoolPay', this.form.signPrice - minprice)
}
} else {
this.$set(this.form, 'schoolPay', undefined)
}
},
},
}
</script>
<style lang="scss" scoped>
.el-row {
display: flex;
flex-wrap: wrap;
}
.evidence-uploader {
display: inline-block;
.el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
&:hover {
border-color: #409eff;
}
.evidence-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
}
}
}
.image-list-item {
height: 100px;
img {
width: auto;
}
}
.btn-close {
position: absolute;
right: 0;
top: 0;
padding: 2px;
font-size: 20px;
background: #f2f6fc;
}
</style>

@ -35,20 +35,31 @@ module.exports = {
proxy: {
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
// target: `http://localhost:8080`,
target: `http://vue.ruoyi.vip/prod-api/`,
target: `http://localhost:8086`,
// target: `http://vue.ruoyi.vip/prod-api/`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
},
"/amap": {
target: "https://restapi.amap.com",
changeOrigin: true,
ws: true,
pathRewrite: {
"^/amap": ""
}
}
},
disableHostCheck: true
},
css: {
loaderOptions: {
sass: {
sassOptions: { outputStyle: 'expanded' }
sassOptions: {
outputStyle: 'expanded'
}
}
}
},
@ -59,6 +70,9 @@ module.exports = {
'@': resolve('src')
}
},
externals: {
AMap: "AMap"
},
plugins: [
// http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
new CompressionPlugin({
@ -92,12 +106,10 @@ module.exports = {
config
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin', [
{
.use('script-ext-html-webpack-plugin', [{
// `runtime` must same as runtimeChunk name. default is `runtime`
inline: /runtime\..*\.js$/
}
])
}])
.end();
config.optimization.splitChunks({
chunks: 'all',
@ -122,8 +134,7 @@ module.exports = {
}
}
});
config.optimization.runtimeChunk('single'),
{
config.optimization.runtimeChunk('single'), {
from: path.resolve(__dirname, './public/robots.txt'), // 防爬虫文件
to: './' // 到根目录下
};

Loading…
Cancel
Save