Browse Source

1

yuhongzhe
于宏哲PHP 10 months ago
parent
commit
f33ba89f9f
  1. 23
      admin/src/app/api/service.ts
  2. 25
      admin/src/app/api/user_feedback.ts
  3. 54
      admin/src/app/lang/zh-cn/service.service.json
  4. 26
      admin/src/app/lang/zh-cn/user_feedback.user_feedback.json
  5. 31
      admin/src/app/views/customer_resources/components/customer-resources-edit.vue
  6. 48
      admin/src/app/views/customer_resources/customer_resources.vue
  7. 4
      admin/src/app/views/departments/departments.vue
  8. 3
      admin/src/app/views/member/components/edit-member.vue
  9. 54
      admin/src/app/views/order_table/components/order-table-edit.vue
  10. 599
      admin/src/app/views/service/components/service-edit.vue
  11. 531
      admin/src/app/views/service/service.vue
  12. 380
      admin/src/app/views/user_feedback/components/user-feedback-edit.vue
  13. 400
      admin/src/app/views/user_feedback/user_feedback.vue
  14. 4
      niucloud/app/adminapi/controller/customer_resources/CustomerResources.php
  15. 8
      niucloud/app/adminapi/controller/departments/Departments.php
  16. 9
      niucloud/app/adminapi/controller/order_table/OrderTable.php
  17. 7
      niucloud/app/adminapi/controller/service/Service.php
  18. 8
      niucloud/app/adminapi/controller/user_feedback/UserFeedback.php
  19. 1
      niucloud/app/adminapi/route/service.php
  20. 3
      niucloud/app/adminapi/route/user_feedback.php
  21. 13
      niucloud/app/model/customer_resources/CustomerResources.php
  22. 96
      niucloud/app/model/service/Service.php
  23. 44
      niucloud/app/model/user_feedback/UserFeedback.php
  24. 32
      niucloud/app/service/admin/customer_resources/CustomerResourcesService.php
  25. 13
      niucloud/app/service/admin/departments/DepartmentsService.php
  26. 12
      niucloud/app/service/admin/order_table/OrderTableService.php
  27. 2
      niucloud/app/service/admin/service/ServiceService.php
  28. 10
      niucloud/app/service/admin/user_feedback/UserFeedbackService.php
  29. 4
      niucloud/app/validate/order_table/OrderTable.php
  30. 6
      niucloud/app/validate/user_feedback/UserFeedback.php

23
admin/src/app/api/service.ts

@ -1,5 +1,7 @@
import request from '@/utils/request' import request from '@/utils/request'
// USER_CODE_BEGIN -- service // USER_CODE_BEGIN -- service
/** /**
* *
@ -7,7 +9,7 @@ import request from '@/utils/request'
* @returns * @returns
*/ */
export function getServiceList(params: Record<string, any>) { export function getServiceList(params: Record<string, any>) {
return request.get(`service/service`, { params }) return request.get(`service/service`, {params})
} }
/** /**
@ -16,7 +18,7 @@ export function getServiceList(params: Record<string, any>) {
* @returns * @returns
*/ */
export function getServiceInfo(id: number) { export function getServiceInfo(id: number) {
return request.get(`service/service/${id}`) return request.get(`service/service/${id}`);
} }
/** /**
@ -25,10 +27,7 @@ export function getServiceInfo(id: number) {
* @returns * @returns
*/ */
export function addService(params: Record<string, any>) { export function addService(params: Record<string, any>) {
return request.post('service/service', params, { return request.post('service/service', params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -38,10 +37,7 @@ export function addService(params: Record<string, any>) {
* @returns * @returns
*/ */
export function editService(params: Record<string, any>) { export function editService(params: Record<string, any>) {
return request.put(`service/service/${params.id}`, params, { return request.put(`service/service/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -50,10 +46,9 @@ export function editService(params: Record<string, any>) {
* @returns * @returns
*/ */
export function deleteService(id: number) { export function deleteService(id: number) {
return request.delete(`service/service/${id}`, { return request.delete(`service/service/${id}`, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
// USER_CODE_END -- service // USER_CODE_END -- service

25
admin/src/app/api/user_feedback.ts

@ -1,5 +1,7 @@
import request from '@/utils/request' import request from '@/utils/request'
// USER_CODE_BEGIN -- user_feedback // USER_CODE_BEGIN -- user_feedback
/** /**
* *
@ -7,7 +9,7 @@ import request from '@/utils/request'
* @returns * @returns
*/ */
export function getUserFeedbackList(params: Record<string, any>) { export function getUserFeedbackList(params: Record<string, any>) {
return request.get(`user_feedback/user_feedback`, { params }) return request.get(`user_feedback/user_feedback`, {params})
} }
/** /**
@ -16,7 +18,7 @@ export function getUserFeedbackList(params: Record<string, any>) {
* @returns * @returns
*/ */
export function getUserFeedbackInfo(id: number) { export function getUserFeedbackInfo(id: number) {
return request.get(`user_feedback/user_feedback/${id}`) return request.get(`user_feedback/user_feedback/${id}`);
} }
/** /**
@ -25,10 +27,7 @@ export function getUserFeedbackInfo(id: number) {
* @returns * @returns
*/ */
export function addUserFeedback(params: Record<string, any>) { export function addUserFeedback(params: Record<string, any>) {
return request.post('user_feedback/user_feedback', params, { return request.post('user_feedback/user_feedback', params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -38,10 +37,7 @@ export function addUserFeedback(params: Record<string, any>) {
* @returns * @returns
*/ */
export function editUserFeedback(params: Record<string, any>) { export function editUserFeedback(params: Record<string, any>) {
return request.put(`user_feedback/user_feedback/${params.id}`, params, { return request.put(`user_feedback/user_feedback/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -50,10 +46,11 @@ export function editUserFeedback(params: Record<string, any>) {
* @returns * @returns
*/ */
export function deleteUserFeedback(id: number) { export function deleteUserFeedback(id: number) {
return request.delete(`user_feedback/user_feedback/${id}`, { return request.delete(`user_feedback/user_feedback/${id}`, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true, }
showSuccessMessage: true,
}) export function getWithCustomerResourcesList(params: Record<string,any>){
return request.get('user_feedback/customer_resources_all', {params})
} }
// USER_CODE_END -- user_feedback // USER_CODE_END -- user_feedback

54
admin/src/app/lang/zh-cn/service.service.json

@ -1,29 +1,27 @@
{ {
"id": "服务编号", "serviceName":"服务名称",
"idPlaceholder": "请输入服务编号", "serviceNamePlaceholder":"请输入服务名称",
"serviceName": "服务名称", "previewImageUrl":"服务预览图",
"serviceNamePlaceholder": "请输入服务名称", "previewImageUrlPlaceholder":"请输入服务预览图",
"previewImageUrl": "服务预览图URL", "description":"服务描述",
"previewImageUrlPlaceholder": "请输入服务预览图URL", "descriptionPlaceholder":"请输入服务描述",
"description": "服务描述", "serviceType":"服务类型",
"descriptionPlaceholder": "请输入服务描述", "serviceTypePlaceholder":"请输入服务类型",
"serviceType": "服务类型", "executionRules":"服务执行规则",
"serviceTypePlaceholder": "请输入服务类型", "executionRulesPlaceholder":"请输入服务执行规则",
"executionRules": "服务执行规则", "staffReminder":"是否员工提醒",
"executionRulesPlaceholder": "请输入服务执行规则", "staffReminderPlaceholder":"请输入是否员工提醒",
"staffReminder": "是否员工提醒: 1-是, 0-否", "customerReminder":"是否客户提醒",
"staffReminderPlaceholder": "请输入是否员工提醒: 1-是, 0-否", "customerReminderPlaceholder":"请输入是否客户提醒",
"customerReminder": "是否客户提醒: 1-是, 0-否", "customerConfirmation":"是否客户确认",
"customerReminderPlaceholder": "请输入是否客户提醒: 1-是, 0-否", "customerConfirmationPlaceholder":"请输入是否客户确认",
"customerConfirmation": "是否客户确认: 1-是, 0-否", "customerFeedback":"客户反馈内容",
"customerConfirmationPlaceholder": "请输入是否客户确认: 1-是, 0-否", "customerFeedbackPlaceholder":"请输入客户反馈内容",
"customerFeedback": "客户反馈内容", "status":"状态",
"customerFeedbackPlaceholder": "请输入客户反馈内容", "statusPlaceholder":"请输入状态",
"status": "状态", "addService":"添加服务",
"statusPlaceholder": "请输入状态", "updateService":"编辑服务",
"addService": "添加服务", "serviceDeleteTips":"确定要删除该数据吗?",
"updateService": "编辑服务", "startDate":"请选择开始时间",
"serviceDeleteTips": "确定要删除该数据吗?", "endDate":"请选择结束时间"
"startDate": "请选择开始时间", }
"endDate": "请选择结束时间"
}

26
admin/src/app/lang/zh-cn/user_feedback.user_feedback.json

@ -1,15 +1,13 @@
{ {
"id": "反馈编号", "userId":"客户名称",
"idPlaceholder": "请输入反馈编号", "userIdPlaceholder":"全部",
"userId": "用户ID", "feedbackText":"反馈内容",
"userIdPlaceholder": "请输入用户ID", "feedbackTextPlaceholder":"请输入反馈内容",
"feedbackText": "反馈内容", "attachmentUrl":"附件",
"feedbackTextPlaceholder": "请输入反馈内容", "attachmentUrlPlaceholder":"请输入附件",
"attachmentUrl": "附件URL(OSS对象存储)", "addUserFeedback":"添加用户反馈信息",
"attachmentUrlPlaceholder": "请输入附件URL(OSS对象存储)", "updateUserFeedback":"查看用户反馈信息",
"addUserFeedback": "添加用户反馈信息", "userFeedbackDeleteTips":"确定要删除该数据吗?",
"updateUserFeedback": "编辑用户反馈信息", "startDate":"请选择开始时间",
"userFeedbackDeleteTips": "确定要删除该数据吗?", "endDate":"请选择结束时间"
"startDate": "请选择开始时间", }
"endDate": "请选择结束时间"
}

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

@ -230,6 +230,26 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="会员标签">
<el-select
v-model="formData.member_label"
multiple
collapse-tags
placeholder="请选择会员标签"
class="input-width"
>
<el-option
:label="item['label_name']"
:value="item['label_id']"
v-for="(item, index) in labelSelectData"
:key="index"
/>
</el-select>
</el-form-item>
</el-form> </el-form>
</el-tab-pane> </el-tab-pane>
@ -410,6 +430,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 { getMemberLabelAll } from '@/app/api/member'
import { import {
addCustomerResources, addCustomerResources,
editCustomerResources, editCustomerResources,
@ -448,6 +469,7 @@ const initialFormData = {
initial_intent: '', initial_intent: '',
campus: '', campus: '',
status: '', status: '',
member_label:'',
purchase_power: '', purchase_power: '',
concept_awareness: '', concept_awareness: '',
@ -461,6 +483,15 @@ const initialFormData = {
second_visit_status: '', second_visit_status: '',
is_closed: '', is_closed: '',
} }
const labelSelectData: any = ref(null)
//
const getMemberLabelAllFn = async () => {
labelSelectData.value = await (await getMemberLabelAll()).data
}
getMemberLabelAllFn()
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>() const formRef = ref<FormInstance>()

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

@ -35,6 +35,24 @@
<el-input v-model="customerResourcesTable.searchParam.phone_number" <el-input v-model="customerResourcesTable.searchParam.phone_number"
:placeholder="t('phoneNumberPlaceholder')" /> :placeholder="t('phoneNumberPlaceholder')" />
</el-form-item> </el-form-item>
<el-form-item label="会员标签" prop="member_label">
<el-select
v-model="customerResourcesTable.searchParam.member_label"
collapse-tags
clearable
placeholder="请选择会员标签"
class="input-width"
>
<el-option label="会员标签" value="" />
<el-option
:label="item['label_name']"
:value="item['label_id']"
v-for="(item, index) in labelSelectData"
:key="index"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间"> <el-form-item label="创建时间">
@ -93,6 +111,26 @@
:show-overflow-tooltip="true" /> :show-overflow-tooltip="true" />
<el-table-column
prop="member_label"
label="会员标签"
min-width="120"
align="center"
>
<template #default="{ row }">
<div class="flex flex-col items-center">
<div
v-for="(item, key) in row.member_label_array"
class="my-[3px]"
:key="key"
>
<el-tag type="info">{{ item.label_name }}</el-tag>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="created_at" label="添加时间" min-width="120" :show-overflow-tooltip="true" /> <el-table-column prop="created_at" label="添加时间" min-width="120" :show-overflow-tooltip="true" />
<el-table-column prop="updated_at" label="修改时间" min-width="120" :show-overflow-tooltip="true" /> <el-table-column prop="updated_at" label="修改时间" min-width="120" :show-overflow-tooltip="true" />
@ -160,8 +198,9 @@
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 Fp from '@/app/views/customer_resources/components/fp.vue' import Fp from '@/app/views/customer_resources/components/fp.vue'
import Order from '@/app/views/order_table/components/order-table-edit.vue' import Order from '@/app/views/order_table/components/order-table-edit.vue'
import Tc from '@/app/views/tc_dialog/tc_dialog.vue' import Tc from '@/app/views/tc_dialog/tc_dialog.vue'
import { getMemberLabelAll } from '@/app/api/member'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
@ -179,6 +218,7 @@
"age": "", "age": "",
"gender": "", "gender": "",
"phone_number": "", "phone_number": "",
"member_label" : "",
'type': '', 'type': '',
"created_at" : "", "created_at" : "",
"updated_at" : "" "updated_at" : ""
@ -195,6 +235,12 @@
// const type = pageName == '' ? 'yjfp' : 'khzy'; // const type = pageName == '' ? 'yjfp' : 'khzy';
//
const labelSelectData = ref([])
const getMemberLabelAllFn = async () => {
labelSelectData.value = await (await getMemberLabelAll()).data
}
getMemberLabelAllFn()
const modificationLog = (id : number) => { const modificationLog = (id : number) => {

4
admin/src/app/views/departments/departments.vue

@ -25,7 +25,7 @@
</el-form-item> </el-form-item>
<el-form-item <el-form-item
:label="t('parentDepartmentId')" label="上级部门"
prop="parent_department_id" prop="parent_department_id"
> >
<el-select <el-select
@ -72,7 +72,7 @@
<el-table-column <el-table-column
prop="parent_department_id_name" prop="parent_department_id_name"
:label="t('parentDepartmentId')" label="上级部门"
min-width="120" min-width="120"
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
/> />

3
admin/src/app/views/member/components/edit-member.vue

@ -47,6 +47,7 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('memberLabel')" v-if="type == 'member_label'"> <el-form-item :label="t('memberLabel')" v-if="type == 'member_label'">
<el-select <el-select
v-model="saveData.member_label" v-model="saveData.member_label"
@ -63,6 +64,8 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<div v-if="type == 'member_level'"> <div v-if="type == 'member_level'">
<el-form-item :label="t('memberLevelUpdate')" prop="member_level"> <el-form-item :label="t('memberLevelUpdate')" prop="member_level">
<el-select <el-select

54
admin/src/app/views/order_table/components/order-table-edit.vue

@ -12,7 +12,7 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<!--
<el-form-item :label="t('orderStatus')" prop="order_status"> <el-form-item :label="t('orderStatus')" prop="order_status">
<el-select class="input-width" v-model="formData.order_status" clearable :placeholder="t('orderStatusPlaceholder')"> <el-select class="input-width" v-model="formData.order_status" clearable :placeholder="t('orderStatusPlaceholder')">
<el-option label="请选择" value=""></el-option> <el-option label="请选择" value=""></el-option>
@ -23,7 +23,7 @@
:value="item.value" :value="item.value"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item> -->
<el-form-item :label="t('paymentType')" prop="payment_type"> <el-form-item :label="t('paymentType')" prop="payment_type">
<el-select class="input-width" v-model="formData.payment_type" clearable :placeholder="t('paymentTypePlaceholder')"> <el-select class="input-width" v-model="formData.payment_type" clearable :placeholder="t('paymentTypePlaceholder')">
@ -36,22 +36,25 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('courseId')" prop="course_id">
<el-select class="input-width" v-model="formData.course_id" clearable :placeholder="t('courseIdPlaceholder')" @change="handleCourseChange">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in courseIdList"
:key="index"
:label="item['course_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('orderAmount')" prop="order_amount"> <el-form-item :label="t('orderAmount')" prop="order_amount">
<el-input v-model="formData.order_amount" clearable :placeholder="t('orderAmountPlaceholder')" class="input-width" /> <el-input v-model="formData.order_amount" :placeholder="t('orderAmountPlaceholder')" class="input-width" disabled/>
</el-form-item> </el-form-item>
<el-form-item :label="t('courseId')" prop="course_id">
<el-select class="input-width" v-model="formData.course_id" clearable :placeholder="t('courseIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in courseIdList"
:key="index"
:label="item['course_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('classId')" prop="class_id"> <el-form-item :label="t('classId')" prop="class_id">
<el-select class="input-width" v-model="formData.class_id" clearable :placeholder="t('classIdPlaceholder')"> <el-select class="input-width" v-model="formData.class_id" clearable :placeholder="t('classIdPlaceholder')">
@ -88,13 +91,17 @@ import { addOrderTable, editOrderTable, getOrderTableInfo, getWithCustomerResour
let showDialog = ref(false) let showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
function handleCourseChange(selectedId) {
const selectedCourse = courseIdList.value.find(item => item.id === selectedId)
formData.order_amount = selectedCourse ? selectedCourse.price : ''
}
/** /**
* 表单数据 * 表单数据
*/ */
const initialFormData = { const initialFormData = {
id: '', id: '',
resource_id: '', resource_id: '',
order_status: '', // order_status: '',
payment_type: '', payment_type: '',
order_amount: '', order_amount: '',
course_id: '', course_id: '',
@ -110,11 +117,6 @@ const formRules = computed(() => {
resource_id: [ resource_id: [
{ required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' }, { required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' },
]
,
order_status: [
{ required: true, message: t('orderStatusPlaceholder'), trigger: 'blur' },
] ]
, ,
payment_type: [ payment_type: [
@ -168,12 +170,12 @@ const confirm = async (formEl: FormInstance | undefined) => {
} }
// //
let order_statusList = ref([]) // let order_statusList = ref([])
const order_statusDictList = async () => { // const order_statusDictList = async () => {
order_statusList.value = await (await useDictionary('order_status')).data.dictionary // order_statusList.value = await (await useDictionary('order_status')).data.dictionary
} // }
order_statusDictList(); // order_statusDictList();
watch(() => order_statusList.value, () => { formData.order_status = order_statusList.value[0].value }) // watch(() => order_statusList.value, () => { formData.order_status = order_statusList.value[0].value })
let payment_typeList = ref([]) let payment_typeList = ref([])
const payment_typeDictList = async () => { const payment_typeDictList = async () => {
payment_typeList.value = await (await useDictionary('payment_type')).data.dictionary payment_typeList.value = await (await useDictionary('payment_type')).data.dictionary

599
admin/src/app/views/service/components/service-edit.vue

@ -1,311 +1,288 @@
<template> <template>
<el-dialog <el-dialog v-model="showDialog" :title="formData.id ? t('updateService') : t('addService')" 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('updateService') : t('addService')" <el-form-item :label="t('serviceName')" prop="service_name">
width="50%" <el-input v-model="formData.service_name" clearable :placeholder="t('serviceNamePlaceholder')" class="input-width" />
class="diy-dialog-wrap" </el-form-item>
:destroy-on-close="true"
> <el-form-item :label="t('previewImageUrl')">
<el-form <upload-image v-model="formData.preview_image_url" />
:model="formData" </el-form-item>
label-width="120px"
ref="formRef" <el-form-item :label="t('description')" prop="description">
:rules="formRules" <el-input v-model="formData.description" clearable :placeholder="t('descriptionPlaceholder')" class="input-width" />
class="page-form" </el-form-item>
v-loading="loading"
> <el-form-item :label="t('serviceType')" prop="service_type">
<el-form-item :label="t('serviceName')" prop="service_name"> <el-input v-model="formData.service_type" clearable :placeholder="t('serviceTypePlaceholder')" class="input-width" />
<el-input </el-form-item>
v-model="formData.service_name"
clearable <el-form-item :label="t('executionRules')" prop="execution_rules">
:placeholder="t('serviceNamePlaceholder')" <el-input v-model="formData.execution_rules" clearable :placeholder="t('executionRulesPlaceholder')" class="input-width" />
class="input-width" </el-form-item>
/>
</el-form-item> <el-form-item :label="t('staffReminder')" prop="staff_reminder">
<el-select class="input-width" v-model="formData.staff_reminder" clearable :placeholder="t('staffReminderPlaceholder')">
<el-form-item :label="t('previewImageUrl')"> <el-option label="请选择" value=""></el-option>
<el-input <el-option
v-model="formData.preview_image_url" v-for="(item, index) in staff_reminderList"
clearable :key="index"
:placeholder="t('previewImageUrlPlaceholder')" :label="item.name"
class="input-width" :value="item.value"
/> />
</el-form-item> </el-select>
</el-form-item>
<el-form-item :label="t('description')" prop="description">
<el-input <el-form-item :label="t('customerReminder')" prop="customer_reminder">
v-model="formData.description" <el-select class="input-width" v-model="formData.customer_reminder" clearable :placeholder="t('customerReminderPlaceholder')">
clearable <el-option label="请选择" value=""></el-option>
:placeholder="t('descriptionPlaceholder')" <el-option
class="input-width" v-for="(item, index) in customer_reminderList"
/> :key="index"
</el-form-item> :label="item.name"
:value="item.value"
<el-form-item :label="t('serviceType')" prop="service_type"> />
<el-input </el-select>
v-model="formData.service_type" </el-form-item>
clearable
:placeholder="t('serviceTypePlaceholder')" <el-form-item :label="t('customerConfirmation')" prop="customer_confirmation">
class="input-width" <el-select class="input-width" v-model="formData.customer_confirmation" clearable :placeholder="t('customerConfirmationPlaceholder')">
/> <el-option label="请选择" value=""></el-option>
</el-form-item> <el-option
v-for="(item, index) in customer_confirmationList"
<el-form-item :label="t('executionRules')" prop="execution_rules"> :key="index"
<el-input :label="item.name"
v-model="formData.execution_rules" :value="item.value"
clearable />
:placeholder="t('executionRulesPlaceholder')" </el-select>
class="input-width" </el-form-item>
/>
</el-form-item> <el-form-item :label="t('customerFeedback')" >
<el-input v-model="formData.customer_feedback" clearable :placeholder="t('customerFeedbackPlaceholder')" class="input-width" />
<el-form-item :label="t('staffReminder')" prop="staff_reminder"> </el-form-item>
<el-input
v-model="formData.staff_reminder" <el-form-item :label="t('status')" prop="status">
clearable <el-select class="input-width" v-model="formData.status" clearable :placeholder="t('statusPlaceholder')">
:placeholder="t('staffReminderPlaceholder')" <el-option label="请选择" value=""></el-option>
class="input-width" <el-option
/> v-for="(item, index) in statusList"
</el-form-item> :key="index"
:label="item.name"
<el-form-item :label="t('customerReminder')" prop="customer_reminder"> :value="item.value"
<el-input />
v-model="formData.customer_reminder" </el-select>
clearable </el-form-item>
:placeholder="t('customerReminderPlaceholder')"
class="input-width" </el-form>
/>
</el-form-item> <template #footer>
<span class="dialog-footer">
<el-form-item <el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
:label="t('customerConfirmation')" <el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
prop="customer_confirmation" t('confirm')
> }}</el-button>
<el-input </span>
v-model="formData.customer_confirmation" </template>
clearable </el-dialog>
:placeholder="t('customerConfirmationPlaceholder')" </template>
class="input-width"
/> <script lang="ts" setup>
</el-form-item> import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
<el-form-item :label="t('customerFeedback')"> import { t } from '@/lang'
<el-input import type { FormInstance } from 'element-plus'
v-model="formData.customer_feedback" import { addService, editService, getServiceInfo } from '@/app/api/service'
clearable
:placeholder="t('customerFeedbackPlaceholder')" let showDialog = ref(false)
class="input-width" const loading = ref(false)
/>
</el-form-item> /**
* 表单数据
<el-form-item :label="t('status')" prop="status"> */
<el-input const initialFormData = {
v-model="formData.status" id: '',
clearable service_name: '',
:placeholder="t('statusPlaceholder')" preview_image_url: '',
class="input-width" description: '',
/> service_type: '',
</el-form-item> execution_rules: '',
</el-form> staff_reminder: '',
customer_reminder: '',
<template #footer> customer_confirmation: '',
<span class="dialog-footer"> customer_feedback: '',
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button> status: '',
<el-button }
type="primary" const formData: Record<string, any> = reactive({ ...initialFormData })
:loading="loading"
@click="confirm(formRef)" const formRef = ref<FormInstance>()
>{{ t('confirm') }}</el-button
> //
</span> const formRules = computed(() => {
</template> return {
</el-dialog> service_name: [
</template> { required: true, message: t('serviceNamePlaceholder'), trigger: 'blur' },
<script lang="ts" setup> ]
import { ref, reactive, computed, watch } from 'vue' ,
import { useDictionary } from '@/app/api/dict' preview_image_url: [
import { t } from '@/lang' { required: true, message: t('previewImageUrlPlaceholder'), trigger: 'blur' },
import type { FormInstance } from 'element-plus'
import { addService, editService, getServiceInfo } from '@/app/api/service' ]
,
let showDialog = ref(false) description: [
const loading = ref(false) { required: true, message: t('descriptionPlaceholder'), trigger: 'blur' },
/** ]
* 表单数据 ,
*/ service_type: [
const initialFormData = { { required: true, message: t('serviceTypePlaceholder'), trigger: 'blur' },
id: '',
service_name: '', ]
preview_image_url: '', ,
description: '', execution_rules: [
service_type: '', { required: true, message: t('executionRulesPlaceholder'), trigger: 'blur' },
execution_rules: '',
staff_reminder: '', ]
customer_reminder: '', ,
customer_confirmation: '', staff_reminder: [
customer_feedback: '', { required: true, message: t('staffReminderPlaceholder'), trigger: 'blur' },
status: '',
} ]
const formData: Record<string, any> = reactive({ ...initialFormData }) ,
customer_reminder: [
const formRef = ref<FormInstance>() { required: true, message: t('customerReminderPlaceholder'), trigger: 'blur' },
// ]
const formRules = computed(() => { ,
return { customer_confirmation: [
service_name: [ { required: true, message: t('customerConfirmationPlaceholder'), trigger: 'blur' },
{ required: true, message: t('serviceNamePlaceholder'), trigger: 'blur' },
], ]
preview_image_url: [ ,
{ customer_feedback: [
required: true, { required: true, message: t('customerFeedbackPlaceholder'), trigger: 'blur' },
message: t('previewImageUrlPlaceholder'),
trigger: 'blur', ]
}, ,
], status: [
description: [ { required: true, message: t('statusPlaceholder'), trigger: 'blur' },
{ required: true, message: t('descriptionPlaceholder'), trigger: 'blur' },
], ]
service_type: [ ,
{ required: true, message: t('serviceTypePlaceholder'), trigger: 'blur' }, }
], })
execution_rules: [
{ const emit = defineEmits(['complete'])
required: true,
message: t('executionRulesPlaceholder'), /**
trigger: 'blur', * 确认
}, * @param formEl
], */
staff_reminder: [ const confirm = async (formEl: FormInstance | undefined) => {
{ if (loading.value || !formEl) return
required: true, let save = formData.id ? editService : addService
message: t('staffReminderPlaceholder'),
trigger: 'blur', await formEl.validate(async (valid) => {
}, if (valid) {
], loading.value = true
customer_reminder: [
{ let data = formData
required: true,
message: t('customerReminderPlaceholder'), save(data).then(res => {
trigger: 'blur', loading.value = false
}, showDialog.value = false
], emit('complete')
customer_confirmation: [ }).catch(err => {
{ loading.value = false
required: true, })
message: t('customerConfirmationPlaceholder'), }
trigger: 'blur', })
}, }
],
customer_feedback: [ //
{ let staff_reminderList = ref([])
required: true, const staff_reminderDictList = async () => {
message: t('customerFeedbackPlaceholder'), staff_reminderList.value = await (await useDictionary('global_true_or_false')).data.dictionary
trigger: 'blur', }
}, staff_reminderDictList();
], watch(() => staff_reminderList.value, () => { formData.staff_reminder = staff_reminderList.value[0].value })
status: [ let customer_reminderList = ref([])
{ required: true, message: t('statusPlaceholder'), trigger: 'blur' }, const customer_reminderDictList = async () => {
], customer_reminderList.value = await (await useDictionary('global_true_or_false')).data.dictionary
} }
}) customer_reminderDictList();
watch(() => customer_reminderList.value, () => { formData.customer_reminder = customer_reminderList.value[0].value })
const emit = defineEmits(['complete']) let customer_confirmationList = ref([])
const customer_confirmationDictList = async () => {
/** customer_confirmationList.value = await (await useDictionary('global_true_or_false')).data.dictionary
* 确认 }
* @param formEl customer_confirmationDictList();
*/ watch(() => customer_confirmationList.value, () => { formData.customer_confirmation = customer_confirmationList.value[0].value })
const confirm = async (formEl: FormInstance | undefined) => { let statusList = ref([])
if (loading.value || !formEl) return const statusDictList = async () => {
let save = formData.id ? editService : addService statusList.value = await (await useDictionary('SiteStatus')).data.dictionary
}
await formEl.validate(async (valid) => { statusDictList();
if (valid) { watch(() => statusList.value, () => { formData.status = statusList.value[0].value })
loading.value = true
let data = formData const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
save(data) loading.value = true
.then((res) => { if(row){
loading.value = false const data = await (await getServiceInfo(row.id)).data
showDialog.value = false if (data) Object.keys(formData).forEach((key: string) => {
emit('complete') if (data[key] != undefined) formData[key] = data[key]
}) })
.catch((err) => { }
loading.value = false loading.value = false
}) }
}
}) //
} const mobileVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) {
// callback(new Error(t('generateMobile')))
} else {
const setFormData = async (row: any = null) => { callback()
Object.assign(formData, initialFormData) }
loading.value = true }
if (row) {
const data = await (await getServiceInfo(row.id)).data //
if (data) const idCardVerify = (rule: any, value: any, callback: any) => {
Object.keys(formData).forEach((key: string) => { 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)) {
if (data[key] != undefined) formData[key] = data[key] callback(new Error(t('generateIdCard')))
}) } else {
} callback()
loading.value = false }
} }
// //
const mobileVerify = (rule: any, value: any, callback: any) => { const emailVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) { if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateMobile'))) callback(new Error(t('generateEmail')))
} else { } else {
callback() callback()
} }
} }
// //
const idCardVerify = (rule: any, value: any, callback: any) => { const numberVerify = (rule: any, value: any, callback: any) => {
if ( if (!Number.isInteger(value)) {
value && callback(new Error(t('generateNumber')))
!/^[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 { defineExpose({
callback() showDialog,
} setFormData
} })
</script>
//
const emailVerify = (rule: any, value: any, callback: any) => { <style lang="scss" scoped></style>
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) { <style lang="scss">
callback(new Error(t('generateEmail'))) .diy-dialog-wrap .el-form-item__label{
} else { height: auto !important;
callback() }
} </style>
}
//
const numberVerify = (rule: any, value: any, callback: any) => {
if (!Number.isInteger(value)) {
callback(new Error(t('generateNumber')))
} else {
callback()
}
}
defineExpose({
showDialog,
setFormData,
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label {
height: auto !important;
}
</style>

531
admin/src/app/views/service/service.vue

@ -1,321 +1,210 @@
<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('addService') }} <el-button type="primary" @click="addEvent">
</el-button> {{ t('addService') }}
</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="serviceTable.searchParam" ref="searchFormRef">
> <el-form-item :label="t('serviceName')" prop="service_name">
<el-form <el-input v-model="serviceTable.searchParam.service_name" :placeholder="t('serviceNamePlaceholder')" />
:inline="true" </el-form-item>
:model="serviceTable.searchParam" <el-form-item :label="t('serviceType')" prop="service_type">
ref="searchFormRef" <el-input v-model="serviceTable.searchParam.service_type" :placeholder="t('serviceTypePlaceholder')" />
> </el-form-item>
<el-form-item :label="t('serviceName')" prop="service_name">
<el-input <el-form-item :label="t('status')" prop="status">
v-model="serviceTable.searchParam.service_name" <el-select class="w-[280px]" v-model="serviceTable.searchParam.status" clearable :placeholder="t('statusPlaceholder')">
:placeholder="t('serviceNamePlaceholder')" <el-option label="全部" value=""></el-option>
/> <el-option
</el-form-item> v-for="(item, index) in statusList"
<el-form-item :label="t('previewImageUrl')" prop="preview_image_url"> :key="index"
<el-input :label="item.name"
v-model="serviceTable.searchParam.preview_image_url" :value="item.value"
:placeholder="t('previewImageUrlPlaceholder')" />
/> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('description')" prop="description">
<el-input <el-form-item>
v-model="serviceTable.searchParam.description" <el-button type="primary" @click="loadServiceList()">{{ t('search') }}</el-button>
:placeholder="t('descriptionPlaceholder')" <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
/> </el-form-item>
</el-form-item> </el-form>
<el-form-item :label="t('serviceType')" prop="service_type"> </el-card>
<el-input
v-model="serviceTable.searchParam.service_type" <div class="mt-[10px]">
:placeholder="t('serviceTypePlaceholder')" <el-table :data="serviceTable.data" size="large" v-loading="serviceTable.loading">
/> <template #empty>
</el-form-item> <span>{{ !serviceTable.loading ? t('emptyData') : '' }}</span>
<el-form-item :label="t('executionRules')" prop="execution_rules"> </template>
<el-input <el-table-column prop="service_name" :label="t('serviceName')" min-width="120" :show-overflow-tooltip="true"/>
v-model="serviceTable.searchParam.execution_rules"
:placeholder="t('executionRulesPlaceholder')" <el-table-column prop="description" :label="t('description')" min-width="120" :show-overflow-tooltip="true"/>
/>
</el-form-item> <el-table-column prop="service_type" :label="t('serviceType')" min-width="120" :show-overflow-tooltip="true"/>
<el-form-item :label="t('staffReminder')" prop="staff_reminder">
<el-input <el-table-column prop="customer_feedback" :label="t('customerFeedback')" min-width="120" :show-overflow-tooltip="true"/>
v-model="serviceTable.searchParam.staff_reminder"
:placeholder="t('staffReminderPlaceholder')" <el-table-column :label="t('status')" min-width="180" align="center" :show-overflow-tooltip="true">
/> <template #default="{ row }">
</el-form-item> <div v-for="(item, index) in statusList">
<el-form-item :label="t('customerReminder')" prop="customer_reminder"> <div v-if="item.value == row.status">{{ item.name }}</div>
<el-input </div>
v-model="serviceTable.searchParam.customer_reminder" </template>
:placeholder="t('customerReminderPlaceholder')" </el-table-column>
/>
</el-form-item> <el-table-column :label="t('operation')" fixed="right" min-width="120">
<el-form-item <template #default="{ row }">
:label="t('customerConfirmation')" <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
prop="customer_confirmation" <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
> </template>
<el-input </el-table-column>
v-model="serviceTable.searchParam.customer_confirmation"
:placeholder="t('customerConfirmationPlaceholder')" </el-table>
/> <div class="mt-[16px] flex justify-end">
</el-form-item> <el-pagination v-model:current-page="serviceTable.page" v-model:page-size="serviceTable.limit"
<el-form-item :label="t('customerFeedback')" prop="customer_feedback"> layout="total, sizes, prev, pager, next, jumper" :total="serviceTable.total"
<el-input @size-change="loadServiceList()" @current-change="loadServiceList" />
v-model="serviceTable.searchParam.customer_feedback" </div>
:placeholder="t('customerFeedbackPlaceholder')" </div>
/>
</el-form-item> <edit ref="editServiceDialog" @complete="loadServiceList" />
<el-form-item :label="t('status')" prop="status"> </el-card>
<el-input </div>
v-model="serviceTable.searchParam.status" </template>
:placeholder="t('statusPlaceholder')"
/> <script lang="ts" setup>
</el-form-item> import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
<el-form-item> import { useDictionary } from '@/app/api/dict'
<el-button type="primary" @click="loadServiceList()">{{ import { getServiceList, deleteService } from '@/app/api/service'
t('search') import { img } from '@/utils/common'
}}</el-button> import { ElMessageBox,FormInstance } from 'element-plus'
<el-button @click="resetForm(searchFormRef)">{{ import Edit from '@/app/views/service/components/service-edit.vue'
t('reset') import { useRoute } from 'vue-router'
}}</el-button> const route = useRoute()
</el-form-item> const pageName = route.meta.title;
</el-form>
</el-card> let serviceTable = reactive({
page: 1,
<div class="mt-[10px]"> limit: 10,
<el-table total: 0,
:data="serviceTable.data" loading: true,
size="large" data: [],
v-loading="serviceTable.loading" searchParam:{
> "service_name":"",
<template #empty> "service_type":"",
<span>{{ !serviceTable.loading ? t('emptyData') : '' }}</span> "status":""
</template> }
<el-table-column })
prop="service_name"
:label="t('serviceName')" const searchFormRef = ref<FormInstance>()
min-width="120"
:show-overflow-tooltip="true" //
/> const selectData = ref<any[]>([])
<el-table-column //
prop="preview_image_url" const staff_reminderList = ref([] as any[])
:label="t('previewImageUrl')" const staff_reminderDictList = async () => {
min-width="120" staff_reminderList.value = await (await useDictionary('global_true_or_false')).data.dictionary
:show-overflow-tooltip="true" }
/> staff_reminderDictList();
const customer_reminderList = ref([] as any[])
<el-table-column const customer_reminderDictList = async () => {
prop="description" customer_reminderList.value = await (await useDictionary('global_true_or_false')).data.dictionary
:label="t('description')" }
min-width="120" customer_reminderDictList();
:show-overflow-tooltip="true" const customer_confirmationList = ref([] as any[])
/> const customer_confirmationDictList = async () => {
customer_confirmationList.value = await (await useDictionary('global_true_or_false')).data.dictionary
<el-table-column }
prop="service_type" customer_confirmationDictList();
:label="t('serviceType')" const statusList = ref([] as any[])
min-width="120" const statusDictList = async () => {
:show-overflow-tooltip="true" statusList.value = await (await useDictionary('SiteStatus')).data.dictionary
/> }
statusDictList();
<el-table-column
prop="execution_rules" /**
:label="t('executionRules')" * 获取服务列表
min-width="120" */
:show-overflow-tooltip="true" const loadServiceList = (page: number = 1) => {
/> serviceTable.loading = true
serviceTable.page = page
<el-table-column
prop="staff_reminder" getServiceList({
:label="t('staffReminder')" page: serviceTable.page,
min-width="120" limit: serviceTable.limit,
:show-overflow-tooltip="true" ...serviceTable.searchParam
/> }).then(res => {
serviceTable.loading = false
<el-table-column serviceTable.data = res.data.data
prop="customer_reminder" serviceTable.total = res.data.total
:label="t('customerReminder')" }).catch(() => {
min-width="120" serviceTable.loading = false
:show-overflow-tooltip="true" })
/> }
loadServiceList()
<el-table-column
prop="customer_confirmation" const editServiceDialog: Record<string, any> | null = ref(null)
:label="t('customerConfirmation')"
min-width="120" /**
:show-overflow-tooltip="true" * 添加服务
/> */
const addEvent = () => {
<el-table-column editServiceDialog.value.setFormData()
prop="customer_feedback" editServiceDialog.value.showDialog = true
:label="t('customerFeedback')" }
min-width="120"
:show-overflow-tooltip="true" /**
/> * 编辑服务
* @param data
<el-table-column */
prop="status" const editEvent = (data: any) => {
:label="t('status')" editServiceDialog.value.setFormData(data)
min-width="120" editServiceDialog.value.showDialog = true
:show-overflow-tooltip="true" }
/>
/**
<el-table-column * 删除服务
:label="t('operation')" */
fixed="right" const deleteEvent = (id: number) => {
min-width="120" ElMessageBox.confirm(t('serviceDeleteTips'), t('warning'),
> {
<template #default="{ row }"> confirmButtonText: t('confirm'),
<el-button type="primary" link @click="editEvent(row)">{{ cancelButtonText: t('cancel'),
t('edit') type: 'warning',
}}</el-button> }
<el-button type="primary" link @click="deleteEvent(row.id)">{{ ).then(() => {
t('delete') deleteService(id).then(() => {
}}</el-button> loadServiceList()
</template> }).catch(() => {
</el-table-column> })
</el-table> })
<div class="mt-[16px] flex justify-end"> }
<el-pagination
v-model:current-page="serviceTable.page"
v-model:page-size="serviceTable.limit"
layout="total, sizes, prev, pager, next, jumper" const resetForm = (formEl: FormInstance | undefined) => {
:total="serviceTable.total" if (!formEl) return
@size-change="loadServiceList()" formEl.resetFields()
@current-change="loadServiceList" loadServiceList()
/> }
</div> </script>
</div>
<style lang="scss" scoped>
<edit ref="editServiceDialog" @complete="loadServiceList" /> /* 多行超出隐藏 */
</el-card> .multi-hidden {
</div> word-break: break-all;
</template> text-overflow: ellipsis;
overflow: hidden;
<script lang="ts" setup> display: -webkit-box;
import { reactive, ref, watch } from 'vue' -webkit-line-clamp: 2;
import { t } from '@/lang' -webkit-box-orient: vertical;
import { useDictionary } from '@/app/api/dict' }
import { getServiceList, deleteService } from '@/app/api/service' </style>
import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus'
import Edit from '@/app/views/service/components/service-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
let serviceTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam: {
service_name: '',
preview_image_url: '',
description: '',
service_type: '',
execution_rules: '',
staff_reminder: '',
customer_reminder: '',
customer_confirmation: '',
customer_feedback: '',
status: '',
},
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取服务列表
*/
const loadServiceList = (page: number = 1) => {
serviceTable.loading = true
serviceTable.page = page
getServiceList({
page: serviceTable.page,
limit: serviceTable.limit,
...serviceTable.searchParam,
})
.then((res) => {
serviceTable.loading = false
serviceTable.data = res.data.data
serviceTable.total = res.data.total
})
.catch(() => {
serviceTable.loading = false
})
}
loadServiceList()
const editServiceDialog: Record<string, any> | null = ref(null)
/**
* 添加服务
*/
const addEvent = () => {
editServiceDialog.value.setFormData()
editServiceDialog.value.showDialog = true
}
/**
* 编辑服务
* @param data
*/
const editEvent = (data: any) => {
editServiceDialog.value.setFormData(data)
editServiceDialog.value.showDialog = true
}
/**
* 删除服务
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('serviceDeleteTips'), t('warning'), {
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteService(id)
.then(() => {
loadServiceList()
})
.catch(() => {})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadServiceList()
}
</script>
<style lang="scss" scoped>
/* 多行超出隐藏 */
.multi-hidden {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>

380
admin/src/app/views/user_feedback/components/user-feedback-edit.vue

@ -1,205 +1,175 @@
<template> <template>
<el-dialog <el-dialog v-model="showDialog" :title="formData.id ? t('updateUserFeedback') : t('addUserFeedback')" 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('updateUserFeedback') : t('addUserFeedback')" <el-form-item :label="t('userId')" >
width="50%" <el-select class="input-width" v-model="formData.user_id" clearable :placeholder="t('userIdPlaceholder')" disabled>
class="diy-dialog-wrap" <el-option label="请选择" value=""></el-option>
:destroy-on-close="true" <el-option
> v-for="(item, index) in userIdList"
<el-form :key="index"
:model="formData" :label="item['name']"
label-width="120px" :value="item['id']"
ref="formRef" />
:rules="formRules" </el-select>
class="page-form" </el-form-item>
v-loading="loading"
> <el-form-item :label="t('feedbackText')" >
<el-form-item :label="t('userId')" prop="user_id"> <el-input disabled v-model="formData.feedback_text" type="textarea" rows="4" clearable :placeholder="t('feedbackTextPlaceholder')" class="input-width"/>
<el-input </el-form-item>
v-model="formData.user_id" <el-form-item :label="t('attachmentUrl')" >
clearable <upload-file v-model="formData.attachment_url" disabled/>
:placeholder="t('userIdPlaceholder')" </el-form-item>
class="input-width"
/> </el-form>
</el-form-item>
<template #footer>
<el-form-item :label="t('feedbackText')" prop="feedback_text"> <span class="dialog-footer">
<el-input <el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
v-model="formData.feedback_text" <el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
clearable t('confirm')
:placeholder="t('feedbackTextPlaceholder')" }}</el-button>
class="input-width" </span>
/> </template>
</el-form-item> </el-dialog>
</template>
<el-form-item :label="t('attachmentUrl')">
<el-input <script lang="ts" setup>
v-model="formData.attachment_url" import { ref, reactive, computed, watch } from 'vue'
clearable import { useDictionary } from '@/app/api/dict'
:placeholder="t('attachmentUrlPlaceholder')" import { t } from '@/lang'
class="input-width" import type { FormInstance } from 'element-plus'
/> import { addUserFeedback, editUserFeedback, getUserFeedbackInfo, getWithCustomerResourcesList } from '@/app/api/user_feedback'
</el-form-item>
</el-form> let showDialog = ref(false)
const loading = ref(false)
<template #footer>
<span class="dialog-footer"> /**
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button> * 表单数据
<el-button */
type="primary" const initialFormData = {
:loading="loading" id: '',
@click="confirm(formRef)" user_id: '',
>{{ t('confirm') }}</el-button feedback_text: '',
> attachment_url: '',
</span> }
</template> const formData: Record<string, any> = reactive({ ...initialFormData })
</el-dialog>
</template> const formRef = ref<FormInstance>()
<script lang="ts" setup> //
import { ref, reactive, computed, watch } from 'vue' const formRules = computed(() => {
import { useDictionary } from '@/app/api/dict' return {
import { t } from '@/lang' user_id: [
import type { FormInstance } from 'element-plus' { required: true, message: t('userIdPlaceholder'), trigger: 'blur' },
import {
addUserFeedback, ]
editUserFeedback, ,
getUserFeedbackInfo, feedback_text: [
} from '@/app/api/user_feedback' { required: true, message: t('feedbackTextPlaceholder'), trigger: 'blur' },
let showDialog = ref(false) ]
const loading = ref(false) ,
attachment_url: [
/** { required: true, message: t('attachmentUrlPlaceholder'), trigger: 'blur' },
* 表单数据
*/ ]
const initialFormData = { ,
id: '', }
user_id: '', })
feedback_text: '',
attachment_url: '', const emit = defineEmits(['complete'])
}
const formData: Record<string, any> = reactive({ ...initialFormData }) /**
* 确认
const formRef = ref<FormInstance>() * @param formEl
*/
// const confirm = async (formEl: FormInstance | undefined) => {
const formRules = computed(() => { if (loading.value || !formEl) return
return { let save = formData.id ? editUserFeedback : addUserFeedback
user_id: [
{ required: true, message: t('userIdPlaceholder'), trigger: 'blur' }, await formEl.validate(async (valid) => {
], if (valid) {
feedback_text: [ loading.value = true
{
required: true, let data = formData
message: t('feedbackTextPlaceholder'),
trigger: 'blur', save(data).then(res => {
}, loading.value = false
], showDialog.value = false
attachment_url: [ emit('complete')
{ }).catch(err => {
required: true, loading.value = false
message: t('attachmentUrlPlaceholder'), })
trigger: 'blur', }
}, })
], }
}
}) //
const emit = defineEmits(['complete'])
/** const userIdList = ref([] as any[])
* 确认 const setUserIdList = async () => {
* @param formEl userIdList.value = await (await getWithCustomerResourcesList({})).data
*/ }
const confirm = async (formEl: FormInstance | undefined) => { setUserIdList()
if (loading.value || !formEl) return const setFormData = async (row: any = null) => {
let save = formData.id ? editUserFeedback : addUserFeedback Object.assign(formData, initialFormData)
loading.value = true
await formEl.validate(async (valid) => { if(row){
if (valid) { const data = await (await getUserFeedbackInfo(row.id)).data
loading.value = true if (data) Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
let data = formData })
}
save(data) loading.value = false
.then((res) => { }
loading.value = false
showDialog.value = false //
emit('complete') const mobileVerify = (rule: any, value: any, callback: any) => {
}) if (value && !/^1[3-9]\d{9}$/.test(value)) {
.catch((err) => { callback(new Error(t('generateMobile')))
loading.value = false } else {
}) callback()
} }
}) }
}
//
// const idCardVerify = (rule: any, value: any, callback: any) => {
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)) {
const setFormData = async (row: any = null) => { callback(new Error(t('generateIdCard')))
Object.assign(formData, initialFormData) } else {
loading.value = true callback()
if (row) { }
const data = await (await getUserFeedbackInfo(row.id)).data }
if (data)
Object.keys(formData).forEach((key: string) => { //
if (data[key] != undefined) formData[key] = data[key] const emailVerify = (rule: any, value: any, callback: any) => {
}) if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
} callback(new Error(t('generateEmail')))
loading.value = false } else {
} callback()
}
// }
const mobileVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) { //
callback(new Error(t('generateMobile'))) const numberVerify = (rule: any, value: any, callback: any) => {
} else { if (!Number.isInteger(value)) {
callback() callback(new Error(t('generateNumber')))
} } else {
} callback()
}
// }
const idCardVerify = (rule: any, value: any, callback: any) => {
if ( defineExpose({
value && showDialog,
!/^[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( setFormData
value })
) </script>
) {
callback(new Error(t('generateIdCard'))) <style lang="scss" scoped></style>
} else { <style lang="scss">
callback() .diy-dialog-wrap .el-form-item__label{
} height: auto !important;
} }
</style>
//
const emailVerify = (rule: any, value: any, callback: any) => {
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateEmail')))
} else {
callback()
}
}
//
const numberVerify = (rule: any, value: any, callback: any) => {
if (!Number.isInteger(value)) {
callback(new Error(t('generateNumber')))
} else {
callback()
}
}
defineExpose({
showDialog,
setFormData,
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label {
height: auto !important;
}
</style>

400
admin/src/app/views/user_feedback/user_feedback.vue

@ -1,223 +1,177 @@
<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('addUserFeedback') }} <el-button type="primary" @click="addEvent">
</el-button> {{ t('addUserFeedback') }}
</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="userFeedbackTable.searchParam" ref="searchFormRef">
>
<el-form <el-form-item :label="t('userId')" prop="user_id">
:inline="true" <el-select class="w-[280px]" v-model="userFeedbackTable.searchParam.user_id" clearable :placeholder="t('userIdPlaceholder')">
:model="userFeedbackTable.searchParam" <el-option
ref="searchFormRef" v-for="(item, index) in userIdList"
> :key="index"
<el-form-item :label="t('userId')" prop="user_id"> :label="item['name']"
<el-input :value="item['id']"
v-model="userFeedbackTable.searchParam.user_id" />
:placeholder="t('userIdPlaceholder')" </el-select>
/> </el-form-item>
</el-form-item>
<el-form-item :label="t('feedbackText')" prop="feedback_text"> <el-form-item>
<el-input <el-button type="primary" @click="loadUserFeedbackList()">{{ t('search') }}</el-button>
v-model="userFeedbackTable.searchParam.feedback_text" <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
:placeholder="t('feedbackTextPlaceholder')" </el-form-item>
/> </el-form>
</el-form-item> </el-card>
<el-form-item :label="t('attachmentUrl')" prop="attachment_url">
<el-input <div class="mt-[10px]">
v-model="userFeedbackTable.searchParam.attachment_url" <el-table :data="userFeedbackTable.data" size="large" v-loading="userFeedbackTable.loading">
:placeholder="t('attachmentUrlPlaceholder')" <template #empty>
/> <span>{{ !userFeedbackTable.loading ? t('emptyData') : '' }}</span>
</el-form-item> </template>
<el-table-column prop="user_id_name" :label="t('userId')" min-width="120" :show-overflow-tooltip="true"/>
<el-form-item>
<el-button type="primary" @click="loadUserFeedbackList()">{{ <el-table-column prop="feedback_text" :label="t('feedbackText')" min-width="120" :show-overflow-tooltip="true"/>
t('search')
}}</el-button> <el-table-column prop="attachment_url" :label="t('attachmentUrl')" min-width="120" :show-overflow-tooltip="true"/>
<el-button @click="resetForm(searchFormRef)">{{
t('reset') <el-table-column :label="t('operation')" fixed="right" min-width="120">
}}</el-button> <template #default="{ row }">
</el-form-item> <el-button type="primary" link @click="editEvent(row)">查看</el-button>
</el-form> <!-- <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button> -->
</el-card> </template>
</el-table-column>
<div class="mt-[10px]">
<el-table </el-table>
:data="userFeedbackTable.data" <div class="mt-[16px] flex justify-end">
size="large" <el-pagination v-model:current-page="userFeedbackTable.page" v-model:page-size="userFeedbackTable.limit"
v-loading="userFeedbackTable.loading" layout="total, sizes, prev, pager, next, jumper" :total="userFeedbackTable.total"
> @size-change="loadUserFeedbackList()" @current-change="loadUserFeedbackList" />
<template #empty> </div>
<span>{{ !userFeedbackTable.loading ? t('emptyData') : '' }}</span> </div>
</template>
<el-table-column <edit ref="editUserFeedbackDialog" @complete="loadUserFeedbackList" />
prop="user_id" </el-card>
:label="t('userId')" </div>
min-width="120" </template>
:show-overflow-tooltip="true"
/> <script lang="ts" setup>
import { reactive, ref, watch } from 'vue'
<el-table-column import { t } from '@/lang'
prop="feedback_text" import { useDictionary } from '@/app/api/dict'
:label="t('feedbackText')" import { getUserFeedbackList, deleteUserFeedback, getWithCustomerResourcesList } from '@/app/api/user_feedback'
min-width="120" import { img } from '@/utils/common'
:show-overflow-tooltip="true" import { ElMessageBox,FormInstance } from 'element-plus'
/> import Edit from '@/app/views/user_feedback/components/user-feedback-edit.vue'
import { useRoute } from 'vue-router'
<el-table-column const route = useRoute()
prop="attachment_url" const pageName = route.meta.title;
:label="t('attachmentUrl')"
min-width="120" let userFeedbackTable = reactive({
:show-overflow-tooltip="true" page: 1,
/> limit: 10,
total: 0,
<el-table-column loading: true,
:label="t('operation')" data: [],
fixed="right" searchParam:{
min-width="120" "user_id":""
> }
<template #default="{ row }"> })
<el-button type="primary" link @click="editEvent(row)">{{
t('edit') const searchFormRef = ref<FormInstance>()
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ //
t('delete') const selectData = ref<any[]>([])
}}</el-button>
</template> //
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end"> /**
<el-pagination * 获取用户反馈信息列表
v-model:current-page="userFeedbackTable.page" */
v-model:page-size="userFeedbackTable.limit" const loadUserFeedbackList = (page: number = 1) => {
layout="total, sizes, prev, pager, next, jumper" userFeedbackTable.loading = true
:total="userFeedbackTable.total" userFeedbackTable.page = page
@size-change="loadUserFeedbackList()"
@current-change="loadUserFeedbackList" getUserFeedbackList({
/> page: userFeedbackTable.page,
</div> limit: userFeedbackTable.limit,
</div> ...userFeedbackTable.searchParam
}).then(res => {
<edit ref="editUserFeedbackDialog" @complete="loadUserFeedbackList" /> userFeedbackTable.loading = false
</el-card> userFeedbackTable.data = res.data.data
</div> userFeedbackTable.total = res.data.total
</template> }).catch(() => {
userFeedbackTable.loading = false
<script lang="ts" setup> })
import { reactive, ref, watch } from 'vue' }
import { t } from '@/lang' loadUserFeedbackList()
import { useDictionary } from '@/app/api/dict'
import { const editUserFeedbackDialog: Record<string, any> | null = ref(null)
getUserFeedbackList,
deleteUserFeedback, /**
} from '@/app/api/user_feedback' * 添加用户反馈信息
import { img } from '@/utils/common' */
import { ElMessageBox, FormInstance } from 'element-plus' const addEvent = () => {
import Edit from '@/app/views/user_feedback/components/user-feedback-edit.vue' editUserFeedbackDialog.value.setFormData()
import { useRoute } from 'vue-router' editUserFeedbackDialog.value.showDialog = true
const route = useRoute() }
const pageName = route.meta.title
/**
let userFeedbackTable = reactive({ * 编辑用户反馈信息
page: 1, * @param data
limit: 10, */
total: 0, const editEvent = (data: any) => {
loading: true, editUserFeedbackDialog.value.setFormData(data)
data: [], editUserFeedbackDialog.value.showDialog = true
searchParam: { }
user_id: '',
feedback_text: '', /**
attachment_url: '', * 删除用户反馈信息
}, */
}) const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('userFeedbackDeleteTips'), t('warning'),
const searchFormRef = ref<FormInstance>() {
confirmButtonText: t('confirm'),
// cancelButtonText: t('cancel'),
const selectData = ref<any[]>([]) type: 'warning',
}
// ).then(() => {
deleteUserFeedback(id).then(() => {
/** loadUserFeedbackList()
* 获取用户反馈信息列表 }).catch(() => {
*/ })
const loadUserFeedbackList = (page: number = 1) => { })
userFeedbackTable.loading = true }
userFeedbackTable.page = page
getUserFeedbackList({ const userIdList = ref([])
page: userFeedbackTable.page, const setUserIdList = async () => {
limit: userFeedbackTable.limit, userIdList.value = await (await getWithCustomerResourcesList({})).data
...userFeedbackTable.searchParam, }
}) setUserIdList()
.then((res) => {
userFeedbackTable.loading = false const resetForm = (formEl: FormInstance | undefined) => {
userFeedbackTable.data = res.data.data if (!formEl) return
userFeedbackTable.total = res.data.total formEl.resetFields()
}) loadUserFeedbackList()
.catch(() => { }
userFeedbackTable.loading = false </script>
})
} <style lang="scss" scoped>
loadUserFeedbackList() /* 多行超出隐藏 */
.multi-hidden {
const editUserFeedbackDialog: Record<string, any> | null = ref(null) word-break: break-all;
text-overflow: ellipsis;
/** overflow: hidden;
* 添加用户反馈信息 display: -webkit-box;
*/ -webkit-line-clamp: 2;
const addEvent = () => { -webkit-box-orient: vertical;
editUserFeedbackDialog.value.setFormData() }
editUserFeedbackDialog.value.showDialog = true </style>
}
/**
* 编辑用户反馈信息
* @param data
*/
const editEvent = (data: any) => {
editUserFeedbackDialog.value.setFormData(data)
editUserFeedbackDialog.value.showDialog = true
}
/**
* 删除用户反馈信息
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('userFeedbackDeleteTips'), t('warning'), {
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteUserFeedback(id)
.then(() => {
loadUserFeedbackList()
})
.catch(() => {})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadUserFeedbackList()
}
</script>
<style lang="scss" scoped>
/* 多行超出隐藏 */
.multi-hidden {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>

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

@ -32,6 +32,7 @@ class CustomerResources extends BaseAdminController
["age",""], ["age",""],
["gender",""], ["gender",""],
["phone_number",""], ["phone_number",""],
['member_label', 0],
["type","khzy"], ["type","khzy"],
["created_at",[]], ["created_at",[]],
["updated_at",[]], ["updated_at",[]],
@ -69,6 +70,8 @@ class CustomerResources extends BaseAdminController
["initial_intent",""], ["initial_intent",""],
["campus",""], ["campus",""],
["status",""], ["status",""],
['member_label', []],
["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",""], ["purchase_power",""],
@ -110,6 +113,7 @@ class CustomerResources extends BaseAdminController
["initial_intent",""], ["initial_intent",""],
["campus",""], ["campus",""],
["status",""], ["status",""],
['member_label', []],
["create_year_month",date("Y-m")], ["create_year_month",date("Y-m")],
["create_date",date("Y-m-d")], ["create_date",date("Y-m-d")],

8
niucloud/app/adminapi/controller/departments/Departments.php

@ -54,8 +54,7 @@ class Departments extends BaseAdminController
]); ]);
$this->validate($data, 'app\validate\departments\Departments.add'); $this->validate($data, 'app\validate\departments\Departments.add');
$id = (new DepartmentsService())->add($data); return (new DepartmentsService())->add($data);
return success('ADD_SUCCESS', ['id' => $id]);
} }
/** /**
@ -70,8 +69,7 @@ class Departments extends BaseAdminController
]); ]);
$this->validate($data, 'app\validate\departments\Departments.edit'); $this->validate($data, 'app\validate\departments\Departments.edit');
(new DepartmentsService())->edit($id, $data); return (new DepartmentsService())->edit($id, $data);
return success('EDIT_SUCCESS');
} }
/** /**
@ -84,7 +82,7 @@ class Departments extends BaseAdminController
return success('DELETE_SUCCESS'); return success('DELETE_SUCCESS');
} }
public function getDepartmentsAll(){ public function getDepartmentsAll(){
return success(( new DepartmentsService())->getDepartmentsAll()); return success(( new DepartmentsService())->getDepartmentsAll());
} }

9
niucloud/app/adminapi/controller/order_table/OrderTable.php

@ -50,7 +50,7 @@ class OrderTable extends BaseAdminController
public function add(){ public function add(){
$data = $this->request->params([ $data = $this->request->params([
["resource_id",0], ["resource_id",0],
["order_status",""], // ["order_status",""],
["payment_type",""], ["payment_type",""],
["order_amount",0.00], ["order_amount",0.00],
["course_id",0], ["course_id",0],
@ -58,8 +58,7 @@ class OrderTable extends BaseAdminController
]); ]);
$this->validate($data, 'app\validate\order_table\OrderTable.add'); $this->validate($data, 'app\validate\order_table\OrderTable.add');
$id = (new OrderTableService())->add($data); return (new OrderTableService())->add($data);
return success('ADD_SUCCESS', ['id' => $id]);
} }
/** /**
@ -70,7 +69,7 @@ class OrderTable extends BaseAdminController
public function edit(int $id){ public function edit(int $id){
$data = $this->request->params([ $data = $this->request->params([
["resource_id",0], ["resource_id",0],
["order_status",""], // ["order_status",""],
["payment_type",""], ["payment_type",""],
["order_amount",0.00], ["order_amount",0.00],
["course_id",0], ["course_id",0],
@ -92,7 +91,7 @@ class OrderTable extends BaseAdminController
return success('DELETE_SUCCESS'); return success('DELETE_SUCCESS');
} }
public function getCustomerResourcesAll(){ public function getCustomerResourcesAll(){
return success(( new OrderTableService())->getCustomerResourcesAll()); return success(( new OrderTableService())->getCustomerResourcesAll());
} }

7
niucloud/app/adminapi/controller/service/Service.php

@ -29,14 +29,7 @@ class Service extends BaseAdminController
public function lists(){ public function lists(){
$data = $this->request->params([ $data = $this->request->params([
["service_name",""], ["service_name",""],
["preview_image_url",""],
["description",""],
["service_type",""], ["service_type",""],
["execution_rules",""],
["staff_reminder",""],
["customer_reminder",""],
["customer_confirmation",""],
["customer_feedback",""],
["status",""] ["status",""]
]); ]);
return success((new ServiceService())->getPage($data)); return success((new ServiceService())->getPage($data));

8
niucloud/app/adminapi/controller/user_feedback/UserFeedback.php

@ -28,9 +28,7 @@ class UserFeedback extends BaseAdminController
*/ */
public function lists(){ public function lists(){
$data = $this->request->params([ $data = $this->request->params([
["user_id",""], ["user_id",""]
["feedback_text",""],
["attachment_url",""]
]); ]);
return success((new UserFeedbackService())->getPage($data)); return success((new UserFeedbackService())->getPage($data));
} }
@ -88,4 +86,8 @@ class UserFeedback extends BaseAdminController
} }
public function getCustomerResourcesAll(){
return success(( new UserFeedbackService())->getCustomerResourcesAll());
}
} }

1
niucloud/app/adminapi/route/service.php

@ -15,6 +15,7 @@ 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 -- service // USER_CODE_BEGIN -- service
Route::group('service', function () { Route::group('service', function () {

3
niucloud/app/adminapi/route/user_feedback.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 -- user_feedback // USER_CODE_BEGIN -- user_feedback
Route::group('user_feedback', function () { Route::group('user_feedback', function () {
@ -29,6 +30,8 @@ Route::group('user_feedback', function () {
//删除用户反馈信息 //删除用户反馈信息
Route::delete('user_feedback/:id', 'user_feedback.UserFeedback/del'); Route::delete('user_feedback/:id', 'user_feedback.UserFeedback/del');
Route::get('customer_resources_all','user_feedback.UserFeedback/getCustomerResourcesAll');
})->middleware([ })->middleware([
AdminCheckToken::class, AdminCheckToken::class,
AdminCheckRole::class, AdminCheckRole::class,

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

@ -15,6 +15,7 @@ use app\model\dict\Dict;
use app\model\resource_sharing\ResourceSharing; use app\model\resource_sharing\ResourceSharing;
use app\model\six_speed\SixSpeed; use app\model\six_speed\SixSpeed;
use core\base\BaseModel; use core\base\BaseModel;
use think\db\Query;
use think\model\concern\SoftDelete; 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;
@ -57,6 +58,10 @@ class CustomerResources extends BaseModel
*/ */
protected $defaultSoftDelete = 0; protected $defaultSoftDelete = 0;
protected $json = [ 'member_label' ];
protected $jsonAssoc = true;
//定义一个常量数组-字段中文映射 //定义一个常量数组-字段中文映射
const FieldZh = [ const FieldZh = [
'id' => '编号', 'id' => '编号',
@ -96,6 +101,14 @@ class CustomerResources extends BaseModel
} }
} }
public function searchMemberLabelAttr(Query $query, $value, $data)
{
if ($value) {
$query->whereLike('member_label', '%"' . $value . '"%');
}
}
/** /**
* 搜索器:客户资源联系电话 * 搜索器:客户资源联系电话
* @param $value * @param $value

96
niucloud/app/model/service/Service.php

@ -50,18 +50,6 @@ class Service 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 $value
@ -74,30 +62,6 @@ class Service extends BaseModel
} }
} }
/**
* 搜索器:服务服务预览图URL
* @param $value
* @param $data
*/
public function searchPreviewImageUrlAttr($query, $value, $data)
{
if ($value) {
$query->where("preview_image_url", $value);
}
}
/**
* 搜索器:服务服务描述
* @param $value
* @param $data
*/
public function searchDescriptionAttr($query, $value, $data)
{
if ($value) {
$query->where("description", $value);
}
}
/** /**
* 搜索器:服务服务类型 * 搜索器:服务服务类型
* @param $value * @param $value
@ -110,66 +74,6 @@ class Service extends BaseModel
} }
} }
/**
* 搜索器:服务服务执行规则
* @param $value
* @param $data
*/
public function searchExecutionRulesAttr($query, $value, $data)
{
if ($value) {
$query->where("execution_rules", $value);
}
}
/**
* 搜索器:服务是否员工提醒: 1-是, 0-否
* @param $value
* @param $data
*/
public function searchStaffReminderAttr($query, $value, $data)
{
if ($value) {
$query->where("staff_reminder", $value);
}
}
/**
* 搜索器:服务是否客户提醒: 1-是, 0-否
* @param $value
* @param $data
*/
public function searchCustomerReminderAttr($query, $value, $data)
{
if ($value) {
$query->where("customer_reminder", $value);
}
}
/**
* 搜索器:服务是否客户确认: 1-是, 0-否
* @param $value
* @param $data
*/
public function searchCustomerConfirmationAttr($query, $value, $data)
{
if ($value) {
$query->where("customer_confirmation", $value);
}
}
/**
* 搜索器:服务客户反馈内容
* @param $value
* @param $data
*/
public function searchCustomerFeedbackAttr($query, $value, $data)
{
if ($value) {
$query->where("customer_feedback", $value);
}
}
/** /**
* 搜索器:服务状态 * 搜索器:服务状态
* @param $value * @param $value

44
niucloud/app/model/user_feedback/UserFeedback.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\customer_resources\CustomerResources;
/** /**
* 用户反馈信息模型 * 用户反馈信息模型
* Class UserFeedback * Class UserFeedback
@ -43,19 +45,7 @@ class UserFeedback extends BaseModel
/** /**
* 搜索器:用户反馈信息反馈编号 * 搜索器:用户反馈信息客户名称
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:用户反馈信息用户ID
* @param $value * @param $value
* @param $data * @param $data
*/ */
@ -66,33 +56,13 @@ class UserFeedback extends BaseModel
} }
} }
/**
* 搜索器:用户反馈信息反馈内容
* @param $value
* @param $data
*/
public function searchFeedbackTextAttr($query, $value, $data)
{
if ($value) {
$query->where("feedback_text", $value);
}
}
/**
* 搜索器:用户反馈信息附件URL(OSS对象存储)
* @param $value
* @param $data
*/
public function searchAttachmentUrlAttr($query, $value, $data)
{
if ($value) {
$query->where("attachment_url", $value);
}
}
public function customerResources(){
return $this->hasOne(CustomerResources::class, 'id', 'user_id')->joinType('left')->withField('name,id')->bind(['user_id_name'=>'name']);
}
} }

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

@ -19,6 +19,7 @@ use app\model\campus\Campus;
use app\model\resource_sharing\ResourceSharing; use app\model\resource_sharing\ResourceSharing;
use app\model\six_speed\SixSpeed; use app\model\six_speed\SixSpeed;
use app\model\six_speed_modification_log\SixSpeedModificationLog; use app\model\six_speed_modification_log\SixSpeedModificationLog;
use app\service\admin\member\MemberLabelService;
use core\base\BaseAdminService; use core\base\BaseAdminService;
@ -66,9 +67,9 @@ class CustomerResourcesService extends BaseAdminService
$where[] = ['b.shared_by','=',0]; $where[] = ['b.shared_by','=',0];
} }
if($data['member_label']){
$where[] = ['a.member_label','like',"%".$data['member_label']."%"];
}
$search_model = $this->model $search_model = $this->model
@ -87,11 +88,9 @@ class CustomerResourcesService extends BaseAdminService
} }
$list = $this->pageQuery($search_model); return $this->pageQuery($search_model, function ($item, $key) {
$item = $this->makeUp($item);
});
return $list;
} }
/** /**
@ -101,7 +100,7 @@ class CustomerResourcesService extends BaseAdminService
*/ */
public function getInfo(int $id) public function getInfo(int $id)
{ {
$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,member_label,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]])->with(['personnel'])->findOrEmpty()->toArray(); $info = $this->model->field($field)->where([['id', "=", $id]])->with(['personnel'])->findOrEmpty()->toArray();
@ -109,7 +108,16 @@ class CustomerResourcesService extends BaseAdminService
$data = $sixSpeed->where(['resource_id' => $id])->field("*,distance as distance_tow")->findOrEmpty()->toArray(); $data = $sixSpeed->where(['resource_id' => $id])->field("*,distance as distance_tow")->findOrEmpty()->toArray();
$info = $info+$data; $info = $info+$data;
return $info; return $this->makeUp($info);
}
public function makeUp($data){
//会员标签
if(!empty($data['member_label'])){
$data['member_label_array'] = (new MemberLabelService())->getMemberLabelListByLabelIds($data['member_label']);
}
return $data;
} }
/** /**
@ -128,6 +136,8 @@ class CustomerResourcesService extends BaseAdminService
} }
$sixSpeed = new SixSpeed(); $sixSpeed = new SixSpeed();
// $data['member_label'] = json_encode($data['member_label']);
$res = $this->model->create($data); $res = $this->model->create($data);
@ -188,7 +198,7 @@ class CustomerResourcesService extends BaseAdminService
$this->model->where([['id', '=', $id]])->update([ $this->model->where([['id', '=', $id]])->update([
'source' => $data['source'], 'source' => $data['source'],
'source_channel' => $data['source_channel'], 'source_channel' => $data['source_channel'],
// 'consultant' => $data['consultant'], 'member_label' => $data['member_label'],
'name' => $data['name'], 'name' => $data['name'],
'age' => $data['age'], 'age' => $data['age'],
'gender' => $data['gender'], 'gender' => $data['gender'],

13
niucloud/app/service/admin/departments/DepartmentsService.php

@ -65,8 +65,12 @@ class DepartmentsService extends BaseAdminService
*/ */
public function add(array $data) public function add(array $data)
{ {
if($this->model->where(['department_name' => $data['department_name']])->find()){
return fail("部门名称不能重复");
}
$res = $this->model->create($data); $res = $this->model->create($data);
return $res->id; return success("操作成功");
} }
@ -74,13 +78,14 @@ class DepartmentsService 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)
{ {
if($this->model->where([['id', '<>', $id]])->where(['department_name' => $data['department_name']])->find()){
return fail("部门名称不能重复");
}
$this->model->where([['id', '=', $id]])->update($data); $this->model->where([['id', '=', $id]])->update($data);
return true; return success("操作成功");
} }
/** /**

12
niucloud/app/service/admin/order_table/OrderTableService.php

@ -69,15 +69,15 @@ class OrderTableService extends BaseAdminService
public function add(array $data) public function add(array $data)
{ {
$personnel = new Personnel(); $personnel = new Personnel();
$data['staff_id'] = $personnel->where(['sys_user_id' => $this->uid])->value("id"); // $data['staff_id'] = $personnel->where(['sys_user_id' => $this->uid])->value("id");
if(!$data['staff_id']){ // if(!$data['staff_id']){
return fail("操作失败"); // return fail("操作失败");
} // }
// $data['staff_id'] = 1; $data['staff_id'] = 1;
$res = $this->model->create($data); $res = $this->model->create($data);
return $res->id; return success("操作成功");
} }

2
niucloud/app/service/admin/service/ServiceService.php

@ -39,7 +39,7 @@ class ServiceService extends BaseAdminService
$field = 'id,service_name,preview_image_url,description,service_type,execution_rules,staff_reminder,customer_reminder,customer_confirmation,customer_feedback,status,created_at,updated_at,deleted_at'; $field = 'id,service_name,preview_image_url,description,service_type,execution_rules,staff_reminder,customer_reminder,customer_confirmation,customer_feedback,status,created_at,updated_at,deleted_at';
$order = 'id desc'; $order = 'id desc';
$search_model = $this->model->withSearch(["id","service_name","preview_image_url","description","service_type","execution_rules","staff_reminder","customer_reminder","customer_confirmation","customer_feedback","status"], $where)->field($field)->order($order); $search_model = $this->model->withSearch(["service_name","service_type","status"], $where)->field($field)->order($order);
$list = $this->pageQuery($search_model); $list = $this->pageQuery($search_model);
return $list; return $list;
} }

10
niucloud/app/service/admin/user_feedback/UserFeedbackService.php

@ -12,6 +12,7 @@
namespace app\service\admin\user_feedback; namespace app\service\admin\user_feedback;
use app\model\user_feedback\UserFeedback; use app\model\user_feedback\UserFeedback;
use app\model\customer_resources\CustomerResources;
use core\base\BaseAdminService; use core\base\BaseAdminService;
@ -39,7 +40,7 @@ class UserFeedbackService extends BaseAdminService
$field = 'id,user_id,feedback_text,attachment_url,created_at,updated_at'; $field = 'id,user_id,feedback_text,attachment_url,created_at,updated_at';
$order = 'id desc'; $order = 'id desc';
$search_model = $this->model->withSearch(["id","user_id","feedback_text","attachment_url"], $where)->field($field)->order($order); $search_model = $this->model->withSearch(["user_id"], $where)->with(['customerResources'])->field($field)->order($order);
$list = $this->pageQuery($search_model); $list = $this->pageQuery($search_model);
return $list; return $list;
} }
@ -53,7 +54,7 @@ class UserFeedbackService extends BaseAdminService
{ {
$field = 'id,user_id,feedback_text,attachment_url,created_at,updated_at'; $field = 'id,user_id,feedback_text,attachment_url,created_at,updated_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray(); $info = $this->model->field($field)->where([['id', "=", $id]])->with(['customerResources'])->findOrEmpty()->toArray();
return $info; return $info;
} }
@ -95,5 +96,10 @@ class UserFeedbackService extends BaseAdminService
} }
public function getCustomerResourcesAll(){
$customerResourcesModel = new CustomerResources();
return $customerResourcesModel->select()->toArray();
}
} }

4
niucloud/app/validate/order_table/OrderTable.php

@ -38,8 +38,8 @@ class OrderTable extends BaseValidate
]; ];
protected $scene = [ protected $scene = [
"add" => ['resource_id', 'order_status', 'payment_type', 'order_amount', 'course_id', 'class_id'], "add" => ['resource_id', 'payment_type', 'order_amount', 'course_id', 'class_id'],
"edit" => ['resource_id', 'order_status', 'payment_type', 'order_amount', 'course_id', 'class_id'] "edit" => ['resource_id', 'payment_type', 'order_amount', 'course_id', 'class_id']
]; ];
} }

6
niucloud/app/validate/user_feedback/UserFeedback.php

@ -20,13 +20,11 @@ class UserFeedback extends BaseValidate
{ {
protected $rule = [ protected $rule = [
'user_id' => 'require',
'feedback_text' => 'require',
]; ];
protected $message = [ protected $message = [
'user_id.require' => ['common_validate.require', ['user_id']],
'feedback_text.require' => ['common_validate.require', ['feedback_text']],
]; ];
protected $scene = [ protected $scene = [

Loading…
Cancel
Save