线索
This commit is contained in:
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -8,7 +8,7 @@
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"[vue]": {
|
||||
"editor.defaultFormatter": "Vue.volar"
|
||||
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
|
||||
13
src/api/call/index.js
Normal file
13
src/api/call/index.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export default {
|
||||
callLogin(data) {
|
||||
return request.post({ url: '/call-api/openapi/V2.0.4/agentLogin', data })
|
||||
},
|
||||
callUserStatus(data) {
|
||||
return request.post({ url: '/call-api/openapi/V2.0.4/getAgentStatus', data })
|
||||
},
|
||||
callNumber(data) {
|
||||
return request.post({ url: '/call-api/openapi/V2.0.4/callNumber', data })
|
||||
}
|
||||
}
|
||||
@@ -19,10 +19,20 @@
|
||||
trigger="click"
|
||||
virtual-triggering
|
||||
>
|
||||
<el-checkbox-group v-model="checkedColumns">
|
||||
<el-checkbox v-for="item in tableColumns" :key="item.field" :label="item.field">
|
||||
{{ item.label }}
|
||||
</el-checkbox>
|
||||
<el-checkbox-group v-model="checkedColumns" @change="confirm">
|
||||
<draggable
|
||||
v-model="allColumns"
|
||||
item-key="field"
|
||||
ghost-class="draggable-ghost"
|
||||
:animation="400"
|
||||
@end="onDragEnd"
|
||||
>
|
||||
<template #item="{ element: item }">
|
||||
<el-checkbox :key="item.field" :label="item.field">
|
||||
{{ item.label }}
|
||||
</el-checkbox>
|
||||
</template>
|
||||
</draggable>
|
||||
</el-checkbox-group>
|
||||
</el-popover>
|
||||
</div>
|
||||
@@ -37,12 +47,19 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import draggable from 'vuedraggable'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { useRoute } from 'vue-router'
|
||||
import cache from '@/plugins/cache'
|
||||
|
||||
const props = defineProps({
|
||||
tableObject: { type: Object, default: () => ({ tableList: [] }) },
|
||||
tableColumns: { type: Array, default: () => [] }
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:tableObject', 'getList'])
|
||||
const emit = defineEmits(['update:tableObject', 'getList', 'getCheckedColumns'])
|
||||
const route = useRoute()
|
||||
const { id: userId } = useUserStore().user //取用户ID
|
||||
|
||||
const currentPage = ref(props.tableObject?.currentPage || 1)
|
||||
|
||||
@@ -50,9 +67,12 @@ const pageSize = ref(props.tableObject?.pageSize || 20)
|
||||
|
||||
const ColumnSetting = ref()
|
||||
const TableColumnPop = ref()
|
||||
|
||||
// 展示在设置里的所有表格列,由于会排序,所以使用新属性,不直接修改原值
|
||||
const allColumns = ref({})
|
||||
// 已勾选的选项
|
||||
const checkedColumns = ref([])
|
||||
|
||||
// 调用获取数据的接口,分页时需要使用
|
||||
function getList({ page, limit }) {
|
||||
emit('update:tableObject', { ...props.tableObject, currentPage: page, pageSize: limit })
|
||||
nextTick(() => {
|
||||
@@ -60,9 +80,75 @@ function getList({ page, limit }) {
|
||||
})
|
||||
}
|
||||
|
||||
// 点击"表格列控制"按钮,出现设置页面
|
||||
const clickSetting = () => {
|
||||
unref(TableColumnPop).TableColumnPop?.delayHide?.()
|
||||
}
|
||||
|
||||
// 获取所有的表格列,注意如果本地有缓存使用缓存数据,因为用户可能已对表格列排序,并且不依赖网络请求,可更快渲染表头
|
||||
function getAllColumns() {
|
||||
// 1. 先获取缓存表头
|
||||
const localData = getColumn('TableColumnAll')[route.name] || []
|
||||
// 2. 如果有缓存的表头,直接使用,并将新增的标题加入,如果没有缓存,那就得用获取到的表头
|
||||
if (localData && localData) {
|
||||
const newColumns = props.tableColumns.filter(
|
||||
(item) => !localData.some((it) => it.field == item.field)
|
||||
)
|
||||
allColumns.value = [...localData, ...newColumns]
|
||||
} else {
|
||||
allColumns.value = [...props.tableColumns]
|
||||
}
|
||||
}
|
||||
// 获取缓存的表头
|
||||
function getColumn(name = 'shitTable') {
|
||||
return cache.local.get(`${name}-${userId}`) || {}
|
||||
}
|
||||
// 设置表头缓存
|
||||
function setColumn(val, name = 'shitTable') {
|
||||
cache.local.set(`${name}-${userId}`, val)
|
||||
}
|
||||
// 获取用户已勾选的表头
|
||||
function getUserCheckedColumns() {
|
||||
// 1. 先获取缓存
|
||||
const localData = getColumn('shitTable')[route.name]
|
||||
// 2. 如果有缓存,使用缓存表头,否则使用默认的所有表头
|
||||
if (localData && localData.length) {
|
||||
checkedColumns.value = localData
|
||||
} else {
|
||||
checkedColumns.value = allColumns.value.map((it) => it.field)
|
||||
}
|
||||
// 3. 回显到表格中
|
||||
emitColumns()
|
||||
}
|
||||
|
||||
// 表格列排序
|
||||
function onDragEnd() {
|
||||
const obj = getColumn('TableColumnAll')
|
||||
obj[route.name] = allColumns.value
|
||||
// 1. 设置缓存
|
||||
setColumn(obj, 'TableColumnAll')
|
||||
// 2. 表格回显
|
||||
emitColumns()
|
||||
}
|
||||
|
||||
// 勾选确认
|
||||
function confirm() {
|
||||
const obj = getColumn()
|
||||
obj[route.name] = checkedColumns.value
|
||||
setColumn(obj, 'shitTable')
|
||||
emitColumns()
|
||||
}
|
||||
|
||||
// 将表头数据返回至父组件
|
||||
function emitColumns() {
|
||||
const arr = allColumns.value.filter((item) => checkedColumns.value.includes(item.field))
|
||||
emit('getCheckedColumns', arr)
|
||||
}
|
||||
|
||||
getAllColumns()
|
||||
getUserCheckedColumns()
|
||||
|
||||
defineExpose({ getUserCheckedColumns })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -7,6 +7,13 @@ import { findIndex } from '@/utils'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { FormSchema } from '@/types/form'
|
||||
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { useRoute } from 'vue-router'
|
||||
import cache from '@/plugins/cache'
|
||||
|
||||
const route = useRoute()
|
||||
const { id: userId } = useUserStore().user //取用户ID
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = defineProps({
|
||||
@@ -43,8 +50,16 @@ const emit = defineEmits(['search', 'reset'])
|
||||
|
||||
const visible = ref(true)
|
||||
|
||||
const SchemaSetting = ref()
|
||||
const SettingPop = ref()
|
||||
|
||||
const checkedSchema = ref([])
|
||||
|
||||
// 用户使用的查询条件
|
||||
const usedSchema = ref([])
|
||||
|
||||
const newSchema = computed(() => {
|
||||
let schema: FormSchema[] = cloneDeep(props.schema)
|
||||
let schema: FormSchema[] = cloneDeep(usedSchema.value)
|
||||
if (props.expand && props.expandField && !unref(visible)) {
|
||||
const index = findIndex(schema, (v: FormSchema) => v.field === props.expandField)
|
||||
if (index > -1) {
|
||||
@@ -65,6 +80,43 @@ const newSchema = computed(() => {
|
||||
return schema
|
||||
})
|
||||
|
||||
function initSearch() {
|
||||
reset()
|
||||
// 1. 先获取缓存
|
||||
const localData = getColumn('Schema')[route.name]
|
||||
// 2. 如果有缓存,使用缓存表头,否则使用默认的所有表头
|
||||
if (localData && localData.length) {
|
||||
usedSchema.value = localData
|
||||
} else {
|
||||
const obj = getColumn('Schema')
|
||||
obj[route.name] = [props.schema[0]]
|
||||
setSchema(obj)
|
||||
usedSchema.value = [props.schema[0]]
|
||||
}
|
||||
checkedSchema.value = usedSchema.value.map((it) => it.field)
|
||||
}
|
||||
|
||||
function changeSearch() {
|
||||
const obj = getColumn('Schema')
|
||||
obj[route.name] = props.schema.filter((item) => checkedSchema.value.includes(item.field))
|
||||
setSchema(obj)
|
||||
initSearch()
|
||||
}
|
||||
|
||||
// 获取缓存的查询条件
|
||||
function getColumn(name = 'Schema') {
|
||||
return cache.local.get(`${name}-${userId}`) || {}
|
||||
}
|
||||
|
||||
// 设置查询条件缓存
|
||||
function setSchema(val: Array<Object>, name = 'Schema') {
|
||||
cache.local.set(`${name}-${userId}`, val)
|
||||
}
|
||||
|
||||
function setSearch() {
|
||||
unref(SettingPop).SettingPop?.delayHide?.()
|
||||
}
|
||||
|
||||
const { register, elFormRef, methods } = useForm({
|
||||
model: props.model || {}
|
||||
})
|
||||
@@ -96,6 +148,8 @@ const setVisible = () => {
|
||||
unref(elFormRef)?.resetFields()
|
||||
visible.value = !unref(visible)
|
||||
}
|
||||
|
||||
initSearch()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -114,6 +168,25 @@ const setVisible = () => {
|
||||
>
|
||||
<template #action>
|
||||
<div v-if="layout === 'inline'">
|
||||
<ElButton ref="SchemaSetting" @click="setSearch">
|
||||
<Icon class="mr-5px" icon="ep:setting" />
|
||||
查询设置
|
||||
</ElButton>
|
||||
<el-popover
|
||||
ref="SettingPop"
|
||||
:virtual-ref="SchemaSetting"
|
||||
placement="bottom"
|
||||
width="120px"
|
||||
trigger="click"
|
||||
virtual-triggering
|
||||
>
|
||||
<el-checkbox-group v-model="checkedSchema" @change="changeSearch">
|
||||
<el-checkbox v-for="item in schema" :key="item.field" :label="item.field">
|
||||
{{ item.label }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-popover>
|
||||
|
||||
<!-- update by 芋艿:去除搜索的 type="primary",颜色变淡一点 -->
|
||||
<ElButton v-if="showSearch" @click="search">
|
||||
<Icon class="mr-5px" icon="ep:search" />
|
||||
|
||||
@@ -52,7 +52,13 @@ const toDocument = () => {
|
||||
<ElDropdown :class="prefixCls" trigger="click">
|
||||
<div class="flex items-center">
|
||||
<img :src="avatar" alt="" class="w-[calc(var(--logo-height)-25px)] rounded-[50%]" />
|
||||
<span class="<lg:hidden text-14px pl-[5px] text-[var(--top-header-text-color)]">
|
||||
<span
|
||||
v-if="userName"
|
||||
class="<lg:hidden text-14px pl-[5px] text-[var(--top-header-text-color)]"
|
||||
>
|
||||
莳松科技管理员
|
||||
</span>
|
||||
<span v-else class="<lg:hidden text-14px pl-[5px] text-[var(--top-header-text-color)]">
|
||||
{{ userName }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
2
src/plugins/cache/index.js
vendored
2
src/plugins/cache/index.js
vendored
@@ -1,5 +1,5 @@
|
||||
import router from '@/router'
|
||||
import { name as appName } from '../../../../package.json'
|
||||
import { name as appName } from '../../../package.json'
|
||||
|
||||
let name = `${appName}-${import.meta.env.VITE_APP_ENV}`
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
overflow-y: auto;
|
||||
padding-top: 0;
|
||||
max-height: calc(100% - 118px);
|
||||
}
|
||||
|
||||
/* nprogress 适配 element-plus 的主题色 */
|
||||
@@ -48,3 +50,8 @@
|
||||
.crud-form-item .el-input__wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.el-dialog {
|
||||
margin-top: 5vh;
|
||||
max-height: 90vh;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px">
|
||||
<el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px" style="height: 90vh">
|
||||
<el-tabs v-model="tabName">
|
||||
<el-tab-pane label="线索信息" name="info">
|
||||
<Form
|
||||
|
||||
@@ -28,6 +28,12 @@
|
||||
</el-collapse>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="handleSave">保 存</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -256,6 +262,11 @@ const activeQues = ref('')
|
||||
function filterList() {
|
||||
showList.value = resultList.filter((it) => it.question.includes(keyword.value))
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
console.log('保存成功')
|
||||
dialogVisible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dialog title="成交登记" v-model="show" width="800px">
|
||||
<el-dialog title="成交登记" v-model="show" width="800px" style="height: 90vh">
|
||||
<Descriptions :data="info" :schema="schema" :columns="2" />
|
||||
<el-form :model="form" ref="formRef" :rules="rules" label-width="80px" class="mt-20px">
|
||||
<el-row :gutter="20">
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
:destroy-on-close="true"
|
||||
:show-close="true"
|
||||
:wrapperClosable="true"
|
||||
@close="destroyMap"
|
||||
>
|
||||
<!-- header -->
|
||||
<el-skeleton :loading="loading" animated>
|
||||
@@ -51,7 +52,7 @@
|
||||
<el-button type="danger" plain>删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-dompurify-html="followContent"></div>
|
||||
<div>{{ followContent }}</div>
|
||||
<div class="flex mt-10px" style="align-items: center">
|
||||
<div class="flex" style="color: #666; align-items: center">
|
||||
<Icon icon="ep:clock" class="mr-5px" />
|
||||
@@ -78,7 +79,7 @@
|
||||
<el-button type="danger" plain>删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div key="followContent" v-dompurify-html="followContent2"></div>
|
||||
<div>{{ followContent2 }}</div>
|
||||
<div class="flex mt-10px" style="align-items: center">
|
||||
<div class="flex" style="color: #666; align-items: center">
|
||||
<Icon icon="ep:clock" class="mr-5px" />
|
||||
@@ -95,22 +96,11 @@
|
||||
</el-timeline>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="详细信息" name="infoDetail">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item min-width="150px" label="线索名称">{{
|
||||
info.name
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item min-width="150px" label="联系方式"
|
||||
>18888888888</el-descriptions-item
|
||||
>
|
||||
<el-descriptions-item min-width="150px" label="线索来源">驾考宝典</el-descriptions-item>
|
||||
<el-descriptions-item min-width="150px" label="意向状态">高意向</el-descriptions-item>
|
||||
<el-descriptions-item min-width="150px" :span="2" label="诉求"
|
||||
>这是诉求内容这是诉求内容这是诉求内容这是诉求内容这是诉求内容这是诉求内容这是诉求内容</el-descriptions-item
|
||||
>
|
||||
<el-descriptions-item min-width="150px" :span="2" label="备注"
|
||||
>这是备注内容</el-descriptions-item
|
||||
>
|
||||
</el-descriptions>
|
||||
<Descriptions :data="info" :schema="schema" :columns="2" />
|
||||
<el-checkbox v-model="showSchool" :label="true" @change="handleShowSchool"
|
||||
>展示场地</el-checkbox
|
||||
>
|
||||
<div id="dialogMap" class="mt-20px" style="height: 400px; width: 100%"></div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="操作记录" name="operateRecord">
|
||||
<el-timeline>
|
||||
@@ -188,10 +178,42 @@
|
||||
|
||||
<script setup>
|
||||
import DialogFollow from './DialogFollow.vue'
|
||||
import ImgFlag from '@/assets/imgs/flag/position_blue.png'
|
||||
import AMapLoader from '@amap/amap-jsapi-loader'
|
||||
const show = ref(false)
|
||||
const info = ref(null)
|
||||
const loading = ref(false)
|
||||
|
||||
const schema = ref([
|
||||
{
|
||||
field: 'name',
|
||||
label: '线索名称'
|
||||
},
|
||||
{
|
||||
field: 'contact',
|
||||
label: '联系方式'
|
||||
},
|
||||
{
|
||||
field: 'supplier',
|
||||
label: '意向状态'
|
||||
},
|
||||
{
|
||||
field: 'supplier',
|
||||
label: '创建时间'
|
||||
},
|
||||
{
|
||||
field: 'purchaseCount',
|
||||
label: '诉求',
|
||||
span: 2
|
||||
},
|
||||
{
|
||||
field: 'remark',
|
||||
label: '备注',
|
||||
isEditor: true,
|
||||
span: 2
|
||||
}
|
||||
])
|
||||
|
||||
const followContent = `<p style="color: red;">这是本次跟进的内容。</p><br/><p>我还能放图片,但需要你自己排版:</p><br/><img style="width: 200px;" src="https://q6.itc.cn/images01/20240407/0e6be21aebc847648109304f20370790.jpeg">`
|
||||
|
||||
const followContent2 = `<p style="color: red;">这是本次跟进的内容。</p>`
|
||||
@@ -211,9 +233,65 @@ const followList = ref([
|
||||
}
|
||||
])
|
||||
|
||||
// 地图相关
|
||||
const dialogMap = ref(null)
|
||||
const aMap = ref(null)
|
||||
|
||||
function open(row) {
|
||||
info.value = row
|
||||
show.value = true
|
||||
if (!dialogMap.value) {
|
||||
nextTick(() => {
|
||||
initMap()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function initMap() {
|
||||
AMapLoader.load({
|
||||
key: '2ffb0e2ea90b1df0b8be48ed66e18fc8', //设置您的key
|
||||
version: '2.0'
|
||||
}).then((AMap) => {
|
||||
aMap.value = AMap
|
||||
dialogMap.value = new AMap.Map('dialogMap', {
|
||||
zoom: 12,
|
||||
zooms: [2, 22],
|
||||
center: [117.283042, 31.86119]
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const showSchool = ref(false)
|
||||
const schoolMarkers = ref([])
|
||||
|
||||
function handleShowSchool() {
|
||||
if (showSchool.value) {
|
||||
let marker1 = new aMap.value.Marker({
|
||||
map: dialogMap.value,
|
||||
position: [117.258001, 31.895216],
|
||||
label: {
|
||||
content: '慧安驾校桃花社区训练基地',
|
||||
direction: 'left'
|
||||
},
|
||||
icon: ImgFlag,
|
||||
// extData: element,
|
||||
clickable: true
|
||||
})
|
||||
let marker2 = new aMap.value.Marker({
|
||||
map: dialogMap.value,
|
||||
position: [117.286731, 31.902396],
|
||||
label: {
|
||||
content: '(皖西)瑞星驾校总校(D)',
|
||||
direction: 'left'
|
||||
},
|
||||
icon: ImgFlag,
|
||||
// extData: element,
|
||||
clickable: true
|
||||
})
|
||||
schoolMarkers.value = [marker1, marker2]
|
||||
} else {
|
||||
dialogMap.value.remove(schoolMarkers.value)
|
||||
}
|
||||
}
|
||||
|
||||
const infoIndex = ref('followRecord')
|
||||
@@ -229,6 +307,11 @@ function addFollow() {
|
||||
function updateFollow() {
|
||||
followRef.value.open('update', { nextFollowTime: '2024-04-01 12:12' })
|
||||
}
|
||||
|
||||
function destroyMap() {
|
||||
dialogMap.value = null
|
||||
aMap.value = null
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -18,7 +18,7 @@ const crudSchemas = reactive([
|
||||
type: 'datetime',
|
||||
format: 'YYYY-MM-DD HH:mm',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm',
|
||||
placeholder: '创建时间'
|
||||
placeholder: '本次跟进时间'
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -45,7 +45,11 @@ const crudSchemas = reactive([
|
||||
field: 'remark',
|
||||
isTable: true,
|
||||
form: {
|
||||
component: 'Editor',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
type: 'textarea',
|
||||
autosize: { minRows: 5, maxRows: 10 }
|
||||
},
|
||||
colProps: {
|
||||
span: 24
|
||||
}
|
||||
|
||||
@@ -28,6 +28,12 @@ const crudSchemas = reactive([
|
||||
isSearch: true,
|
||||
isTable: true
|
||||
},
|
||||
{
|
||||
label: '线索位置',
|
||||
field: 'address',
|
||||
isSearch: true,
|
||||
isTable: true
|
||||
},
|
||||
{
|
||||
label: '线索来源',
|
||||
field: 'resource',
|
||||
@@ -183,6 +189,11 @@ const crudSchemas = reactive([
|
||||
placeholder: '创建时间'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '跟进记录',
|
||||
field: 'followRecord',
|
||||
isTable: true
|
||||
}
|
||||
])
|
||||
export const { allSchemas } = useCrudSchemas(crudSchemas)
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
</el-tabs>
|
||||
<div class="absolute" style="right: 10px; top: 0">
|
||||
<el-button plain>导入</el-button>
|
||||
<el-button type="primary" @click="handleInsert">新增</el-button>
|
||||
<el-button type="primary" @click="handleInsert">新增线索</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 搜索工作栏 -->
|
||||
@@ -47,14 +47,28 @@
|
||||
v-model:tableObject="tableObject"
|
||||
:tableColumns="allSchemas.tableColumns"
|
||||
@get-list="getTableList"
|
||||
@get-checked-columns="getCheckedColumns"
|
||||
>
|
||||
<el-table-column
|
||||
v-for="item in allSchemas.tableColumns"
|
||||
v-for="item in showColumns"
|
||||
:key="item.field"
|
||||
:prop="item.field"
|
||||
:label="item.label"
|
||||
min-width="120px"
|
||||
/>
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<div v-if="item.field == 'followRecord'">
|
||||
<el-button type="primary" text style="padding: 0" @click="handleFollow(row)"
|
||||
>快速新增</el-button
|
||||
>
|
||||
</div>
|
||||
<div v-else-if="item.field == 'contact'">
|
||||
<span>{{ row[item.field] }}</span>
|
||||
<Icon class="ml-5px" icon="ep:phone" @click="makeCall(row.contact)" />
|
||||
</div>
|
||||
<span v-else>{{ row[item.field] }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200px" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" link @click="handleDetail(scope.row)">详情</el-button>
|
||||
@@ -68,6 +82,7 @@
|
||||
<DialogClue ref="formRef" />
|
||||
<DrawerClue ref="drawerRef" />
|
||||
<DialogSuccess ref="successRef" />
|
||||
<DialogFollow ref="followRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -76,6 +91,7 @@ import { allSchemas } from './cluePool.data'
|
||||
import DialogClue from './Comp/DialogClue.vue'
|
||||
import DrawerClue from './Comp/DrawerClue.vue'
|
||||
import DialogSuccess from './Comp/DialogSuccess.vue'
|
||||
import DialogFollow from './Comp/DialogFollow.vue'
|
||||
|
||||
const searchForm = ref({
|
||||
mode: '2'
|
||||
@@ -83,6 +99,7 @@ const searchForm = ref({
|
||||
const formRef = ref()
|
||||
const drawerRef = ref()
|
||||
const successRef = ref()
|
||||
const followRef = ref()
|
||||
|
||||
// const { tableObject, tableMethods } = useTable({
|
||||
// getListApi: MailTemplateApi.getMailTemplatePage, // 分页接口
|
||||
@@ -90,12 +107,20 @@ const successRef = ref()
|
||||
// })
|
||||
|
||||
const tableObject = ref({
|
||||
tableList: [{ name: '测试', contact: '18888888888' }],
|
||||
tableList: [{ name: '测试', contact: '17318531354' }],
|
||||
loading: false,
|
||||
total: 1,
|
||||
pageSize: 20,
|
||||
currentPage: 1
|
||||
})
|
||||
|
||||
const showColumns = ref([])
|
||||
|
||||
// 初始化表格
|
||||
function getCheckedColumns(list) {
|
||||
showColumns.value = list
|
||||
}
|
||||
|
||||
const setSearchParams = function () {
|
||||
// 方法体
|
||||
}
|
||||
@@ -117,6 +142,14 @@ function handleDetail(row) {
|
||||
drawerRef.value.open(row)
|
||||
}
|
||||
|
||||
function handleFollow(row) {
|
||||
followRef.value.open('create', row)
|
||||
}
|
||||
|
||||
async function makeCall(phone) {
|
||||
console.log('打电话:' + phone)
|
||||
}
|
||||
|
||||
// 登记
|
||||
function handleSuccess(row) {
|
||||
successRef.value.open(row)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-table :data="list" border stripe>
|
||||
<el-table :data="list" border>
|
||||
<el-table-column type="index" width="50" />
|
||||
<el-table-column label="来源名称">
|
||||
<template #default="{ row }">
|
||||
@@ -12,6 +12,11 @@
|
||||
<el-input v-model="row.link" placeholder="请输入" :clearable="false" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否启用" width="100px">
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.inEnable" :active-value="true" :inactive-value="false" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100px">
|
||||
<template #default="{ $index }">
|
||||
<el-button type="primary" style="padding: 0px" text @click="handleRemove($index)"
|
||||
|
||||
@@ -1,82 +1,125 @@
|
||||
<template>
|
||||
<el-form :model="form" ref="sendForm" :rules="rules" label-width="100px" :inline="false">
|
||||
<el-form-item label="是否自动分配">
|
||||
<el-radio-group v-model="form.isAuto">
|
||||
<el-radio :label="1"> 自动分配 </el-radio>
|
||||
<el-radio :label="0"> 手动分配 </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<div v-if="form.isAuto">
|
||||
<el-form-item label="分配对象">
|
||||
<div>
|
||||
<el-checkbox
|
||||
v-model="checkUserAll"
|
||||
:indeterminate="userIndeterminate"
|
||||
@change="userCheckAllChange"
|
||||
>
|
||||
全选
|
||||
</el-checkbox>
|
||||
<el-checkbox-group v-model="form.users" @change="userCheckedChange">
|
||||
<el-checkbox
|
||||
v-for="(item, index) in userOptions"
|
||||
:key="index"
|
||||
:label="item.value"
|
||||
:value="item.value"
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="线索来源">
|
||||
<div>
|
||||
<el-checkbox
|
||||
v-model="checkResourceAll"
|
||||
:indeterminate="resourceIndeterminate"
|
||||
@change="resourceCheckAllChange"
|
||||
>
|
||||
全选
|
||||
</el-checkbox>
|
||||
<el-checkbox-group v-model="form.resource" @change="resourceCheckedChange">
|
||||
<el-checkbox
|
||||
v-for="(item, index) in resourceOptions"
|
||||
:key="index"
|
||||
:label="item.value"
|
||||
:value="item.value"
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="权重配置">
|
||||
<div>
|
||||
<div v-for="(item, index) in intentionOptions" :key="index" class="flex mb-10px">
|
||||
<div class="mr-15px" style="width: 100px">{{ item.label }}</div>
|
||||
<el-input v-model="item.value" type="number" placeholder="请输入权重">
|
||||
<template #suffix> % </template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="分配时间">
|
||||
<el-time-picker
|
||||
v-model="form.sendTime"
|
||||
placeholder="任意时间点"
|
||||
format="HH:mm"
|
||||
value-format="HH:mm"
|
||||
:clearable="false"
|
||||
/>
|
||||
</el-form-item>
|
||||
<div class="flex">
|
||||
<div class="mr-20px" style="width: 500px">
|
||||
<el-input
|
||||
v-model="searchForm.keyword"
|
||||
placeholder="请输入关键字查询"
|
||||
clearable
|
||||
class="mb-10px"
|
||||
@keyup.enter="getUserList"
|
||||
/>
|
||||
|
||||
<el-table :data="userList" @cell-click="selectUser">
|
||||
<el-table-column prop="name" label="员工姓名" />
|
||||
<el-table-column prop="phone" label="电话" />
|
||||
<el-table-column prop="workNum" label="工号" />
|
||||
</el-table>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
v-model:limit="searchForm.pageSize"
|
||||
v-model:page="searchForm.pageNum"
|
||||
:total="total"
|
||||
@pagination="getUserList"
|
||||
/>
|
||||
</div>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button>重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form :model="form" ref="sendForm" :rules="rules" label-width="100px" :inline="false">
|
||||
<el-form-item label="是否自动分配">
|
||||
<el-radio-group v-model="form.isAuto">
|
||||
<el-radio :label="1"> 自动分配 </el-radio>
|
||||
<el-radio :label="0"> 手动分配 </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<div v-if="form.isAuto">
|
||||
<!-- <el-form-item label="分配对象">
|
||||
<div>
|
||||
<el-checkbox
|
||||
v-model="checkUserAll"
|
||||
:indeterminate="userIndeterminate"
|
||||
@change="userCheckAllChange"
|
||||
>
|
||||
全选
|
||||
</el-checkbox>
|
||||
<el-checkbox-group v-model="form.users" @change="userCheckedChange">
|
||||
<el-checkbox
|
||||
v-for="(item, index) in userOptions"
|
||||
:key="index"
|
||||
:label="item.value"
|
||||
:value="item.value"
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="线索来源">
|
||||
<div>
|
||||
<el-checkbox
|
||||
v-model="checkResourceAll"
|
||||
:indeterminate="resourceIndeterminate"
|
||||
@change="resourceCheckAllChange"
|
||||
>
|
||||
全选
|
||||
</el-checkbox>
|
||||
<el-checkbox-group v-model="form.resource" @change="resourceCheckedChange">
|
||||
<el-checkbox
|
||||
v-for="(item, index) in resourceOptions"
|
||||
:key="index"
|
||||
:label="item.value"
|
||||
:value="item.value"
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="权重配置">
|
||||
<div>
|
||||
<el-radio-group v-model="form.isRandom">
|
||||
<el-radio :label="1">
|
||||
<Tooltip message="根据剩余的线索平均分配到未分配线索的所有人" />
|
||||
平均分配
|
||||
</el-radio>
|
||||
<el-radio :label="0"> 权重分配 </el-radio>
|
||||
</el-radio-group>
|
||||
<div v-if="form.isRandom == 0">
|
||||
<div v-for="(item, index) in intentionOptions" :key="index" class="flex mb-10px">
|
||||
<div class="mr-15px" style="width: 100px">{{ item.label }}</div>
|
||||
<el-input v-model="item.value" type="number" placeholder="请输入权重">
|
||||
<template #suffix> % </template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="分配时间">
|
||||
<el-time-picker
|
||||
v-model="form.sendTime"
|
||||
placeholder="任意时间点"
|
||||
format="HH:mm"
|
||||
value-format="HH:mm"
|
||||
:clearable="false"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button>重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const searchForm = ref({
|
||||
keyword: '',
|
||||
pageSize: 20,
|
||||
pageNum: 1
|
||||
})
|
||||
|
||||
const total = ref(1)
|
||||
|
||||
const userList = ref([{ name: '张三', phone: '1888888888', workNum: '202101030001' }])
|
||||
|
||||
const form = ref({
|
||||
isAuto: 1,
|
||||
users: [1, 2],
|
||||
@@ -85,23 +128,27 @@ const form = ref({
|
||||
})
|
||||
const rules = ref({})
|
||||
|
||||
const checkUserAll = ref(false)
|
||||
const userIndeterminate = ref(true)
|
||||
const userOptions = ref([
|
||||
{ label: '张三', value: 1 },
|
||||
{ label: '李四', value: 2 },
|
||||
{ label: '王二', value: 3 }
|
||||
])
|
||||
// const checkUserAll = ref(false)
|
||||
// const userIndeterminate = ref(true)
|
||||
// const userOptions = ref([
|
||||
// { label: '张三', value: 1 },
|
||||
// { label: '李四', value: 2 },
|
||||
// { label: '王二', value: 3 }
|
||||
// ])
|
||||
|
||||
function userCheckAllChange(val) {
|
||||
form.value.users = val ? userOptions.value.map((it) => it.value) : []
|
||||
userIndeterminate.value = false
|
||||
}
|
||||
// function userCheckAllChange(val) {
|
||||
// form.value.users = val ? userOptions.value.map((it) => it.value) : []
|
||||
// userIndeterminate.value = false
|
||||
// }
|
||||
|
||||
function userCheckedChange(val) {
|
||||
const checkedCount = val.length
|
||||
checkUserAll.value = checkedCount == userOptions.value.length
|
||||
userIndeterminate.value = checkedCount > 0 && checkedCount < userOptions.value.length
|
||||
// function userCheckedChange(val) {
|
||||
// const checkedCount = val.length
|
||||
// checkUserAll.value = checkedCount == userOptions.value.length
|
||||
// userIndeterminate.value = checkedCount > 0 && checkedCount < userOptions.value.length
|
||||
// }
|
||||
|
||||
function getUserList() {
|
||||
console.log('获取列表')
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
@@ -133,6 +180,10 @@ const intentionOptions = ref([
|
||||
{ label: '低意向', value: 20 },
|
||||
{ label: '未知意向', value: 40 }
|
||||
])
|
||||
|
||||
function selectUser(row) {
|
||||
console.log(row)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -68,10 +68,10 @@
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
<el-row class="mt-10px" :gutter="10" justify="space-between">
|
||||
<el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24" class="mb-10px">
|
||||
<!-- <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24" class="mb-10px">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="flex justify-between h-3">
|
||||
<div class="flex justify-between ">
|
||||
<span>本月成交来源</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -79,11 +79,11 @@
|
||||
<Echart :options="pieOptionsData" :height="280" />
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24" class="mb-10px">
|
||||
</el-col> -->
|
||||
<el-col :xl="8" :lg="8" :md="12" :sm="12" :xs="24" class="mb-10px">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="flex justify-between h-3">
|
||||
<div class="flex justify-between">
|
||||
<span>成交率</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -94,10 +94,10 @@
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24" class="mb-10px">
|
||||
<el-col :xl="8" :lg="8" :md="12" :sm="12" :xs="24" class="mb-10px">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="flex justify-between h-3">
|
||||
<div class="flex justify-between items-center">
|
||||
<span>跟进榜Top10</span>
|
||||
<el-radio-group v-model="followDate" size="small">
|
||||
<el-radio label="day">本日</el-radio>
|
||||
@@ -123,18 +123,16 @@
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24" class="mb-10px">
|
||||
<el-col :xl="8" :lg="8" :md="12" :sm="12" :xs="24" class="mb-10px">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="flex justify-between h-3">
|
||||
<span>本月成交榜Top10</span>
|
||||
</div>
|
||||
<div class="flex justify-between"> 本月成交榜Top10 </div>
|
||||
</template>
|
||||
<el-skeleton :loading="loading" animated>
|
||||
<el-table :data="followList" size="small">
|
||||
<el-table-column prop="sort" label="排名" width="50" />
|
||||
<el-table-column prop="name" label="姓名" width="70" />
|
||||
<el-table-column prop="count" label="跟进数量" width="70" />
|
||||
<el-table-column prop="count" label="成交数量" width="70" />
|
||||
<el-table-column prop="orgName" label="所属组织" />
|
||||
</el-table>
|
||||
</el-skeleton>
|
||||
@@ -255,4 +253,8 @@ getAllApi()
|
||||
.number-font {
|
||||
font-family: numberFont !important;
|
||||
}
|
||||
|
||||
:deep(.el-card__header) {
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -30,16 +30,17 @@ export default ({ command, mode }) => {
|
||||
// 端口号
|
||||
port: env.VITE_PORT,
|
||||
host: '0.0.0.0',
|
||||
open: env.VITE_OPEN === 'true'
|
||||
open: env.VITE_OPEN === 'true',
|
||||
// 本地跨域代理. 目前注释的原因:暂时没有用途,server 端已经支持跨域
|
||||
// proxy: {
|
||||
// ['/admin-api']: {
|
||||
// target: env.VITE_BASE_URL,
|
||||
// ws: false,
|
||||
// changeOrigin: true,
|
||||
// rewrite: (path) => path.replace(new RegExp(`^/admin-api`), ''),
|
||||
// },
|
||||
// },
|
||||
proxy: {
|
||||
['/call-api']: {
|
||||
// target: env.VITE_BASE_URL,
|
||||
target: 'http://119.3.87.30:443',
|
||||
ws: false,
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(new RegExp(`^/call-api`), '')
|
||||
}
|
||||
}
|
||||
},
|
||||
// 项目使用的vite插件。 单独提取到build/vite/plugin中管理
|
||||
plugins: createVitePlugins(),
|
||||
|
||||
8647
yarn-error.log
8647
yarn-error.log
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user