Browse Source

1

yuhongzhe
于宏哲PHP 11 months ago
parent
commit
275211cb83
  1. 4
      admin/components.d.ts
  2. 30
      admin/src/app/api/customer_resources.ts
  3. 27
      admin/src/app/api/six_speed.ts
  4. 12
      admin/src/app/api/sys.ts
  5. 72
      admin/src/app/lang/zh-cn/customer_resources.customer_resources.json
  6. 60
      admin/src/app/lang/zh-cn/six_speed.six_speed.json
  7. 1109
      admin/src/app/views/customer_resources/components/customer-resources-edit.vue
  8. 422
      admin/src/app/views/customer_resources/customer_resources.vue
  9. 527
      admin/src/app/views/six_speed/components/six-speed-edit.vue
  10. 468
      admin/src/app/views/six_speed/six_speed.vue
  11. 46
      niucloud/app/adminapi/controller/customer_resources/CustomerResources.php
  12. 34
      niucloud/app/adminapi/controller/six_speed/SixSpeed.php
  13. 4
      niucloud/app/adminapi/route/customer_resources.php
  14. 5
      niucloud/app/adminapi/route/six_speed.php
  15. 28
      niucloud/app/common.php
  16. 6
      niucloud/app/model/customer_resources/CustomerResources.php
  17. 172
      niucloud/app/model/six_speed/SixSpeed.php
  18. 151
      niucloud/app/service/admin/customer_resources/CustomerResourcesService.php
  19. 16
      niucloud/app/service/admin/six_speed/SixSpeedService.php
  20. 8
      niucloud/app/validate/six_speed/SixSpeed.php

4
admin/components.d.ts

@ -10,7 +10,6 @@ declare module '@vue/runtime-core' {
Attachment: typeof import('./src/components/upload-attachment/attachment.vue')['default'] Attachment: typeof import('./src/components/upload-attachment/attachment.vue')['default']
DiyLink: typeof import('./src/components/diy-link/index.vue')['default'] DiyLink: typeof import('./src/components/diy-link/index.vue')['default']
Editor: typeof import('./src/components/editor/index.vue')['default'] Editor: typeof import('./src/components/editor/index.vue')['default']
ElAlert: typeof import('element-plus/es')['ElAlert']
ElAside: typeof import('element-plus/es')['ElAside'] ElAside: typeof import('element-plus/es')['ElAside']
ElAvatar: typeof import('element-plus/es')['ElAvatar'] ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
@ -45,7 +44,6 @@ declare module '@vue/runtime-core' {
ElPopover: typeof import('element-plus/es')['ElPopover'] ElPopover: typeof import('element-plus/es')['ElPopover']
ElRadio: typeof import('element-plus/es')['ElRadio'] ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElResult: typeof import('element-plus/es')['ElResult']
ElRow: typeof import('element-plus/es')['ElRow'] ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect'] ElSelect: typeof import('element-plus/es')['ElSelect']
@ -58,8 +56,6 @@ declare module '@vue/runtime-core' {
ElTabPane: typeof import('element-plus/es')['ElTabPane'] ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs'] ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag'] ElTag: typeof import('element-plus/es')['ElTag']
ElTimeline: typeof import('element-plus/es')['ElTimeline']
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree'] ElTree: typeof import('element-plus/es')['ElTree']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect'] ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']

30
admin/src/app/api/customer_resources.ts

@ -1,5 +1,9 @@
import request from '@/utils/request' import request from '@/utils/request'
// USER_CODE_BEGIN -- customer_resources // USER_CODE_BEGIN -- customer_resources
/** /**
* *
@ -7,7 +11,7 @@ import request from '@/utils/request'
* @returns * @returns
*/ */
export function getCustomerResourcesList(params: Record<string, any>) { export function getCustomerResourcesList(params: Record<string, any>) {
return request.get(`customer_resources/customer_resources`, { params }) return request.get(`customer_resources/customer_resources`, {params})
} }
/** /**
@ -16,7 +20,7 @@ export function getCustomerResourcesList(params: Record<string, any>) {
* @returns * @returns
*/ */
export function getCustomerResourcesInfo(id: number) { export function getCustomerResourcesInfo(id: number) {
return request.get(`customer_resources/customer_resources/${id}`) return request.get(`customer_resources/customer_resources/${id}`);
} }
/** /**
@ -25,10 +29,7 @@ export function getCustomerResourcesInfo(id: number) {
* @returns * @returns
*/ */
export function addCustomerResources(params: Record<string, any>) { export function addCustomerResources(params: Record<string, any>) {
return request.post('customer_resources/customer_resources', params, { return request.post('customer_resources/customer_resources', params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -38,11 +39,7 @@ export function addCustomerResources(params: Record<string, any>) {
* @returns * @returns
*/ */
export function editCustomerResources(params: Record<string, any>) { export function editCustomerResources(params: Record<string, any>) {
return request.put( return request.put(`customer_resources/customer_resources/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
`customer_resources/customer_resources/${params.id}`,
params,
{ showErrorMessage: true, showSuccessMessage: true }
)
} }
/** /**
@ -51,14 +48,13 @@ export function editCustomerResources(params: Record<string, any>) {
* @returns * @returns
*/ */
export function deleteCustomerResources(id: number) { export function deleteCustomerResources(id: number) {
return request.delete(`customer_resources/customer_resources/${id}`, { return request.delete(`customer_resources/customer_resources/${id}`, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
export function getWithCampusList(params: Record<string, any>) { export function getWithPersonnelList(params: Record<string,any>){
return request.get('customer_resources/campus_all', { params }) return request.get('customer_resources/personnel_all', {params})
}export function getWithCampusList(params: Record<string,any>){
return request.get('customer_resources/campus_all', {params})
} }
// USER_CODE_END -- customer_resources // USER_CODE_END -- customer_resources

27
admin/src/app/api/six_speed.ts

@ -1,5 +1,7 @@
import request from '@/utils/request' import request from '@/utils/request'
// USER_CODE_BEGIN -- six_speed // USER_CODE_BEGIN -- six_speed
/** /**
* *
@ -7,7 +9,7 @@ import request from '@/utils/request'
* @returns * @returns
*/ */
export function getSixSpeedList(params: Record<string, any>) { export function getSixSpeedList(params: Record<string, any>) {
return request.get(`six_speed/six_speed`, { params }) return request.get(`six_speed/six_speed`, {params})
} }
/** /**
@ -16,7 +18,7 @@ export function getSixSpeedList(params: Record<string, any>) {
* @returns * @returns
*/ */
export function getSixSpeedInfo(id: number) { export function getSixSpeedInfo(id: number) {
return request.get(`six_speed/six_speed/${id}`) return request.get(`six_speed/six_speed/${id}`);
} }
/** /**
@ -25,10 +27,7 @@ export function getSixSpeedInfo(id: number) {
* @returns * @returns
*/ */
export function addSixSpeed(params: Record<string, any>) { export function addSixSpeed(params: Record<string, any>) {
return request.post('six_speed/six_speed', params, { return request.post('six_speed/six_speed', params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -38,10 +37,7 @@ export function addSixSpeed(params: Record<string, any>) {
* @returns * @returns
*/ */
export function editSixSpeed(params: Record<string, any>) { export function editSixSpeed(params: Record<string, any>) {
return request.put(`six_speed/six_speed/${params.id}`, params, { return request.put(`six_speed/six_speed/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -50,10 +46,13 @@ export function editSixSpeed(params: Record<string, any>) {
* @returns * @returns
*/ */
export function deleteSixSpeed(id: number) { export function deleteSixSpeed(id: number) {
return request.delete(`six_speed/six_speed/${id}`, { return request.delete(`six_speed/six_speed/${id}`, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true, }
showSuccessMessage: true,
}) export function getWithPersonnelList(params: Record<string,any>){
return request.get('six_speed/personnel_all', {params})
}export function getWithCustomerResourcesList(params: Record<string,any>){
return request.get('six_speed/customer_resources_all', {params})
} }
// USER_CODE_END -- six_speed // USER_CODE_END -- six_speed

12
admin/src/app/api/sys.ts

@ -720,3 +720,15 @@ export function deleteExport(id: number) {
export function getInstallConfig() { export function getInstallConfig() {
return request.get('sys/install/config') return request.get('sys/install/config')
} }
//业绩配置
export function getYjpzConfig() {
return request.get('sys/get_yjpz_config')
}
export function yjpzConfig(params: Record<string, any>) {
return request.post(`sys/yjpz_config`, params)
}

72
admin/src/app/lang/zh-cn/customer_resources.customer_resources.json

@ -1,38 +1,38 @@
{ {
"source": "来源", "source":"来源",
"sourcePlaceholder": "请输入来源", "sourcePlaceholder":"请输入来源",
"sourceChannel": "来源渠道", "sourceChannel":"来源渠道",
"sourceChannelPlaceholder": "请输入来源渠道", "sourceChannelPlaceholder":"请输入来源渠道",
"consultant": "顾问", "consultant":"顾问",
"name": "姓名", "name":"姓名",
"namePlaceholder": "请输入姓名", "namePlaceholder":"请输入姓名",
"age": "年龄", "age":"年龄",
"agePlaceholder": "请输入年龄", "agePlaceholder":"请输入年龄",
"gender": "性别", "gender":"性别",
"genderPlaceholder": "请输入性别", "genderPlaceholder":"请输入性别",
"phoneNumber": "联系电话", "phoneNumber":"联系电话",
"phoneNumberPlaceholder": "请输入联系电话", "phoneNumberPlaceholder":"请输入联系电话",
"demand": "需求", "demand":"需求",
"demandPlaceholder": "请输入需求", "demandPlaceholder":"请输入需求",
"purchasingPower": "购买力", "purchasingPower":"购买力",
"purchasingPowerPlaceholder": "请输入购买力", "purchasingPowerPlaceholder":"请输入购买力",
"cognitiveIdea": "认知理念", "cognitiveIdea":"认知理念",
"cognitiveIdeaPlaceholder": "请输入认知理念", "cognitiveIdeaPlaceholder":"请输入认知理念",
"optionalClassTime": "可选上课时间", "optionalClassTime":"可选上课时间",
"optionalClassTimePlaceholder": "请输入可选上课时间", "optionalClassTimePlaceholder":"请输入可选上课时间",
"distance": "距离", "distance":"距离",
"distancePlaceholder": "请输入距离", "distancePlaceholder":"请输入距离",
"decisionMaker": "决策人", "decisionMaker":"决策人",
"decisionMakerPlaceholder": "请输入决策人", "decisionMakerPlaceholder":"请输入决策人",
"initialIntent": "客户初步意向度", "initialIntent":"客户初步意向度",
"initialIntentPlaceholder": "请输入客户初步意向度", "initialIntentPlaceholder":"请输入客户初步意向度",
"campus": "所属校区", "campus":"所属校区",
"campusPlaceholder": "请输入所属校区", "campusPlaceholder":"请输入所属校区",
"status": "客户状态", "status":"客户状态",
"statusPlaceholder": "请输入客户状态", "statusPlaceholder":"请输入客户状态",
"addCustomerResources": "添加客户资源", "addCustomerResources":"添加客户资源",
"updateCustomerResources": "编辑客户资源", "updateCustomerResources":"编辑客户资源",
"customerResourcesDeleteTips": "确定要删除该数据吗?", "customerResourcesDeleteTips":"确定要删除该数据吗?",
"startDate": "请选择开始时间", "startDate":"请选择开始时间",
"endDate": "请选择结束时间" "endDate":"请选择结束时间"
} }

60
admin/src/app/lang/zh-cn/six_speed.six_speed.json

@ -1,35 +1,29 @@
{ {
"id": "编号", "purchasePower":"需求购买力",
"idPlaceholder": "请输入编号", "purchasePowerPlaceholder":"请输入需求购买力",
"purchasePower": "需求购买力", "conceptAwareness":"认知理念",
"purchasePowerPlaceholder": "请输入需求购买力", "conceptAwarenessPlaceholder":"请输入认知理念",
"conceptAwareness": "认知理念", "preferredClassTime":"可选上课时间",
"conceptAwarenessPlaceholder": "请输入认知理念", "preferredClassTimePlaceholder":"请输入可选上课时间",
"preferredClassTime": "可选上课时间", "distance":"距离",
"preferredClassTimePlaceholder": "请输入可选上课时间", "distancePlaceholder":"请输入距离",
"distance": "距离", "communication":"沟通备注",
"distancePlaceholder": "请输入距离", "communicationPlaceholder":"请输入沟通备注",
"communication": "沟通备注", "promisedVisitTime":"承诺到访时间",
"communicationPlaceholder": "请输入沟通备注", "promisedVisitTimePlaceholder":"请输入承诺到访时间",
"promisedVisitTime": "承诺到访时间", "actualVisitTime":"实际到访时间",
"promisedVisitTimePlaceholder": "请输入承诺到访时间", "actualVisitTimePlaceholder":"请输入实际到访时间",
"actualVisitTime": "实际到访时间", "callIntent":"电话后的意向程度",
"actualVisitTimePlaceholder": "请输入实际到访时间", "callIntentPlaceholder":"请输入电话后的意向程度",
"callIntent": "电话后的意向程度: low-低, medium-中, high-高", "firstVisitStatus":"一访情况",
"callIntentPlaceholder": "请输入电话后的意向程度: low-低, medium-中, high-高", "firstVisitStatusPlaceholder":"请输入一访情况",
"firstVisitStatus": "一访情况", "secondVisitStatus":"二访情况",
"firstVisitStatusPlaceholder": "请输入一访情况", "secondVisitStatusPlaceholder":"请输入二访情况",
"secondVisitStatus": "二访情况", "isClosed":"是否关单",
"secondVisitStatusPlaceholder": "请输入二访情况", "isClosedPlaceholder":"请输入是否关单",
"isClosed": "是否关单: 1-是, 0-否", "addSixSpeed":"添加六一速",
"isClosedPlaceholder": "请输入是否关单: 1-是, 0-否", "updateSixSpeed":"编辑六一速",
"staffId": "人员ID", "sixSpeedDeleteTips":"确定要删除该数据吗?",
"staffIdPlaceholder": "请输入人员ID", "startDate":"请选择开始时间",
"resourceId": "资源ID", "endDate":"请选择结束时间"
"resourceIdPlaceholder": "请输入资源ID",
"addSixSpeed": "添加六一速",
"updateSixSpeed": "编辑六一速",
"sixSpeedDeleteTips": "确定要删除该数据吗?",
"startDate": "请选择开始时间",
"endDate": "请选择结束时间"
} }

1109
admin/src/app/views/customer_resources/components/customer-resources-edit.vue

File diff suppressed because it is too large

422
admin/src/app/views/customer_resources/customer_resources.vue

@ -1,179 +1,102 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span> <div class="flex justify-between items-center">
<el-button type="primary" @click="addEvent"> <span class="text-lg">{{pageName}}</span>
{{ t('addCustomerResources') }} <el-button type="primary" @click="addEvent">
</el-button> {{ t('addCustomerResources') }}
</div> </el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap" <el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
shadow="never" <el-form :inline="true" :model="customerResourcesTable.searchParam" ref="searchFormRef">
> <el-form-item :label="t('name')" prop="name">
<el-form <el-input v-model="customerResourcesTable.searchParam.name" :placeholder="t('namePlaceholder')" />
:inline="true" </el-form-item>
:model="customerResourcesTable.searchParam" <el-form-item :label="t('phoneNumber')" prop="phone_number">
ref="searchFormRef" <el-input v-model="customerResourcesTable.searchParam.phone_number" :placeholder="t('phoneNumberPlaceholder')" />
> </el-form-item>
<el-form-item :label="t('name')" prop="name"> <el-form-item>
<el-input <el-button type="primary" @click="loadCustomerResourcesList()">{{ t('search') }}</el-button>
v-model="customerResourcesTable.searchParam.name" <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
:placeholder="t('namePlaceholder')" </el-form-item>
/> </el-form>
</el-form-item> </el-card>
<el-form-item :label="t('phoneNumber')" prop="phone_number">
<el-input <div class="mt-[10px]">
v-model="customerResourcesTable.searchParam.phone_number" <el-table :data="customerResourcesTable.data" size="large" v-loading="customerResourcesTable.loading">
:placeholder="t('phoneNumberPlaceholder')" <template #empty>
/> <span>{{ !customerResourcesTable.loading ? t('emptyData') : '' }}</span>
</el-form-item> </template>
<el-table-column :label="t('source')" min-width="180" align="center" :show-overflow-tooltip="true">
<el-form-item> <template #default="{ row }">
<el-button type="primary" @click="loadCustomerResourcesList()">{{ <div v-for="(item, index) in sourceList">
t('search') <div v-if="item.value == row.source">{{ item.name }}</div>
}}</el-button> </div>
<el-button @click="resetForm(searchFormRef)">{{ </template>
t('reset') </el-table-column>
}}</el-button>
</el-form-item> <el-table-column prop="consultant_name" :label="t('consultant')" min-width="120" :show-overflow-tooltip="true"/>
</el-form>
</el-card> <el-table-column prop="name" :label="t('name')" min-width="120" :show-overflow-tooltip="true"/>
<div class="mt-[10px]"> <el-table-column prop="age" :label="t('age')" min-width="120" :show-overflow-tooltip="true"/>
<el-table
:data="customerResourcesTable.data" <el-table-column :label="t('gender')" min-width="180" align="center" :show-overflow-tooltip="true">
size="large" <template #default="{ row }">
v-loading="customerResourcesTable.loading" <div v-for="(item, index) in genderList">
> <div v-if="item.value == row.gender">{{ item.name }}</div>
<template #empty> </div>
<span>{{ </template>
!customerResourcesTable.loading ? t('emptyData') : '' </el-table-column>
}}</span>
</template> <el-table-column prop="phone_number" :label="t('phoneNumber')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
:label="t('source')" <el-table-column prop="decision_maker" :label="t('decisionMaker')" min-width="120" :show-overflow-tooltip="true"/>
min-width="180"
align="center" <el-table-column :label="t('operation')" fixed="right" min-width="120">
:show-overflow-tooltip="true" <template #default="{ row }">
> <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<template #default="{ row }"> <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
<div v-for="(item, index) in sourceList"> </template>
<div v-if="item.value == row.source">{{ item.name }}</div> </el-table-column>
</div>
</template> </el-table>
</el-table-column> <div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="customerResourcesTable.page" v-model:page-size="customerResourcesTable.limit"
<el-table-column layout="total, sizes, prev, pager, next, jumper" :total="customerResourcesTable.total"
prop="consultant" @size-change="loadCustomerResourcesList()" @current-change="loadCustomerResourcesList" />
:label="t('consultant')" </div>
min-width="120" </div>
:show-overflow-tooltip="true"
/> <edit ref="editCustomerResourcesDialog" @complete="loadCustomerResourcesList" />
</el-card>
<el-table-column </div>
prop="name"
:label="t('name')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="age"
:label="t('age')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
:label="t('gender')"
min-width="180"
align="center"
:show-overflow-tooltip="true"
>
<template #default="{ row }">
<div v-for="(item, index) in genderList">
<div v-if="item.value == row.gender">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column
prop="phone_number"
:label="t('phoneNumber')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="decision_maker"
:label="t('decisionMaker')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="customerResourcesTable.page"
v-model:page-size="customerResourcesTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="customerResourcesTable.total"
@size-change="loadCustomerResourcesList()"
@current-change="loadCustomerResourcesList"
/>
</div>
</div>
<edit
ref="editCustomerResourcesDialog"
@complete="loadCustomerResourcesList"
/>
</el-card>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, watch } from 'vue' import { reactive, ref, watch } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict' import { useDictionary } from '@/app/api/dict'
import { import { getCustomerResourcesList, deleteCustomerResources, getWithPersonnelList, getWithCampusList } from '@/app/api/customer_resources'
getCustomerResourcesList,
deleteCustomerResources,
getWithCampusList,
} from '@/app/api/customer_resources'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus' import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/customer_resources/components/customer-resources-edit.vue' import Edit from '@/app/views/customer_resources/components/customer-resources-edit.vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title;
let customerResourcesTable = reactive({ let customerResourcesTable = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam: { searchParam:{
name: '', "name":"",
phone_number: '', "phone_number":""
}, }
}) })
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
@ -182,69 +105,59 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([]) const selectData = ref<any[]>([])
// //
const sourceList = ref([] as any[]) const sourceList = ref([] as any[])
const sourceDictList = async () => { const sourceDictList = async () => {
sourceList.value = await (await useDictionary('source')).data.dictionary sourceList.value = await (await useDictionary('source')).data.dictionary
} }
sourceDictList() sourceDictList();
const source_channelList = ref([] as any[]) const source_channelList = ref([] as any[])
const source_channelDictList = async () => { const source_channelDictList = async () => {
source_channelList.value = await ( source_channelList.value = await (await useDictionary('SourceChannel')).data.dictionary
await useDictionary('SourceChannel') }
).data.dictionary source_channelDictList();
} const genderList = ref([] as any[])
source_channelDictList() const genderDictList = async () => {
const genderList = ref([] as any[]) genderList.value = await (await useDictionary('zy_sex')).data.dictionary
const genderDictList = async () => { }
genderList.value = await (await useDictionary('zy_sex')).data.dictionary genderDictList();
} const purchasing_powerList = ref([] as any[])
genderDictList() const purchasing_powerDictList = async () => {
const purchasing_powerList = ref([] as any[]) purchasing_powerList.value = await (await useDictionary('customer_purchasing_power')).data.dictionary
const purchasing_powerDictList = async () => { }
purchasing_powerList.value = await ( purchasing_powerDictList();
await useDictionary('customer_purchasing_power') const cognitive_ideaList = ref([] as any[])
).data.dictionary const cognitive_ideaDictList = async () => {
} cognitive_ideaList.value = await (await useDictionary('cognitive_concept')).data.dictionary
purchasing_powerDictList() }
const cognitive_ideaList = ref([] as any[]) cognitive_ideaDictList();
const cognitive_ideaDictList = async () => { const initial_intentList = ref([] as any[])
cognitive_ideaList.value = await ( const initial_intentDictList = async () => {
await useDictionary('cognitive_concept') initial_intentList.value = await (await useDictionary('preliminarycustomerintention')).data.dictionary
).data.dictionary }
} initial_intentDictList();
cognitive_ideaDictList() const statusList = ref([] as any[])
const initial_intentList = ref([] as any[]) const statusDictList = async () => {
const initial_intentDictList = async () => { statusList.value = await (await useDictionary('kh_status')).data.dictionary
initial_intentList.value = await ( }
await useDictionary('preliminarycustomerintention') statusDictList();
).data.dictionary
}
initial_intentDictList()
const statusList = ref([] as any[])
const statusDictList = async () => {
statusList.value = await (await useDictionary('kh_status')).data.dictionary
}
statusDictList()
/** /**
* 获取客户资源列表 * 获取客户资源列表
*/ */
const loadCustomerResourcesList = (page: number = 1) => { const loadCustomerResourcesList = (page: number = 1) => {
customerResourcesTable.loading = true customerResourcesTable.loading = true
customerResourcesTable.page = page customerResourcesTable.page = page
getCustomerResourcesList({ getCustomerResourcesList({
page: customerResourcesTable.page, page: customerResourcesTable.page,
limit: customerResourcesTable.limit, limit: customerResourcesTable.limit,
...customerResourcesTable.searchParam, ...customerResourcesTable.searchParam
}) }).then(res => {
.then((res) => { customerResourcesTable.loading = false
customerResourcesTable.loading = false customerResourcesTable.data = res.data.data
customerResourcesTable.data = res.data.data customerResourcesTable.total = res.data.total
customerResourcesTable.total = res.data.total }).catch(() => {
}) customerResourcesTable.loading = false
.catch(() => {
customerResourcesTable.loading = false
}) })
} }
loadCustomerResourcesList() loadCustomerResourcesList()
@ -255,8 +168,8 @@ const editCustomerResourcesDialog: Record<string, any> | null = ref(null)
* 添加客户资源 * 添加客户资源
*/ */
const addEvent = () => { const addEvent = () => {
editCustomerResourcesDialog.value.setFormData() editCustomerResourcesDialog.value.setFormData()
editCustomerResourcesDialog.value.showDialog = true editCustomerResourcesDialog.value.showDialog = true
} }
/** /**
@ -264,48 +177,55 @@ const addEvent = () => {
* @param data * @param data
*/ */
const editEvent = (data: any) => { const editEvent = (data: any) => {
editCustomerResourcesDialog.value.setFormData(data) editCustomerResourcesDialog.value.setFormData(data)
editCustomerResourcesDialog.value.showDialog = true editCustomerResourcesDialog.value.showDialog = true
} }
/** /**
* 删除客户资源 * 删除客户资源
*/ */
const deleteEvent = (id: number) => { const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('customerResourcesDeleteTips'), t('warning'), { ElMessageBox.confirm(t('customerResourcesDeleteTips'), t('warning'),
confirmButtonText: t('confirm'), {
cancelButtonText: t('cancel'), confirmButtonText: t('confirm'),
type: 'warning', cancelButtonText: t('cancel'),
}).then(() => { type: 'warning',
deleteCustomerResources(id) }
.then(() => { ).then(() => {
loadCustomerResourcesList() deleteCustomerResources(id).then(() => {
}) loadCustomerResourcesList()
.catch(() => {}) }).catch(() => {
}) })
})
} }
const campusList = ref([])
const setCampusList = async () => { const consultantList = ref([])
campusList.value = await (await getWithCampusList({})).data const setConsultantList = async () => {
} consultantList.value = await (await getWithPersonnelList({})).data
setCampusList() }
setConsultantList()
const campusList = ref([])
const setCampusList = async () => {
campusList.value = await (await getWithCampusList({})).data
}
setCampusList()
const resetForm = (formEl: FormInstance | undefined) => { const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields() formEl.resetFields()
loadCustomerResourcesList() loadCustomerResourcesList()
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/* 多行超出隐藏 */ /* 多行超出隐藏 */
.multi-hidden { .multi-hidden {
word-break: break-all; word-break: break-all;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
</style> </style>

527
admin/src/app/views/six_speed/components/six-speed-edit.vue

@ -1,152 +1,108 @@
<template> <template>
<el-dialog <el-dialog v-model="showDialog" :title="formData.id ? t('updateSixSpeed') : t('addSixSpeed')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
v-model="showDialog" <el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
:title="formData.id ? t('updateSixSpeed') : t('addSixSpeed')" <el-form-item :label="t('purchasePower')" prop="purchase_power">
width="50%" <el-select class="input-width" v-model="formData.purchase_power" clearable :placeholder="t('purchasePowerPlaceholder')">
class="diy-dialog-wrap" <el-option label="请选择" value=""></el-option>
:destroy-on-close="true" <el-option
> v-for="(item, index) in purchase_powerList"
<el-form :key="index"
:model="formData" :label="item.name"
label-width="120px" :value="item.value"
ref="formRef" />
:rules="formRules" </el-select>
class="page-form" </el-form-item>
v-loading="loading"
> <el-form-item :label="t('conceptAwareness')" prop="concept_awareness">
<el-form-item :label="t('purchasePower')" prop="purchase_power"> <el-select class="input-width" v-model="formData.concept_awareness" clearable :placeholder="t('conceptAwarenessPlaceholder')">
<el-input <el-option label="请选择" value=""></el-option>
v-model="formData.purchase_power" <el-option
clearable v-for="(item, index) in concept_awarenessList"
:placeholder="t('purchasePowerPlaceholder')" :key="index"
class="input-width" :label="item.name"
/> :value="item.value"
</el-form-item> />
</el-select>
<el-form-item :label="t('conceptAwareness')" prop="concept_awareness"> </el-form-item>
<el-input
v-model="formData.concept_awareness" <el-form-item :label="t('preferredClassTime')" prop="preferred_class_time" class="input-width">
clearable <el-date-picker
:placeholder="t('conceptAwarenessPlaceholder')" class="flex-1 !flex"
class="input-width" v-model="formData.preferred_class_time"
/> clearable
</el-form-item> type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
<el-form-item :placeholder="t('preferredClassTimePlaceholder')">
:label="t('preferredClassTime')" </el-date-picker>
prop="preferred_class_time" </el-form-item>
> <el-form-item :label="t('distance')" prop="distance">
<el-input <el-input v-model="formData.distance" clearable :placeholder="t('distancePlaceholder')" class="input-width" />
v-model="formData.preferred_class_time" </el-form-item>
clearable
:placeholder="t('preferredClassTimePlaceholder')" <el-form-item :label="t('communication')" prop="communication">
class="input-width" <el-input v-model="formData.communication" type="textarea" rows="4" clearable :placeholder="t('communicationPlaceholder')" class="input-width"/>
/> </el-form-item>
</el-form-item> <el-form-item :label="t('promisedVisitTime')" prop="promised_visit_time" class="input-width">
<el-date-picker
<el-form-item :label="t('distance')" prop="distance"> class="flex-1 !flex"
<el-input v-model="formData.promised_visit_time"
v-model="formData.distance" clearable
clearable type="datetime"
:placeholder="t('distancePlaceholder')" value-format="YYYY-MM-DD HH:mm:ss"
class="input-width" :placeholder="t('promisedVisitTimePlaceholder')">
/> </el-date-picker>
</el-form-item> </el-form-item>
<el-form-item :label="t('actualVisitTime')" class="input-width">
<el-form-item :label="t('communication')" prop="communication"> <el-date-picker
<el-input class="flex-1 !flex"
v-model="formData.communication" v-model="formData.actual_visit_time"
clearable clearable
:placeholder="t('communicationPlaceholder')" type="datetime"
class="input-width" value-format="YYYY-MM-DD HH:mm:ss"
/> :placeholder="t('actualVisitTimePlaceholder')">
</el-form-item> </el-date-picker>
</el-form-item>
<el-form-item :label="t('promisedVisitTime')" prop="promised_visit_time"> <el-form-item :label="t('callIntent')" prop="call_intent">
<el-input <el-select class="input-width" v-model="formData.call_intent" clearable :placeholder="t('callIntentPlaceholder')">
v-model="formData.promised_visit_time" <el-option label="请选择" value=""></el-option>
clearable <el-option
:placeholder="t('promisedVisitTimePlaceholder')" v-for="(item, index) in call_intentList"
class="input-width" :key="index"
/> :label="item.name"
</el-form-item> :value="item.value"
/>
<el-form-item :label="t('actualVisitTime')"> </el-select>
<el-input </el-form-item>
v-model="formData.actual_visit_time"
clearable <el-form-item :label="t('firstVisitStatus')" >
:placeholder="t('actualVisitTimePlaceholder')" <el-input v-model="formData.first_visit_status" type="textarea" rows="4" clearable :placeholder="t('firstVisitStatusPlaceholder')" class="input-width"/>
class="input-width" </el-form-item>
/> <el-form-item :label="t('secondVisitStatus')" >
</el-form-item> <el-input v-model="formData.second_visit_status" type="textarea" rows="4" clearable :placeholder="t('secondVisitStatusPlaceholder')" class="input-width"/>
</el-form-item>
<el-form-item :label="t('callIntent')" prop="call_intent"> <el-form-item :label="t('isClosed')" prop="is_closed">
<el-input <el-select class="input-width" v-model="formData.is_closed" clearable :placeholder="t('isClosedPlaceholder')">
v-model="formData.call_intent" <el-option label="请选择" value=""></el-option>
clearable <el-option
:placeholder="t('callIntentPlaceholder')" v-for="(item, index) in is_closedList"
class="input-width" :key="index"
/> :label="item.name"
</el-form-item> :value="item.value"
/>
<el-form-item :label="t('firstVisitStatus')"> </el-select>
<el-input </el-form-item>
v-model="formData.first_visit_status"
clearable </el-form>
:placeholder="t('firstVisitStatusPlaceholder')"
class="input-width" <template #footer>
/> <span class="dialog-footer">
</el-form-item> <el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
<el-form-item :label="t('secondVisitStatus')"> t('confirm')
<el-input }}</el-button>
v-model="formData.second_visit_status" </span>
clearable </template>
:placeholder="t('secondVisitStatusPlaceholder')" </el-dialog>
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('isClosed')" prop="is_closed">
<el-input
v-model="formData.is_closed"
clearable
:placeholder="t('isClosedPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('staffId')" prop="staff_id">
<el-input
v-model="formData.staff_id"
clearable
:placeholder="t('staffIdPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('resourceId')" prop="resource_id">
<el-input
v-model="formData.resource_id"
clearable
:placeholder="t('resourceIdPlaceholder')"
class="input-width"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
</span>
</template>
</el-dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -154,7 +110,7 @@ import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict' import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { addSixSpeed, editSixSpeed, getSixSpeedInfo } from '@/app/api/six_speed' import { addSixSpeed, editSixSpeed, getSixSpeedInfo, getWithPersonnelList, getWithCustomerResourcesList } from '@/app/api/six_speed'
let showDialog = ref(false) let showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
@ -163,20 +119,18 @@ const loading = ref(false)
* 表单数据 * 表单数据
*/ */
const initialFormData = { const initialFormData = {
id: '', id: '',
purchase_power: '', purchase_power: '',
concept_awareness: '', concept_awareness: '',
preferred_class_time: '', preferred_class_time: '',
distance: '', distance: '',
communication: '', communication: '',
promised_visit_time: '', promised_visit_time: '',
actual_visit_time: '', actual_visit_time: '',
call_intent: '', call_intent: '',
first_visit_status: '', first_visit_status: '',
second_visit_status: '', second_visit_status: '',
is_closed: '', is_closed: '',
staff_id: '',
resource_id: '',
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -184,79 +138,63 @@ const formRef = ref<FormInstance>()
// //
const formRules = computed(() => { const formRules = computed(() => {
return { return {
purchase_power: [ purchase_power: [
{ { required: true, message: t('purchasePowerPlaceholder'), trigger: 'blur' },
required: true,
message: t('purchasePowerPlaceholder'), ]
trigger: 'blur', ,
},
],
concept_awareness: [ concept_awareness: [
{ { required: true, message: t('conceptAwarenessPlaceholder'), trigger: 'blur' },
required: true,
message: t('conceptAwarenessPlaceholder'), ]
trigger: 'blur', ,
},
],
preferred_class_time: [ preferred_class_time: [
{ { required: true, message: t('preferredClassTimePlaceholder'), trigger: 'blur' },
required: true,
message: t('preferredClassTimePlaceholder'), ]
trigger: 'blur', ,
},
],
distance: [ distance: [
{ required: true, message: t('distancePlaceholder'), trigger: 'blur' }, { required: true, message: t('distancePlaceholder'), trigger: 'blur' },
],
]
,
communication: [ communication: [
{ { required: true, message: t('communicationPlaceholder'), trigger: 'blur' },
required: true,
message: t('communicationPlaceholder'), ]
trigger: 'blur', ,
},
],
promised_visit_time: [ promised_visit_time: [
{ { required: true, message: t('promisedVisitTimePlaceholder'), trigger: 'blur' },
required: true,
message: t('promisedVisitTimePlaceholder'), ]
trigger: 'blur', ,
},
],
actual_visit_time: [ actual_visit_time: [
{ { required: true, message: t('actualVisitTimePlaceholder'), trigger: 'blur' },
required: true,
message: t('actualVisitTimePlaceholder'), ]
trigger: 'blur', ,
},
],
call_intent: [ call_intent: [
{ required: true, message: t('callIntentPlaceholder'), trigger: 'blur' }, { required: true, message: t('callIntentPlaceholder'), trigger: 'blur' },
],
]
,
first_visit_status: [ first_visit_status: [
{ { required: true, message: t('firstVisitStatusPlaceholder'), trigger: 'blur' },
required: true,
message: t('firstVisitStatusPlaceholder'), ]
trigger: 'blur', ,
},
],
second_visit_status: [ second_visit_status: [
{ { required: true, message: t('secondVisitStatusPlaceholder'), trigger: 'blur' },
required: true,
message: t('secondVisitStatusPlaceholder'), ]
trigger: 'blur', ,
},
],
is_closed: [ is_closed: [
{ required: true, message: t('isClosedPlaceholder'), trigger: 'blur' }, { required: true, message: t('isClosedPlaceholder'), trigger: 'blur' },
],
staff_id: [ ]
{ required: true, message: t('staffIdPlaceholder'), trigger: 'blur' }, ,
], }
resource_id: [
{ required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' },
],
}
}) })
const emit = defineEmits(['complete']) const emit = defineEmits(['complete'])
@ -266,93 +204,120 @@ const emit = defineEmits(['complete'])
* @param formEl * @param formEl
*/ */
const confirm = async (formEl: FormInstance | undefined) => { const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return if (loading.value || !formEl) return
let save = formData.id ? editSixSpeed : addSixSpeed let save = formData.id ? editSixSpeed : addSixSpeed
await formEl.validate(async (valid) => { await formEl.validate(async (valid) => {
if (valid) { if (valid) {
loading.value = true loading.value = true
let data = formData let data = formData
save(data) save(data).then(res => {
.then((res) => { loading.value = false
loading.value = false showDialog.value = false
showDialog.value = false emit('complete')
emit('complete') }).catch(err => {
}) loading.value = false
.catch((err) => { })
loading.value = false }
}) })
}
})
} }
// //
let purchase_powerList = ref([])
const purchase_powerDictList = async () => {
purchase_powerList.value = await (await useDictionary('customer_purchasing_power')).data.dictionary
}
purchase_powerDictList();
watch(() => purchase_powerList.value, () => { formData.purchase_power = purchase_powerList.value[0].value })
let concept_awarenessList = ref([])
const concept_awarenessDictList = async () => {
concept_awarenessList.value = await (await useDictionary('cognitive_concept')).data.dictionary
}
concept_awarenessDictList();
watch(() => concept_awarenessList.value, () => { formData.concept_awareness = concept_awarenessList.value[0].value })
let call_intentList = ref([])
const call_intentDictList = async () => {
call_intentList.value = await (await useDictionary('preliminarycustomerintention')).data.dictionary
}
call_intentDictList();
watch(() => call_intentList.value, () => { formData.call_intent = call_intentList.value[0].value })
let is_closedList = ref([])
const is_closedDictList = async () => {
is_closedList.value = await (await useDictionary('global_true_or_false')).data.dictionary
}
is_closedDictList();
watch(() => is_closedList.value, () => { formData.is_closed = is_closedList.value[0].value })
const staffIdList = ref([] as any[])
const setStaffIdList = async () => {
staffIdList.value = await (await getWithPersonnelList({})).data
}
setStaffIdList()
const resourceIdList = ref([] as any[])
const setResourceIdList = async () => {
resourceIdList.value = await (await getWithCustomerResourcesList({})).data
}
setResourceIdList()
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
loading.value = true loading.value = true
if (row) { if(row){
const data = await (await getSixSpeedInfo(row.id)).data const data = await (await getSixSpeedInfo(row.id)).data
if (data) if (data) Object.keys(formData).forEach((key: string) => {
Object.keys(formData).forEach((key: string) => { if (data[key] != undefined) formData[key] = data[key]
if (data[key] != undefined) formData[key] = data[key] })
}) }
} loading.value = false
loading.value = false
} }
// //
const mobileVerify = (rule: any, value: any, callback: any) => { const mobileVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) { if (value && !/^1[3-9]\d{9}$/.test(value)) {
callback(new Error(t('generateMobile'))) callback(new Error(t('generateMobile')))
} else { } else {
callback() callback()
} }
} }
// //
const idCardVerify = (rule: any, value: any, callback: any) => { const idCardVerify = (rule: any, value: any, callback: any) => {
if ( if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
value && callback(new Error(t('generateIdCard')))
!/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test( } else {
value callback()
) }
) {
callback(new Error(t('generateIdCard')))
} else {
callback()
}
} }
// //
const emailVerify = (rule: any, value: any, callback: any) => { const emailVerify = (rule: any, value: any, callback: any) => {
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) { if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateEmail'))) callback(new Error(t('generateEmail')))
} else { } else {
callback() callback()
} }
} }
// //
const numberVerify = (rule: any, value: any, callback: any) => { const numberVerify = (rule: any, value: any, callback: any) => {
if (!Number.isInteger(value)) { if (!Number.isInteger(value)) {
callback(new Error(t('generateNumber'))) callback(new Error(t('generateNumber')))
} else { } else {
callback() callback()
} }
} }
defineExpose({ defineExpose({
showDialog, showDialog,
setFormData, setFormData
}) })
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>
<style lang="scss"> <style lang="scss">
.diy-dialog-wrap .el-form-item__label { .diy-dialog-wrap .el-form-item__label{
height: auto !important; height: auto !important;
} }
</style> </style>

468
admin/src/app/views/six_speed/six_speed.vue

@ -1,289 +1,100 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span> <div class="flex justify-between items-center">
<el-button type="primary" @click="addEvent"> <span class="text-lg">{{pageName}}</span>
{{ t('addSixSpeed') }} <el-button type="primary" @click="addEvent">
</el-button> {{ t('addSixSpeed') }}
</div> </el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap" <el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
shadow="never" <el-form :inline="true" :model="sixSpeedTable.searchParam" ref="searchFormRef">
>
<el-form <el-form-item>
:inline="true" <el-button type="primary" @click="loadSixSpeedList()">{{ t('search') }}</el-button>
:model="sixSpeedTable.searchParam" <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
ref="searchFormRef" </el-form-item>
> </el-form>
<el-form-item :label="t('purchasePower')" prop="purchase_power"> </el-card>
<el-input
v-model="sixSpeedTable.searchParam.purchase_power" <div class="mt-[10px]">
:placeholder="t('purchasePowerPlaceholder')" <el-table :data="sixSpeedTable.data" size="large" v-loading="sixSpeedTable.loading">
/> <template #empty>
</el-form-item> <span>{{ !sixSpeedTable.loading ? t('emptyData') : '' }}</span>
<el-form-item :label="t('conceptAwareness')" prop="concept_awareness"> </template>
<el-input <el-table-column prop="preferred_class_time" :label="t('preferredClassTime')" min-width="120" :show-overflow-tooltip="true"/>
v-model="sixSpeedTable.searchParam.concept_awareness"
:placeholder="t('conceptAwarenessPlaceholder')" <el-table-column prop="distance" :label="t('distance')" min-width="120" :show-overflow-tooltip="true"/>
/>
</el-form-item> <el-table-column prop="communication" :label="t('communication')" min-width="120" :show-overflow-tooltip="true"/>
<el-form-item
:label="t('preferredClassTime')" <el-table-column prop="promised_visit_time" :label="t('promisedVisitTime')" min-width="120" :show-overflow-tooltip="true"/>
prop="preferred_class_time"
> <el-table-column prop="actual_visit_time" :label="t('actualVisitTime')" min-width="120" :show-overflow-tooltip="true"/>
<el-input
v-model="sixSpeedTable.searchParam.preferred_class_time" <el-table-column :label="t('callIntent')" min-width="180" align="center" :show-overflow-tooltip="true">
:placeholder="t('preferredClassTimePlaceholder')" <template #default="{ row }">
/> <div v-for="(item, index) in call_intentList">
</el-form-item> <div v-if="item.value == row.call_intent">{{ item.name }}</div>
<el-form-item :label="t('distance')" prop="distance"> </div>
<el-input </template>
v-model="sixSpeedTable.searchParam.distance" </el-table-column>
:placeholder="t('distancePlaceholder')"
/> <el-table-column prop="first_visit_status" :label="t('firstVisitStatus')" min-width="120" :show-overflow-tooltip="true"/>
</el-form-item>
<el-form-item :label="t('communication')" prop="communication"> <el-table-column prop="second_visit_status" :label="t('secondVisitStatus')" min-width="120" :show-overflow-tooltip="true"/>
<el-input
v-model="sixSpeedTable.searchParam.communication" <el-table-column :label="t('isClosed')" min-width="180" align="center" :show-overflow-tooltip="true">
:placeholder="t('communicationPlaceholder')" <template #default="{ row }">
/> <div v-for="(item, index) in is_closedList">
</el-form-item> <div v-if="item.value == row.is_closed">{{ item.name }}</div>
<el-form-item </div>
:label="t('promisedVisitTime')" </template>
prop="promised_visit_time" </el-table-column>
>
<el-input <el-table-column :label="t('operation')" fixed="right" min-width="120">
v-model="sixSpeedTable.searchParam.promised_visit_time" <template #default="{ row }">
:placeholder="t('promisedVisitTimePlaceholder')" <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
/> <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</el-form-item> </template>
<el-form-item :label="t('actualVisitTime')" prop="actual_visit_time"> </el-table-column>
<el-input
v-model="sixSpeedTable.searchParam.actual_visit_time" </el-table>
:placeholder="t('actualVisitTimePlaceholder')" <div class="mt-[16px] flex justify-end">
/> <el-pagination v-model:current-page="sixSpeedTable.page" v-model:page-size="sixSpeedTable.limit"
</el-form-item> layout="total, sizes, prev, pager, next, jumper" :total="sixSpeedTable.total"
<el-form-item :label="t('callIntent')" prop="call_intent"> @size-change="loadSixSpeedList()" @current-change="loadSixSpeedList" />
<el-input </div>
v-model="sixSpeedTable.searchParam.call_intent" </div>
:placeholder="t('callIntentPlaceholder')"
/> <edit ref="editSixSpeedDialog" @complete="loadSixSpeedList" />
</el-form-item> </el-card>
<el-form-item </div>
:label="t('firstVisitStatus')"
prop="first_visit_status"
>
<el-input
v-model="sixSpeedTable.searchParam.first_visit_status"
:placeholder="t('firstVisitStatusPlaceholder')"
/>
</el-form-item>
<el-form-item
:label="t('secondVisitStatus')"
prop="second_visit_status"
>
<el-input
v-model="sixSpeedTable.searchParam.second_visit_status"
:placeholder="t('secondVisitStatusPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('isClosed')" prop="is_closed">
<el-input
v-model="sixSpeedTable.searchParam.is_closed"
:placeholder="t('isClosedPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('staffId')" prop="staff_id">
<el-input
v-model="sixSpeedTable.searchParam.staff_id"
:placeholder="t('staffIdPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('resourceId')" prop="resource_id">
<el-input
v-model="sixSpeedTable.searchParam.resource_id"
:placeholder="t('resourceIdPlaceholder')"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadSixSpeedList()">{{
t('search')
}}</el-button>
<el-button @click="resetForm(searchFormRef)">{{
t('reset')
}}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table
:data="sixSpeedTable.data"
size="large"
v-loading="sixSpeedTable.loading"
>
<template #empty>
<span>{{ !sixSpeedTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column
prop="purchase_power"
:label="t('purchasePower')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="concept_awareness"
:label="t('conceptAwareness')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="preferred_class_time"
:label="t('preferredClassTime')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="distance"
:label="t('distance')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="communication"
:label="t('communication')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="promised_visit_time"
:label="t('promisedVisitTime')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="actual_visit_time"
:label="t('actualVisitTime')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="call_intent"
:label="t('callIntent')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="first_visit_status"
:label="t('firstVisitStatus')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="second_visit_status"
:label="t('secondVisitStatus')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="is_closed"
:label="t('isClosed')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="staff_id"
:label="t('staffId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="resource_id"
:label="t('resourceId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="sixSpeedTable.page"
v-model:page-size="sixSpeedTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="sixSpeedTable.total"
@size-change="loadSixSpeedList()"
@current-change="loadSixSpeedList"
/>
</div>
</div>
<edit ref="editSixSpeedDialog" @complete="loadSixSpeedList" />
</el-card>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, watch } from 'vue' import { reactive, ref, watch } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict' import { useDictionary } from '@/app/api/dict'
import { getSixSpeedList, deleteSixSpeed } from '@/app/api/six_speed' import { getSixSpeedList, deleteSixSpeed, getWithPersonnelList, getWithCustomerResourcesList } from '@/app/api/six_speed'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus' import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/six_speed/components/six-speed-edit.vue' import Edit from '@/app/views/six_speed/components/six-speed-edit.vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title;
let sixSpeedTable = reactive({ let sixSpeedTable = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam: { searchParam:{
purchase_power: '',
concept_awareness: '', }
preferred_class_time: '',
distance: '',
communication: '',
promised_visit_time: '',
actual_visit_time: '',
call_intent: '',
first_visit_status: '',
second_visit_status: '',
is_closed: '',
staff_id: '',
resource_id: '',
},
}) })
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
@ -292,26 +103,44 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([]) const selectData = ref<any[]>([])
// //
const purchase_powerList = ref([] as any[])
const purchase_powerDictList = async () => {
purchase_powerList.value = await (await useDictionary('customer_purchasing_power')).data.dictionary
}
purchase_powerDictList();
const concept_awarenessList = ref([] as any[])
const concept_awarenessDictList = async () => {
concept_awarenessList.value = await (await useDictionary('cognitive_concept')).data.dictionary
}
concept_awarenessDictList();
const call_intentList = ref([] as any[])
const call_intentDictList = async () => {
call_intentList.value = await (await useDictionary('preliminarycustomerintention')).data.dictionary
}
call_intentDictList();
const is_closedList = ref([] as any[])
const is_closedDictList = async () => {
is_closedList.value = await (await useDictionary('global_true_or_false')).data.dictionary
}
is_closedDictList();
/** /**
* 获取六一速列表 * 获取六一速列表
*/ */
const loadSixSpeedList = (page: number = 1) => { const loadSixSpeedList = (page: number = 1) => {
sixSpeedTable.loading = true sixSpeedTable.loading = true
sixSpeedTable.page = page sixSpeedTable.page = page
getSixSpeedList({ getSixSpeedList({
page: sixSpeedTable.page, page: sixSpeedTable.page,
limit: sixSpeedTable.limit, limit: sixSpeedTable.limit,
...sixSpeedTable.searchParam, ...sixSpeedTable.searchParam
}) }).then(res => {
.then((res) => { sixSpeedTable.loading = false
sixSpeedTable.loading = false sixSpeedTable.data = res.data.data
sixSpeedTable.data = res.data.data sixSpeedTable.total = res.data.total
sixSpeedTable.total = res.data.total }).catch(() => {
}) sixSpeedTable.loading = false
.catch(() => {
sixSpeedTable.loading = false
}) })
} }
loadSixSpeedList() loadSixSpeedList()
@ -322,8 +151,8 @@ const editSixSpeedDialog: Record<string, any> | null = ref(null)
* 添加六一速 * 添加六一速
*/ */
const addEvent = () => { const addEvent = () => {
editSixSpeedDialog.value.setFormData() editSixSpeedDialog.value.setFormData()
editSixSpeedDialog.value.showDialog = true editSixSpeedDialog.value.showDialog = true
} }
/** /**
@ -331,42 +160,55 @@ const addEvent = () => {
* @param data * @param data
*/ */
const editEvent = (data: any) => { const editEvent = (data: any) => {
editSixSpeedDialog.value.setFormData(data) editSixSpeedDialog.value.setFormData(data)
editSixSpeedDialog.value.showDialog = true editSixSpeedDialog.value.showDialog = true
} }
/** /**
* 删除六一速 * 删除六一速
*/ */
const deleteEvent = (id: number) => { const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('sixSpeedDeleteTips'), t('warning'), { ElMessageBox.confirm(t('sixSpeedDeleteTips'), t('warning'),
confirmButtonText: t('confirm'), {
cancelButtonText: t('cancel'), confirmButtonText: t('confirm'),
type: 'warning', cancelButtonText: t('cancel'),
}).then(() => { type: 'warning',
deleteSixSpeed(id) }
.then(() => { ).then(() => {
loadSixSpeedList() deleteSixSpeed(id).then(() => {
}) loadSixSpeedList()
.catch(() => {}) }).catch(() => {
}) })
})
} }
const staffIdList = ref([])
const setStaffIdList = async () => {
staffIdList.value = await (await getWithPersonnelList({})).data
}
setStaffIdList()
const resourceIdList = ref([])
const setResourceIdList = async () => {
resourceIdList.value = await (await getWithCustomerResourcesList({})).data
}
setResourceIdList()
const resetForm = (formEl: FormInstance | undefined) => { const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields() formEl.resetFields()
loadSixSpeedList() loadSixSpeedList()
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/* 多行超出隐藏 */ /* 多行超出隐藏 */
.multi-hidden { .multi-hidden {
word-break: break-all; word-break: break-all;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
</style> </style>

46
niucloud/app/adminapi/controller/customer_resources/CustomerResources.php

@ -64,13 +64,23 @@ class CustomerResources extends BaseAdminController
["initial_intent",""], ["initial_intent",""],
["campus",""], ["campus",""],
["status",""], ["status",""],
["create_year_month",date("Y-m")], ["create_year_month",date("Y-m")],
["create_date",date("Y-m-d")] ["create_date",date("Y-m-d")],
]); ["purchase_power",""],
["concept_awareness",""],
["preferred_class_time",""],
["distance_tow",""],
["communication",""],
["promised_visit_time",""],
["actual_visit_time",""],
["call_intent",""],
["first_visit_status",""],
["second_visit_status",""],
["is_closed",""]
]);
$this->validate($data, 'app\validate\customer_resources\CustomerResources.add'); $this->validate($data, 'app\validate\customer_resources\CustomerResources.add');
$id = (new CustomerResourcesService())->add($data); return (new CustomerResourcesService())->add($data);
return success('ADD_SUCCESS', ['id' => $id]);
} }
/** /**
@ -94,11 +104,27 @@ class CustomerResources extends BaseAdminController
["decision_maker",""], ["decision_maker",""],
["initial_intent",""], ["initial_intent",""],
["campus",""], ["campus",""],
["status",""] ["status",""],
["create_year_month",date("Y-m")],
["create_date",date("Y-m-d")],
["purchase_power",""],
["concept_awareness",""],
["preferred_class_time",""],
["distance_tow",""],
["communication",""],
["promised_visit_time",""],
["actual_visit_time",""],
["call_intent",""],
["first_visit_status",""],
["second_visit_status",""],
["is_closed",""]
]); ]);
$this->validate($data, 'app\validate\customer_resources\CustomerResources.edit'); $this->validate($data, 'app\validate\customer_resources\CustomerResources.edit');
(new CustomerResourcesService())->edit($id, $data);
return success('EDIT_SUCCESS'); return (new CustomerResourcesService())->edit($id, $data);
} }
/** /**
@ -112,6 +138,10 @@ class CustomerResources extends BaseAdminController
} }
public function getPersonnelAll(){
return success(( new CustomerResourcesService())->getPersonnelAll());
}
public function getCampusAll(){ public function getCampusAll(){
return success(( new CustomerResourcesService())->getCampusAll()); return success(( new CustomerResourcesService())->getCampusAll());
} }

34
niucloud/app/adminapi/controller/six_speed/SixSpeed.php

@ -28,19 +28,7 @@ class SixSpeed extends BaseAdminController
*/ */
public function lists(){ public function lists(){
$data = $this->request->params([ $data = $this->request->params([
["purchase_power",""],
["concept_awareness",""],
["preferred_class_time",""],
["distance",""],
["communication",""],
["promised_visit_time",""],
["actual_visit_time",""],
["call_intent",""],
["first_visit_status",""],
["second_visit_status",""],
["is_closed",""],
["staff_id",""],
["resource_id",""]
]); ]);
return success((new SixSpeedService())->getPage($data)); return success((new SixSpeedService())->getPage($data));
} }
@ -65,14 +53,12 @@ class SixSpeed extends BaseAdminController
["preferred_class_time",""], ["preferred_class_time",""],
["distance",""], ["distance",""],
["communication",""], ["communication",""],
["promised_visit_time","2025-05-16 17:57:14"], ["promised_visit_time","2025-05-18 16:21:59"],
["actual_visit_time","2025-05-16 17:57:14"], ["actual_visit_time","2025-05-18 16:21:59"],
["call_intent",""], ["call_intent",""],
["first_visit_status",""], ["first_visit_status",""],
["second_visit_status",""], ["second_visit_status",""],
["is_closed",0], ["is_closed",0],
["staff_id",0],
["resource_id",0],
]); ]);
$this->validate($data, 'app\validate\six_speed\SixSpeed.add'); $this->validate($data, 'app\validate\six_speed\SixSpeed.add');
@ -92,14 +78,12 @@ class SixSpeed extends BaseAdminController
["preferred_class_time",""], ["preferred_class_time",""],
["distance",""], ["distance",""],
["communication",""], ["communication",""],
["promised_visit_time","2025-05-16 17:57:14"], ["promised_visit_time","2025-05-18 16:21:59"],
["actual_visit_time","2025-05-16 17:57:14"], ["actual_visit_time","2025-05-18 16:21:59"],
["call_intent",""], ["call_intent",""],
["first_visit_status",""], ["first_visit_status",""],
["second_visit_status",""], ["second_visit_status",""],
["is_closed",0], ["is_closed",0],
["staff_id",0],
["resource_id",0],
]); ]);
$this->validate($data, 'app\validate\six_speed\SixSpeed.edit'); $this->validate($data, 'app\validate\six_speed\SixSpeed.edit');
@ -118,4 +102,12 @@ class SixSpeed extends BaseAdminController
} }
public function getPersonnelAll(){
return success(( new SixSpeedService())->getPersonnelAll());
}
public function getCustomerResourcesAll(){
return success(( new SixSpeedService())->getCustomerResourcesAll());
}
} }

4
niucloud/app/adminapi/route/customer_resources.php

@ -18,6 +18,8 @@ use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- customer_resources // USER_CODE_BEGIN -- customer_resources
Route::group('customer_resources', function () { Route::group('customer_resources', function () {
@ -33,6 +35,8 @@ Route::group('customer_resources', function () {
//删除客户资源 //删除客户资源
Route::delete('customer_resources/:id', 'customer_resources.CustomerResources/del'); Route::delete('customer_resources/:id', 'customer_resources.CustomerResources/del');
Route::get('personnel_all','customer_resources.CustomerResources/getPersonnelAll');
Route::get('campus_all','customer_resources.CustomerResources/getCampusAll'); Route::get('campus_all','customer_resources.CustomerResources/getCampusAll');
})->middleware([ })->middleware([

5
niucloud/app/adminapi/route/six_speed.php

@ -14,6 +14,7 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole; use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken; use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog; use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- six_speed // USER_CODE_BEGIN -- six_speed
Route::group('six_speed', function () { Route::group('six_speed', function () {
@ -29,6 +30,10 @@ Route::group('six_speed', function () {
//删除六一速 //删除六一速
Route::delete('six_speed/:id', 'six_speed.SixSpeed/del'); Route::delete('six_speed/:id', 'six_speed.SixSpeed/del');
Route::get('personnel_all','six_speed.SixSpeed/getPersonnelAll');
Route::get('customer_resources_all','six_speed.SixSpeed/getCustomerResourcesAll');
})->middleware([ })->middleware([
AdminCheckToken::class, AdminCheckToken::class,
AdminCheckRole::class, AdminCheckRole::class,

28
niucloud/app/common.php

@ -1046,3 +1046,31 @@ function get_campus_where($user_id){
return $where; return $where;
} }
function getModifiedFields(array $oldData, array $newData): array
{
$modifiedFields = [];
$oldValues = [];
$newValues = [];
foreach ($newData as $key => $newValue) {
if (!array_key_exists($key, $oldData)) {
continue;
}
if ($oldData[$key] != $newValue) {
$modifiedFields[] = $key;
$oldValues[$key] = $oldData[$key];
$newValues[$key] = $newValue;
}
}
return [
'is_save' => !empty($modifiedFields),
'modified_fields' => json_encode($modifiedFields, JSON_UNESCAPED_UNICODE),
'old_values' => json_encode($oldValues, JSON_UNESCAPED_UNICODE),
'new_values' => json_encode($newValues, JSON_UNESCAPED_UNICODE),
];
}

6
niucloud/app/model/customer_resources/CustomerResources.php

@ -16,6 +16,8 @@ use think\model\concern\SoftDelete;
use think\model\relation\HasMany; use think\model\relation\HasMany;
use think\model\relation\HasOne; use think\model\relation\HasOne;
use app\model\personnel\Personnel;
use app\model\campus\Campus; use app\model\campus\Campus;
/** /**
@ -81,6 +83,10 @@ class CustomerResources extends BaseModel
public function personnel(){
return $this->hasOne(Personnel::class, 'id', 'consultant')->joinType('left')->withField('name,id')->bind(['consultant_name'=>'name']);
}
public function campus(){ public function campus(){
return $this->hasOne(Campus::class, 'id', 'campus')->joinType('left')->withField('campus_name,id')->bind(['campus_name'=>'campus_name']); return $this->hasOne(Campus::class, 'id', 'campus')->joinType('left')->withField('campus_name,id')->bind(['campus_name'=>'campus_name']);
} }

172
niucloud/app/model/six_speed/SixSpeed.php

@ -16,6 +16,10 @@ use think\model\concern\SoftDelete;
use think\model\relation\HasMany; use think\model\relation\HasMany;
use think\model\relation\HasOne; use think\model\relation\HasOne;
use app\model\personnel\Personnel;
use app\model\customer_resources\CustomerResources;
/** /**
* 六一速模型 * 六一速模型
* Class SixSpeed * Class SixSpeed
@ -50,177 +54,17 @@ class SixSpeed extends BaseModel
*/ */
protected $defaultSoftDelete = 0; protected $defaultSoftDelete = 0;
/**
* 搜索器:六一速编号
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:六一速需求购买力
* @param $value
* @param $data
*/
public function searchPurchasePowerAttr($query, $value, $data)
{
if ($value) {
$query->where("purchase_power", $value);
}
}
/**
* 搜索器:六一速认知理念
* @param $value
* @param $data
*/
public function searchConceptAwarenessAttr($query, $value, $data)
{
if ($value) {
$query->where("concept_awareness", $value);
}
}
/**
* 搜索器:六一速可选上课时间
* @param $value
* @param $data
*/
public function searchPreferredClassTimeAttr($query, $value, $data)
{
if ($value) {
$query->where("preferred_class_time", $value);
}
}
/**
* 搜索器:六一速距离
* @param $value
* @param $data
*/
public function searchDistanceAttr($query, $value, $data)
{
if ($value) {
$query->where("distance", $value);
}
}
/**
* 搜索器:六一速沟通备注
* @param $value
* @param $data
*/
public function searchCommunicationAttr($query, $value, $data)
{
if ($value) {
$query->where("communication", $value);
}
}
/**
* 搜索器:六一速承诺到访时间
* @param $value
* @param $data
*/
public function searchPromisedVisitTimeAttr($query, $value, $data)
{
if ($value) {
$query->where("promised_visit_time", $value);
}
}
/**
* 搜索器:六一速实际到访时间
* @param $value
* @param $data
*/
public function searchActualVisitTimeAttr($query, $value, $data)
{
if ($value) {
$query->where("actual_visit_time", $value);
}
}
/**
* 搜索器:六一速电话后的意向程度: low-低, medium-中, high-高
* @param $value
* @param $data
*/
public function searchCallIntentAttr($query, $value, $data)
{
if ($value) {
$query->where("call_intent", $value);
}
}
/**
* 搜索器:六一速一访情况
* @param $value
* @param $data
*/
public function searchFirstVisitStatusAttr($query, $value, $data)
{
if ($value) {
$query->where("first_visit_status", $value);
}
}
/**
* 搜索器:六一速二访情况
* @param $value
* @param $data
*/
public function searchSecondVisitStatusAttr($query, $value, $data)
{
if ($value) {
$query->where("second_visit_status", $value);
}
}
/**
* 搜索器:六一速是否关单: 1-是, 0-否
* @param $value
* @param $data
*/
public function searchIsClosedAttr($query, $value, $data)
{
if ($value) {
$query->where("is_closed", $value);
}
}
/** public function personnel(){
* 搜索器:六一速人员ID return $this->hasOne(Personnel::class, 'id', 'staff_id')->joinType('left')->withField('name,id')->bind(['staff_id_name'=>'name']);
* @param $value
* @param $data
*/
public function searchStaffIdAttr($query, $value, $data)
{
if ($value) {
$query->where("staff_id", $value);
}
} }
/** public function customerResources(){
* 搜索器:六一速资源ID return $this->hasOne(CustomerResources::class, 'id', 'resource_id')->joinType('left')->withField('name,id')->bind(['resource_id_name'=>'name']);
* @param $value
* @param $data
*/
public function searchResourceIdAttr($query, $value, $data)
{
if ($value) {
$query->where("resource_id", $value);
}
} }
} }

151
niucloud/app/service/admin/customer_resources/CustomerResourcesService.php

@ -11,9 +11,13 @@
namespace app\service\admin\customer_resources; namespace app\service\admin\customer_resources;
use app\model\customer_resource_changes\CustomerResourceChanges;
use app\model\customer_resources\CustomerResources; use app\model\customer_resources\CustomerResources;
use app\model\personnel\Personnel;
use app\model\campus\Campus; use app\model\campus\Campus;
use app\model\six_speed\SixSpeed;
use app\model\six_speed_modification_log\SixSpeedModificationLog;
use core\base\BaseAdminService; use core\base\BaseAdminService;
@ -40,7 +44,7 @@ class CustomerResourcesService extends BaseAdminService
$field = 'id,create_year_month,create_date,source,source_channel,consultant,name,age,gender,phone_number,demand,purchasing_power,cognitive_idea,optional_class_time,distance,decision_maker,initial_intent,campus,created_at,updated_at,deleted_at,status'; $field = 'id,create_year_month,create_date,source,source_channel,consultant,name,age,gender,phone_number,demand,purchasing_power,cognitive_idea,optional_class_time,distance,decision_maker,initial_intent,campus,created_at,updated_at,deleted_at,status';
$order = 'id desc'; $order = 'id desc';
$search_model = $this->model->where(get_campus_where($this->uid))->withSearch(["name","phone_number"], $where)->with(['campus'])->field($field)->order($order); $search_model = $this->model->withSearch(["name","phone_number"], $where)->with(['personnel'])->field($field)->order($order);
$list = $this->pageQuery($search_model); $list = $this->pageQuery($search_model);
return $list; return $list;
} }
@ -54,7 +58,12 @@ class CustomerResourcesService extends BaseAdminService
{ {
$field = 'id,create_year_month,create_date,source,source_channel,consultant,name,age,gender,phone_number,demand,purchasing_power,cognitive_idea,optional_class_time,distance,decision_maker,initial_intent,campus,created_at,updated_at,deleted_at,status'; $field = 'id,create_year_month,create_date,source,source_channel,consultant,name,age,gender,phone_number,demand,purchasing_power,cognitive_idea,optional_class_time,distance,decision_maker,initial_intent,campus,created_at,updated_at,deleted_at,status';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray(); $info = $this->model->field($field)->where([['id', "=", $id]])->with(['personnel'])->findOrEmpty()->toArray();
$sixSpeed = new SixSpeed();
$data = $sixSpeed->where(['resource_id' => $id])->field("*,distance as distance_tow")->findOrEmpty()->toArray();
$info = $info+$data;
return $info; return $info;
} }
@ -65,9 +74,41 @@ class CustomerResourcesService extends BaseAdminService
*/ */
public function add(array $data) public function add(array $data)
{ {
$data['consultant'] = $this->username; $personnel = new Personnel();
$data['consultant'] = $personnel->where(['sys_user_id' => $this->uid])->value("id");
if(!$data['consultant']){
return fail("操作失败");
}
$sixSpeed = new SixSpeed();
$res = $this->model->create($data); $res = $this->model->create($data);
return $res->id;
if($data['purchase_power']){
$six_id = $sixSpeed->where(['resource_id' => $res->id])->value("id");
$data['staff_id'] = $data['consultant'];
$field = [
'purchase_power' => $data['purchase_power'],
'concept_awareness' => $data['concept_awareness'],
'preferred_class_time' => $data['preferred_class_time'],
'distance' => $data['distance_tow'],
'communication' => $data['communication'],
'promised_visit_time' => $data['promised_visit_time'],
'actual_visit_time' => $data['actual_visit_time'],
'call_intent' => $data['call_intent'],
'first_visit_status' => $data['first_visit_status'],
'second_visit_status' => $data['second_visit_status'],
'is_closed' => $data['is_closed'],
'staff_id' => $data['staff_id'],
'resource_id' => $res->id
];
if($six_id){
$sixSpeed->where(['resource_id' => $res->id])->update($field);
}else{
$sixSpeed->insert($field);
}
}
return success("操作成功");
} }
@ -75,14 +116,101 @@ class CustomerResourcesService extends BaseAdminService
* 客户资源编辑 * 客户资源编辑
* @param int $id * @param int $id
* @param array $data * @param array $data
* @return bool
*/ */
public function edit(int $id, array $data) public function edit(int $id, array $data)
{ {
$personnel = new Personnel();
$data['consultant'] = $this->username; // $data['consultant'] = $personnel->where(['sys_user_id' => $this->uid])->value("id");
$this->model->where([['id', '=', $id]])->update($data); // if(!$data['consultant']){
return true; // return fail("操作失败");
// }
$data['consultant'] = 1;
$res = $this->model->where([['id', '=', $id]])->findOrEmpty()->toArray();
$this->model->where([['id', '=', $id]])->update([
'source' => $data['source'],
'source_channel' => $data['source_channel'],
'consultant' => $data['consultant'],
'name' => $data['name'],
'age' => $data['age'],
'gender' => $data['gender'],
'phone_number' => $data['phone_number'],
'demand' => $data['demand'],
'purchasing_power' => $data['purchasing_power'],
'cognitive_idea' => $data['cognitive_idea'],
'optional_class_time' => $data['optional_class_time'],
'distance' => $data['distance'],
'decision_maker' => $data['decision_maker'],
'initial_intent' => $data['initial_intent'],
'campus' => $data['campus'],
'status' => $data['status'],
'create_year_month' => $data['create_year_month'],
'create_date' => $data['create_date']
]);
$resources_save = getModifiedFields($res,$data);
$customerResourceChanges = new CustomerResourceChanges();
if($resources_save['is_save']){
$customerResourceChanges->insert([
'customer_resource_id' => $id,
'operator_id' => $data['consultant'],
'campus_id' => $data['campus'],
'modified_fields' => $resources_save['modified_fields'],
'old_values' => $resources_save['old_values'],
'new_values' => $resources_save['new_values']
]);
}
$sixSpeed = new SixSpeed();
if($data['purchase_power']){
$sixSpeedModificationLog = new SixSpeedModificationLog();
$six_id = $sixSpeed->where(['resource_id' => $id])->value("id");
$data['staff_id'] = $data['consultant'];
$field = [
'purchase_power' => $data['purchase_power'],
'concept_awareness' => $data['concept_awareness'],
'preferred_class_time' => $data['preferred_class_time'],
'distance' => $data['distance_tow'],
'communication' => $data['communication'],
'promised_visit_time' => $data['promised_visit_time'],
'actual_visit_time' => $data['actual_visit_time'],
'call_intent' => $data['call_intent'],
'first_visit_status' => $data['first_visit_status'],
'second_visit_status' => $data['second_visit_status'],
'is_closed' => $data['is_closed'],
'staff_id' => $data['staff_id'],
'resource_id' => $id
];
if($six_id){
$six_log = $sixSpeed->where(['resource_id' => $id])->findOrEmpty()->toArray();
$six_save = getModifiedFields($six_log,$field);
if($six_save['is_save']){
$sixSpeedModificationLog->insert([
'customer_resource_id' => $id,
'operator_id' => $data['consultant'],
'campus_id' => $data['campus'],
'modified_field' => $six_save['modified_fields'],
'old_value' => $six_save['old_values'],
'new_value' => $six_save['new_values']
]);
}
$sixSpeed->where(['resource_id' => $id])->update($field);
}else{
$sixSpeed->insert($field);
}
}
return success("操作成功");
} }
/** /**
@ -98,6 +226,11 @@ class CustomerResourcesService extends BaseAdminService
} }
public function getPersonnelAll(){
$personnelModel = new Personnel();
return $personnelModel->select()->toArray();
}
public function getCampusAll(){ public function getCampusAll(){
$campusModel = new Campus(); $campusModel = new Campus();
return $campusModel->select()->toArray(); return $campusModel->select()->toArray();

16
niucloud/app/service/admin/six_speed/SixSpeedService.php

@ -12,6 +12,8 @@
namespace app\service\admin\six_speed; namespace app\service\admin\six_speed;
use app\model\six_speed\SixSpeed; use app\model\six_speed\SixSpeed;
use app\model\personnel\Personnel;
use app\model\customer_resources\CustomerResources;
use core\base\BaseAdminService; use core\base\BaseAdminService;
@ -39,7 +41,7 @@ class SixSpeedService extends BaseAdminService
$field = 'id,purchase_power,concept_awareness,preferred_class_time,distance,communication,promised_visit_time,actual_visit_time,call_intent,first_visit_status,second_visit_status,is_closed,staff_id,resource_id,created_at,updated_at,deleted_at'; $field = 'id,purchase_power,concept_awareness,preferred_class_time,distance,communication,promised_visit_time,actual_visit_time,call_intent,first_visit_status,second_visit_status,is_closed,staff_id,resource_id,created_at,updated_at,deleted_at';
$order = 'id desc'; $order = 'id desc';
$search_model = $this->model->withSearch(["id","purchase_power","concept_awareness","preferred_class_time","distance","communication","promised_visit_time","actual_visit_time","call_intent","first_visit_status","second_visit_status","is_closed","staff_id","resource_id"], $where)->field($field)->order($order); $search_model = $this->model->withSearch([], $where)->with(['personnel','customerResources'])->field($field)->order($order);
$list = $this->pageQuery($search_model); $list = $this->pageQuery($search_model);
return $list; return $list;
} }
@ -53,7 +55,7 @@ class SixSpeedService extends BaseAdminService
{ {
$field = 'id,purchase_power,concept_awareness,preferred_class_time,distance,communication,promised_visit_time,actual_visit_time,call_intent,first_visit_status,second_visit_status,is_closed,staff_id,resource_id,created_at,updated_at,deleted_at'; $field = 'id,purchase_power,concept_awareness,preferred_class_time,distance,communication,promised_visit_time,actual_visit_time,call_intent,first_visit_status,second_visit_status,is_closed,staff_id,resource_id,created_at,updated_at,deleted_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray(); $info = $this->model->field($field)->where([['id', "=", $id]])->with(['personnel','customerResources'])->findOrEmpty()->toArray();
return $info; return $info;
} }
@ -95,5 +97,15 @@ class SixSpeedService extends BaseAdminService
} }
public function getPersonnelAll(){
$personnelModel = new Personnel();
return $personnelModel->select()->toArray();
}
public function getCustomerResourcesAll(){
$customerResourcesModel = new CustomerResources();
return $customerResourcesModel->select()->toArray();
}
} }

8
niucloud/app/validate/six_speed/SixSpeed.php

@ -28,8 +28,6 @@ class SixSpeed extends BaseValidate
'promised_visit_time' => 'require', 'promised_visit_time' => 'require',
'call_intent' => 'require', 'call_intent' => 'require',
'is_closed' => 'require', 'is_closed' => 'require',
'staff_id' => 'require',
'resource_id' => 'require',
]; ];
protected $message = [ protected $message = [
@ -41,13 +39,11 @@ class SixSpeed extends BaseValidate
'promised_visit_time.require' => ['common_validate.require', ['promised_visit_time']], 'promised_visit_time.require' => ['common_validate.require', ['promised_visit_time']],
'call_intent.require' => ['common_validate.require', ['call_intent']], 'call_intent.require' => ['common_validate.require', ['call_intent']],
'is_closed.require' => ['common_validate.require', ['is_closed']], 'is_closed.require' => ['common_validate.require', ['is_closed']],
'staff_id.require' => ['common_validate.require', ['staff_id']],
'resource_id.require' => ['common_validate.require', ['resource_id']],
]; ];
protected $scene = [ protected $scene = [
"add" => ['purchase_power', 'concept_awareness', 'preferred_class_time', 'distance', 'communication', 'promised_visit_time', 'actual_visit_time', 'call_intent', 'first_visit_status', 'second_visit_status', 'is_closed', 'staff_id', 'resource_id'], "add" => ['purchase_power', 'concept_awareness', 'preferred_class_time', 'distance', 'communication', 'promised_visit_time', 'actual_visit_time', 'call_intent', 'first_visit_status', 'second_visit_status', 'is_closed'],
"edit" => ['purchase_power', 'concept_awareness', 'preferred_class_time', 'distance', 'communication', 'promised_visit_time', 'actual_visit_time', 'call_intent', 'first_visit_status', 'second_visit_status', 'is_closed', 'staff_id', 'resource_id'] "edit" => ['purchase_power', 'concept_awareness', 'preferred_class_time', 'distance', 'communication', 'promised_visit_time', 'actual_visit_time', 'call_intent', 'first_visit_status', 'second_visit_status', 'is_closed']
]; ];
} }

Loading…
Cancel
Save