salary
qsh 5 months ago
parent 58929c05ef
commit 8a5ae3948a
  1. 2
      .vscode/settings.json
  2. 13
      src/api/call/index.js
  3. 98
      src/components/SSTable/index.vue
  4. 75
      src/components/Search/src/Search.vue
  5. 8
      src/layout/components/UserInfo/src/UserInfo.vue
  6. 2
      src/plugins/cache/index.js
  7. 7
      src/styles/index.scss
  8. 2
      src/views/Clue/Pool/Comp/DialogClue.vue
  9. 11
      src/views/Clue/Pool/Comp/DialogFollow.vue
  10. 2
      src/views/Clue/Pool/Comp/DialogSuccess.vue
  11. 119
      src/views/Clue/Pool/Comp/DrawerClue.vue
  12. 8
      src/views/Clue/Pool/Comp/follow.data.js
  13. 11
      src/views/Clue/Pool/cluePool.data.js
  14. 41
      src/views/Clue/Pool/index.vue
  15. 7
      src/views/Clue/Set/Comp/ClueGet.vue
  16. 215
      src/views/Clue/Set/Comp/ClueSend.vue
  17. 26
      src/views/Home/Index.vue
  18. 19
      vite.config.js
  19. 8647
      yarn-error.log

@ -8,7 +8,7 @@
"source.fixAll.eslint": "explicit" "source.fixAll.eslint": "explicit"
}, },
"[vue]": { "[vue]": {
"editor.defaultFormatter": "Vue.volar" "editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
}, },
"[javascript]": { "[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"

@ -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" trigger="click"
virtual-triggering virtual-triggering
> >
<el-checkbox-group v-model="checkedColumns"> <el-checkbox-group v-model="checkedColumns" @change="confirm">
<el-checkbox v-for="item in tableColumns" :key="item.field" :label="item.field"> <draggable
{{ item.label }} v-model="allColumns"
</el-checkbox> 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-checkbox-group>
</el-popover> </el-popover>
</div> </div>
@ -37,12 +47,19 @@
</template> </template>
<script setup> <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({ const props = defineProps({
tableObject: { type: Object, default: () => ({ tableList: [] }) }, tableObject: { type: Object, default: () => ({ tableList: [] }) },
tableColumns: { type: Array, default: () => [] } 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) const currentPage = ref(props.tableObject?.currentPage || 1)
@ -50,9 +67,12 @@ const pageSize = ref(props.tableObject?.pageSize || 20)
const ColumnSetting = ref() const ColumnSetting = ref()
const TableColumnPop = ref() const TableColumnPop = ref()
// 使
const allColumns = ref({})
//
const checkedColumns = ref([]) const checkedColumns = ref([])
// ,使
function getList({ page, limit }) { function getList({ page, limit }) {
emit('update:tableObject', { ...props.tableObject, currentPage: page, pageSize: limit }) emit('update:tableObject', { ...props.tableObject, currentPage: page, pageSize: limit })
nextTick(() => { nextTick(() => {
@ -60,9 +80,75 @@ function getList({ page, limit }) {
}) })
} }
// ""
const clickSetting = () => { const clickSetting = () => {
unref(TableColumnPop).TableColumnPop?.delayHide?.() 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> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

@ -7,6 +7,13 @@ import { findIndex } from '@/utils'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import { FormSchema } from '@/types/form' 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 { t } = useI18n()
const props = defineProps({ const props = defineProps({
@ -43,8 +50,16 @@ const emit = defineEmits(['search', 'reset'])
const visible = ref(true) const visible = ref(true)
const SchemaSetting = ref()
const SettingPop = ref()
const checkedSchema = ref([])
// 使
const usedSchema = ref([])
const newSchema = computed(() => { const newSchema = computed(() => {
let schema: FormSchema[] = cloneDeep(props.schema) let schema: FormSchema[] = cloneDeep(usedSchema.value)
if (props.expand && props.expandField && !unref(visible)) { if (props.expand && props.expandField && !unref(visible)) {
const index = findIndex(schema, (v: FormSchema) => v.field === props.expandField) const index = findIndex(schema, (v: FormSchema) => v.field === props.expandField)
if (index > -1) { if (index > -1) {
@ -65,6 +80,43 @@ const newSchema = computed(() => {
return schema 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({ const { register, elFormRef, methods } = useForm({
model: props.model || {} model: props.model || {}
}) })
@ -96,6 +148,8 @@ const setVisible = () => {
unref(elFormRef)?.resetFields() unref(elFormRef)?.resetFields()
visible.value = !unref(visible) visible.value = !unref(visible)
} }
initSearch()
</script> </script>
<template> <template>
@ -114,6 +168,25 @@ const setVisible = () => {
> >
<template #action> <template #action>
<div v-if="layout === 'inline'"> <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"颜色变淡一点 --> <!-- update by 芋艿去除搜索的 type="primary"颜色变淡一点 -->
<ElButton v-if="showSearch" @click="search"> <ElButton v-if="showSearch" @click="search">
<Icon class="mr-5px" icon="ep:search" /> <Icon class="mr-5px" icon="ep:search" />

@ -52,7 +52,13 @@ const toDocument = () => {
<ElDropdown :class="prefixCls" trigger="click"> <ElDropdown :class="prefixCls" trigger="click">
<div class="flex items-center"> <div class="flex items-center">
<img :src="avatar" alt="" class="w-[calc(var(--logo-height)-25px)] rounded-[50%]" /> <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 }} {{ userName }}
</span> </span>
</div> </div>

@ -1,5 +1,5 @@
import router from '@/router' 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}` let name = `${appName}-${import.meta.env.VITE_APP_ENV}`

@ -17,7 +17,9 @@
} }
.el-dialog__body { .el-dialog__body {
overflow-y: auto;
padding-top: 0; padding-top: 0;
max-height: calc(100% - 118px);
} }
/* nprogress 适配 element-plus 的主题色 */ /* nprogress 适配 element-plus 的主题色 */
@ -48,3 +50,8 @@
.crud-form-item .el-input__wrapper { .crud-form-item .el-input__wrapper {
width: 100%; width: 100%;
} }
.el-dialog {
margin-top: 5vh;
max-height: 90vh;
}

@ -1,5 +1,5 @@
<template> <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-tabs v-model="tabName">
<el-tab-pane label="线索信息" name="info"> <el-tab-pane label="线索信息" name="info">
<Form <Form

@ -28,6 +28,12 @@
</el-collapse> </el-collapse>
</div> </div>
</div> </div>
<template #footer>
<span>
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="handleSave"> </el-button>
</span>
</template>
</el-dialog> </el-dialog>
</template> </template>
@ -256,6 +262,11 @@ const activeQues = ref('')
function filterList() { function filterList() {
showList.value = resultList.filter((it) => it.question.includes(keyword.value)) showList.value = resultList.filter((it) => it.question.includes(keyword.value))
} }
function handleSave() {
console.log('保存成功')
dialogVisible.value = false
}
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

@ -1,5 +1,5 @@
<template> <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" /> <Descriptions :data="info" :schema="schema" :columns="2" />
<el-form :model="form" ref="formRef" :rules="rules" label-width="80px" class="mt-20px"> <el-form :model="form" ref="formRef" :rules="rules" label-width="80px" class="mt-20px">
<el-row :gutter="20"> <el-row :gutter="20">

@ -8,6 +8,7 @@
:destroy-on-close="true" :destroy-on-close="true"
:show-close="true" :show-close="true"
:wrapperClosable="true" :wrapperClosable="true"
@close="destroyMap"
> >
<!-- header --> <!-- header -->
<el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated>
@ -51,7 +52,7 @@
<el-button type="danger" plain>删除</el-button> <el-button type="danger" plain>删除</el-button>
</div> </div>
</div> </div>
<div v-dompurify-html="followContent"></div> <div>{{ followContent }}</div>
<div class="flex mt-10px" style="align-items: center"> <div class="flex mt-10px" style="align-items: center">
<div class="flex" style="color: #666; align-items: center"> <div class="flex" style="color: #666; align-items: center">
<Icon icon="ep:clock" class="mr-5px" /> <Icon icon="ep:clock" class="mr-5px" />
@ -78,7 +79,7 @@
<el-button type="danger" plain>删除</el-button> <el-button type="danger" plain>删除</el-button>
</div> </div>
</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 mt-10px" style="align-items: center">
<div class="flex" style="color: #666; align-items: center"> <div class="flex" style="color: #666; align-items: center">
<Icon icon="ep:clock" class="mr-5px" /> <Icon icon="ep:clock" class="mr-5px" />
@ -95,22 +96,11 @@
</el-timeline> </el-timeline>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="详细信息" name="infoDetail"> <el-tab-pane label="详细信息" name="infoDetail">
<el-descriptions :column="2" border> <Descriptions :data="info" :schema="schema" :columns="2" />
<el-descriptions-item min-width="150px" label="线索名称">{{ <el-checkbox v-model="showSchool" :label="true" @change="handleShowSchool"
info.name >展示场地</el-checkbox
}}</el-descriptions-item> >
<el-descriptions-item min-width="150px" label="联系方式" <div id="dialogMap" class="mt-20px" style="height: 400px; width: 100%"></div>
>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>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="操作记录" name="operateRecord"> <el-tab-pane label="操作记录" name="operateRecord">
<el-timeline> <el-timeline>
@ -188,10 +178,42 @@
<script setup> <script setup>
import DialogFollow from './DialogFollow.vue' 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 show = ref(false)
const info = ref(null) const info = ref(null)
const loading = ref(false) 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 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>` 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) { function open(row) {
info.value = row info.value = row
show.value = true 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') const infoIndex = ref('followRecord')
@ -229,6 +307,11 @@ function addFollow() {
function updateFollow() { function updateFollow() {
followRef.value.open('update', { nextFollowTime: '2024-04-01 12:12' }) followRef.value.open('update', { nextFollowTime: '2024-04-01 12:12' })
} }
function destroyMap() {
dialogMap.value = null
aMap.value = null
}
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

@ -18,7 +18,7 @@ const crudSchemas = reactive([
type: 'datetime', type: 'datetime',
format: 'YYYY-MM-DD HH:mm', format: 'YYYY-MM-DD HH:mm',
valueFormat: 'YYYY-MM-DD HH:mm', valueFormat: 'YYYY-MM-DD HH:mm',
placeholder: '创建时间' placeholder: '本次跟进时间'
} }
} }
}, },
@ -45,7 +45,11 @@ const crudSchemas = reactive([
field: 'remark', field: 'remark',
isTable: true, isTable: true,
form: { form: {
component: 'Editor', component: 'Input',
componentProps: {
type: 'textarea',
autosize: { minRows: 5, maxRows: 10 }
},
colProps: { colProps: {
span: 24 span: 24
} }

@ -28,6 +28,12 @@ const crudSchemas = reactive([
isSearch: true, isSearch: true,
isTable: true isTable: true
}, },
{
label: '线索位置',
field: 'address',
isSearch: true,
isTable: true
},
{ {
label: '线索来源', label: '线索来源',
field: 'resource', field: 'resource',
@ -183,6 +189,11 @@ const crudSchemas = reactive([
placeholder: '创建时间' placeholder: '创建时间'
} }
} }
},
{
label: '跟进记录',
field: 'followRecord',
isTable: true
} }
]) ])
export const { allSchemas } = useCrudSchemas(crudSchemas) export const { allSchemas } = useCrudSchemas(crudSchemas)

@ -31,7 +31,7 @@
</el-tabs> </el-tabs>
<div class="absolute" style="right: 10px; top: 0"> <div class="absolute" style="right: 10px; top: 0">
<el-button plain>导入</el-button> <el-button plain>导入</el-button>
<el-button type="primary" @click="handleInsert">新增</el-button> <el-button type="primary" @click="handleInsert">新增线索</el-button>
</div> </div>
</div> </div>
<!-- 搜索工作栏 --> <!-- 搜索工作栏 -->
@ -47,14 +47,28 @@
v-model:tableObject="tableObject" v-model:tableObject="tableObject"
:tableColumns="allSchemas.tableColumns" :tableColumns="allSchemas.tableColumns"
@get-list="getTableList" @get-list="getTableList"
@get-checked-columns="getCheckedColumns"
> >
<el-table-column <el-table-column
v-for="item in allSchemas.tableColumns" v-for="item in showColumns"
:key="item.field" :key="item.field"
:prop="item.field" :prop="item.field"
:label="item.label" :label="item.label"
min-width="120px" 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"> <el-table-column label="操作" width="200px" fixed="right">
<template #default="scope"> <template #default="scope">
<el-button type="primary" link @click="handleDetail(scope.row)">详情</el-button> <el-button type="primary" link @click="handleDetail(scope.row)">详情</el-button>
@ -68,6 +82,7 @@
<DialogClue ref="formRef" /> <DialogClue ref="formRef" />
<DrawerClue ref="drawerRef" /> <DrawerClue ref="drawerRef" />
<DialogSuccess ref="successRef" /> <DialogSuccess ref="successRef" />
<DialogFollow ref="followRef" />
</div> </div>
</template> </template>
@ -76,6 +91,7 @@ import { allSchemas } from './cluePool.data'
import DialogClue from './Comp/DialogClue.vue' import DialogClue from './Comp/DialogClue.vue'
import DrawerClue from './Comp/DrawerClue.vue' import DrawerClue from './Comp/DrawerClue.vue'
import DialogSuccess from './Comp/DialogSuccess.vue' import DialogSuccess from './Comp/DialogSuccess.vue'
import DialogFollow from './Comp/DialogFollow.vue'
const searchForm = ref({ const searchForm = ref({
mode: '2' mode: '2'
@ -83,6 +99,7 @@ const searchForm = ref({
const formRef = ref() const formRef = ref()
const drawerRef = ref() const drawerRef = ref()
const successRef = ref() const successRef = ref()
const followRef = ref()
// const { tableObject, tableMethods } = useTable({ // const { tableObject, tableMethods } = useTable({
// getListApi: MailTemplateApi.getMailTemplatePage, // // getListApi: MailTemplateApi.getMailTemplatePage, //
@ -90,12 +107,20 @@ const successRef = ref()
// }) // })
const tableObject = ref({ const tableObject = ref({
tableList: [{ name: '测试', contact: '18888888888' }], tableList: [{ name: '测试', contact: '17318531354' }],
loading: false, loading: false,
total: 1, total: 1,
pageSize: 20, pageSize: 20,
currentPage: 1 currentPage: 1
}) })
const showColumns = ref([])
//
function getCheckedColumns(list) {
showColumns.value = list
}
const setSearchParams = function () { const setSearchParams = function () {
// //
} }
@ -117,6 +142,14 @@ function handleDetail(row) {
drawerRef.value.open(row) drawerRef.value.open(row)
} }
function handleFollow(row) {
followRef.value.open('create', row)
}
async function makeCall(phone) {
console.log('打电话:' + phone)
}
// //
function handleSuccess(row) { function handleSuccess(row) {
successRef.value.open(row) successRef.value.open(row)

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<el-table :data="list" border stripe> <el-table :data="list" border>
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="来源名称"> <el-table-column label="来源名称">
<template #default="{ row }"> <template #default="{ row }">
@ -12,6 +12,11 @@
<el-input v-model="row.link" placeholder="请输入" :clearable="false" /> <el-input v-model="row.link" placeholder="请输入" :clearable="false" />
</template> </template>
</el-table-column> </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"> <el-table-column label="操作" width="100px">
<template #default="{ $index }"> <template #default="{ $index }">
<el-button type="primary" style="padding: 0px" text @click="handleRemove($index)" <el-button type="primary" style="padding: 0px" text @click="handleRemove($index)"

@ -1,82 +1,125 @@
<template> <template>
<el-form :model="form" ref="sendForm" :rules="rules" label-width="100px" :inline="false"> <div class="flex">
<el-form-item label="是否自动分配"> <div class="mr-20px" style="width: 500px">
<el-radio-group v-model="form.isAuto"> <el-input
<el-radio :label="1"> 自动分配 </el-radio> v-model="searchForm.keyword"
<el-radio :label="0"> 手动分配 </el-radio> placeholder="请输入关键字查询"
</el-radio-group> clearable
</el-form-item> class="mb-10px"
<div v-if="form.isAuto"> @keyup.enter="getUserList"
<el-form-item label="分配对象"> />
<div>
<el-checkbox <el-table :data="userList" @cell-click="selectUser">
v-model="checkUserAll" <el-table-column prop="name" label="员工姓名" />
:indeterminate="userIndeterminate" <el-table-column prop="phone" label="电话" />
@change="userCheckAllChange" <el-table-column prop="workNum" label="工号" />
> </el-table>
全选 <!-- 分页 -->
</el-checkbox> <Pagination
<el-checkbox-group v-model="form.users" @change="userCheckedChange"> v-model:limit="searchForm.pageSize"
v-model:page="searchForm.pageNum"
:total="total"
@pagination="getUserList"
/>
</div>
<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 <el-checkbox
v-for="(item, index) in userOptions" v-model="checkUserAll"
:key="index" :indeterminate="userIndeterminate"
:label="item.value" @change="userCheckAllChange"
:value="item.value"
> >
{{ item.label }} 全选
</el-checkbox> </el-checkbox>
</el-checkbox-group> <el-checkbox-group v-model="form.users" @change="userCheckedChange">
</div> <el-checkbox
</el-form-item> v-for="(item, index) in userOptions"
<el-form-item label="线索来源"> :key="index"
<div> :label="item.value"
<el-checkbox :value="item.value"
v-model="checkResourceAll" >
:indeterminate="resourceIndeterminate" {{ item.label }}
@change="resourceCheckAllChange" </el-checkbox>
> </el-checkbox-group>
全选 </div>
</el-checkbox> </el-form-item> -->
<el-checkbox-group v-model="form.resource" @change="resourceCheckedChange"> <el-form-item label="线索来源">
<div>
<el-checkbox <el-checkbox
v-for="(item, index) in resourceOptions" v-model="checkResourceAll"
:key="index" :indeterminate="resourceIndeterminate"
:label="item.value" @change="resourceCheckAllChange"
:value="item.value"
> >
{{ item.label }} 全选
</el-checkbox> </el-checkbox>
</el-checkbox-group> <el-checkbox-group v-model="form.resource" @change="resourceCheckedChange">
</div> <el-checkbox
</el-form-item> v-for="(item, index) in resourceOptions"
<el-form-item label="权重配置"> :key="index"
<div> :label="item.value"
<div v-for="(item, index) in intentionOptions" :key="index" class="flex mb-10px"> :value="item.value"
<div class="mr-15px" style="width: 100px">{{ item.label }}</div> >
<el-input v-model="item.value" type="number" placeholder="请输入权重"> {{ item.label }}
<template #suffix> % </template> </el-checkbox>
</el-input> </el-checkbox-group>
</div> </div>
</div> </el-form-item>
</el-form-item> <el-form-item label="权重配置">
<el-form-item label="分配时间"> <div>
<el-time-picker <el-radio-group v-model="form.isRandom">
v-model="form.sendTime" <el-radio :label="1">
placeholder="任意时间点" <Tooltip message="根据剩余的线索平均分配到未分配线索的所有人" />
format="HH:mm" 平均分配
value-format="HH:mm" </el-radio>
:clearable="false" <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-item>
</div> </el-form>
<el-form-item> </div>
<el-button type="primary" @click="onSubmit">保存</el-button>
<el-button>重置</el-button>
</el-form-item>
</el-form>
</template> </template>
<script setup> <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({ const form = ref({
isAuto: 1, isAuto: 1,
users: [1, 2], users: [1, 2],
@ -85,23 +128,27 @@ const form = ref({
}) })
const rules = ref({}) const rules = ref({})
const checkUserAll = ref(false) // const checkUserAll = ref(false)
const userIndeterminate = ref(true) // const userIndeterminate = ref(true)
const userOptions = ref([ // const userOptions = ref([
{ label: '张三', value: 1 }, // { label: '', value: 1 },
{ label: '李四', value: 2 }, // { label: '', value: 2 },
{ label: '王二', value: 3 } // { label: '', value: 3 }
]) // ])
function userCheckAllChange(val) { // function userCheckAllChange(val) {
form.value.users = val ? userOptions.value.map((it) => it.value) : [] // form.value.users = val ? userOptions.value.map((it) => it.value) : []
userIndeterminate.value = false // userIndeterminate.value = false
} // }
function userCheckedChange(val) { // function userCheckedChange(val) {
const checkedCount = val.length // const checkedCount = val.length
checkUserAll.value = checkedCount == userOptions.value.length // checkUserAll.value = checkedCount == userOptions.value.length
userIndeterminate.value = checkedCount > 0 && checkedCount < userOptions.value.length // userIndeterminate.value = checkedCount > 0 && checkedCount < userOptions.value.length
// }
function getUserList() {
console.log('获取列表')
} }
function onSubmit() { function onSubmit() {
@ -133,6 +180,10 @@ const intentionOptions = ref([
{ label: '低意向', value: 20 }, { label: '低意向', value: 20 },
{ label: '未知意向', value: 40 } { label: '未知意向', value: 40 }
]) ])
function selectUser(row) {
console.log(row)
}
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

@ -68,10 +68,10 @@
</el-skeleton> </el-skeleton>
</el-card> </el-card>
<el-row class="mt-10px" :gutter="10" justify="space-between"> <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"> <el-card shadow="never">
<template #header> <template #header>
<div class="flex justify-between h-3"> <div class="flex justify-between ">
<span>本月成交来源</span> <span>本月成交来源</span>
</div> </div>
</template> </template>
@ -79,11 +79,11 @@
<Echart :options="pieOptionsData" :height="280" /> <Echart :options="pieOptionsData" :height="280" />
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</el-col> </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"> <el-card shadow="never">
<template #header> <template #header>
<div class="flex justify-between h-3"> <div class="flex justify-between">
<span>成交率</span> <span>成交率</span>
</div> </div>
</template> </template>
@ -94,10 +94,10 @@
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</el-col> </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"> <el-card shadow="never">
<template #header> <template #header>
<div class="flex justify-between h-3"> <div class="flex justify-between items-center">
<span>跟进榜Top10</span> <span>跟进榜Top10</span>
<el-radio-group v-model="followDate" size="small"> <el-radio-group v-model="followDate" size="small">
<el-radio label="day">本日</el-radio> <el-radio label="day">本日</el-radio>
@ -123,18 +123,16 @@
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</el-col> </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"> <el-card shadow="never">
<template #header> <template #header>
<div class="flex justify-between h-3"> <div class="flex justify-between"> 本月成交榜Top10 </div>
<span>本月成交榜Top10</span>
</div>
</template> </template>
<el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated>
<el-table :data="followList" size="small"> <el-table :data="followList" size="small">
<el-table-column prop="sort" label="排名" width="50" /> <el-table-column prop="sort" label="排名" width="50" />
<el-table-column prop="name" label="姓名" width="70" /> <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-column prop="orgName" label="所属组织" />
</el-table> </el-table>
</el-skeleton> </el-skeleton>
@ -255,4 +253,8 @@ getAllApi()
.number-font { .number-font {
font-family: numberFont !important; font-family: numberFont !important;
} }
:deep(.el-card__header) {
padding: 10px;
}
</style> </style>

@ -30,16 +30,17 @@ export default ({ command, mode }) => {
// 端口号 // 端口号
port: env.VITE_PORT, port: env.VITE_PORT,
host: '0.0.0.0', host: '0.0.0.0',
open: env.VITE_OPEN === 'true' open: env.VITE_OPEN === 'true',
// 本地跨域代理. 目前注释的原因:暂时没有用途,server 端已经支持跨域 // 本地跨域代理. 目前注释的原因:暂时没有用途,server 端已经支持跨域
// proxy: { proxy: {
// ['/admin-api']: { ['/call-api']: {
// target: env.VITE_BASE_URL, // target: env.VITE_BASE_URL,
// ws: false, target: 'http://119.3.87.30:443',
// changeOrigin: true, ws: false,
// rewrite: (path) => path.replace(new RegExp(`^/admin-api`), ''), changeOrigin: true,
// }, rewrite: (path) => path.replace(new RegExp(`^/call-api`), '')
// }, }
}
}, },
// 项目使用的vite插件。 单独提取到build/vite/plugin中管理 // 项目使用的vite插件。 单独提取到build/vite/plugin中管理
plugins: createVitePlugins(), plugins: createVitePlugins(),

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save