Selaa lähdekoodia

Merge remote-tracking branch 'origin/master'

yfh 1 viikko sitten
vanhempi
commit
0068d2b754

+ 40 - 0
.env.prod-hyt

@@ -0,0 +1,40 @@
+# 页面标题
+VUE_APP_TITLE =宏医堂互联网医院管理系统
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =宏医堂互联网医院
+# 公司名称
+VUE_APP_COMPANY_NAME =易行健和泰(湖北)健康咨询有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD =鄂ICP备2025116549号-1
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/myhk.png
+# 存储桶配置
+VUE_APP_OBS_ACCESS_KEY_ID = K2UTJGIN7UTZJR2XMXYG
+# 存储桶配置
+VUE_APP_OBS_SECRET_ACCESS_KEY = sbyeNJLbcYmH6copxeFP9pAoksM4NIT9Zw4x0SRX
+# 存储桶配置
+VUE_APP_OBS_SERVER = https://obs.cn-north-4.myhuaweicloud.com
+# 存储桶配置
+VUE_APP_OBS_BUCKET = hyt-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = fzhyt-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://fzhyttcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://hytobs.ylrztop.com
+
+# 开发环境配置
+ENV = 'production'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 1
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 1 - 0
package.json

@@ -35,6 +35,7 @@
     "build:prod-fby": "vue-cli-service build --mode prod-fby",
     "build:prod-zkzh": "vue-cli-service build --mode prod-zkzh",
     "build:prod-syysy": "vue-cli-service build --mode prod-syysy",
+    "build:prod-hyt": "vue-cli-service build --mode prod-hyt",
     "preview": "node build/index.js --preview",
     "lint": "eslint --ext .js,.vue src"
   },

+ 75 - 0
src/api/complaint/complaint.js

@@ -0,0 +1,75 @@
+import request from '@/utils/request'
+
+// 提交投诉
+export function submitComplaint(data) {
+  return request({
+    url: '/complaint',
+    method: 'post',
+    data: data
+  })
+}
+
+// 根据ID查询投诉详情
+export function getComplaintById(id) {
+  return request({
+    url: `/complaint/${id}`,
+    method: 'get'
+  })
+}
+
+// 根据投诉单号查询投诉详情
+export function getComplaintByNo(complaintNo) {
+  return request({
+    url: `/complaint/no/${complaintNo}`,
+    method: 'get'
+  })
+}
+
+// 分页查询投诉列表
+export function getComplaintPage(data) {
+  return request({
+    url: '/complaint/list',
+    method: 'post',
+    data: data
+  })
+}
+
+// 更新投诉信息
+export function updateComplaint(id, data) {
+  return request({
+    url: `/complaint/${id}`,
+    method: 'put',
+    data: {
+      ...data,
+      type: data.categoryId
+    }
+  })
+}
+
+// 删除投诉
+export function deleteComplaint(id) {
+  return request({
+    url: `/complaint/${id}`,
+    method: 'delete'
+  })
+}
+
+// 处理投诉(快捷更新状态为已处理)
+export function handleComplaint(id) {
+  return request({
+    url: `/complaint/${id}`,
+    method: 'put',
+    data: {
+      status: '1' // 假设1表示已处理状态
+    }
+  })
+}
+// 新增:获取所有投诉分类
+export function getAllCategory() {
+  return request({
+    url: '/complaint/queryAllCategory',
+    method: 'post'
+  })
+}
+
+

+ 39 - 0
src/api/course/coursePlaySourceConfig.js

@@ -0,0 +1,39 @@
+import request from '@/utils/request'
+
+export function list(query) {
+  return request({
+    url: '/course/playSourceConfig/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function get(id) {
+  return request({
+    url: '/course/playSourceConfig/' + id,
+    method: 'get'
+  })
+}
+
+export function add(data) {
+  return request({
+    url: '/course/playSourceConfig',
+    method: 'post',
+    data: data
+  })
+}
+
+export function update(data) {
+  return request({
+    url: '/course/playSourceConfig',
+    method: 'put',
+    data: data
+  })
+}
+
+export function del(id) {
+  return request({
+    url: '/course/playSourceConfig/' + id,
+    method: 'delete'
+  })
+}

+ 44 - 0
src/api/food/record.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询饮食记录列表
+export function listFoodRecord(query) {
+  return request({
+    url: '/food-record/admin/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询饮食记录详细
+export function getFoodRecord(id) {
+  return request({
+    url: '/food-record/getRecordInfo/' + id,
+    method: 'get'
+  })
+}
+
+// 新增饮食记录
+export function addFoodRecord(data) {
+  return request({
+    url: '/food-record/addRecord',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改饮食记录
+export function updateFoodRecord(data) {
+  return request({
+    url: '/food-record/editRecord',
+    method: 'post',
+    data: data
+  })
+}
+
+// 删除饮食记录
+export function delFoodRecord(id) {
+  return request({
+    url: '/food-record/deleteRecord/' + id,
+    method: 'post'
+  })
+}

+ 27 - 0
src/api/his/inquiryPatient.js

@@ -0,0 +1,27 @@
+import request from '@/utils/request'
+
+// 新增患者问诊信息
+export function addinquiryPatient(data) {
+  return request({
+    url: '/his/inquiryPatientInfo',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改患者问诊信息
+export function updateinquiryPatient(data) {
+  return request({
+    url: '/his/inquiryPatientInfo',
+    method: 'put',
+    data: data
+  })
+}
+
+//获取患者问诊信息详情
+export function detail(inquiryOrderId) {
+  return request({
+    url: '/his/inquiryPatientInfo/detail/'+ inquiryOrderId,
+    method: 'get'
+  })
+}

+ 49 - 0
src/api/saler/competitorInfo.js

@@ -0,0 +1,49 @@
+import request from '@/utils/request'
+
+// 竞品信息模块请求前缀
+const prefix = '/saler/competitorInfo'
+
+// 查询竞品信息列表
+export function listCompetitorInfo(query) {
+  return request({
+    url: prefix + '/listPage',
+    method: 'post',
+    data: query
+  })
+}
+
+// 查询竞品信息详细
+export function getCompetitorInfo(id) {
+  return request({
+    url: prefix + '/findById',
+    method: 'post',
+    data: { id }
+  })
+}
+
+// 新增竞品信息
+export function addCompetitorInfo(data) {
+  return request({
+    url: prefix + '/save',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改竞品信息
+export function updateCompetitorInfo(data) {
+  return request({
+    url: prefix + '/updateById',
+    method: 'post',
+    data: data
+  })
+}
+
+// 删除竞品信息
+export function delCompetitorInfo(id) {
+  return request({
+    url: prefix + '/deleteById',
+    method: 'post',
+    data: { id }
+  })
+}

+ 46 - 0
src/api/saler/productInfo.js

@@ -0,0 +1,46 @@
+import request from '@/utils/request'
+
+// 查询商品列表
+export function listProductInfo(query) {
+  return request({
+    url: '/saler/serviceGoods/listPage',
+    method: 'post',
+    data: query
+  })
+}
+
+// 查询商品详细
+export function getProductInfo(id) {
+  return request({
+    url: '/saler/serviceGoods/findById',
+    method: 'post',
+    data: { id }
+  })
+}
+
+// 新增商品
+export function addProductInfo(data) {
+  return request({
+    url: '/saler/serviceGoods/save',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改商品
+export function updateProductInfo(data) {
+  return request({
+    url: '/saler/serviceGoods/updateById',
+    method: 'post',
+    data: data
+  })
+}
+
+// 删除商品
+export function delProductInfo(id) {
+  return request({
+    url: '/saler/serviceGoods/deleteById',
+    method: 'post',
+    data: { id }
+  })
+}

+ 81 - 0
src/api/todo/todoItems.js

@@ -0,0 +1,81 @@
+import request from '@/utils/request'
+
+// 查询待办事项列表
+export function listTodoItems(query) {
+  return request({
+    url: '/todoItems/listPage',
+    method: 'post',
+    data: query
+  })
+}
+
+// 查询待办事项详细
+export function getTodoItems(id) {
+  return request({
+    url: '/todoItems/findById',
+    method: 'post',
+    data: { id: id }
+  })
+}
+
+// 新增待办事项
+export function addTodoItems(data) {
+  return request({
+    url: '/todoItems/add',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改待办事项
+export function updateTodoItems(data) {
+  return request({
+    url: '/todoItems/updateById',
+    method: 'post',
+    data: data
+  })
+}
+
+// 更新待办事项状态
+export function updateTodoItemsStatus(id, status) {
+  return request({
+    url: '/todoItems/updateStatusById',
+    method: 'post',
+    data: { id: id, status: status }
+  })
+}
+
+// 删除待办事项
+export function delTodoItems(id) {
+  return request({
+    url: '/todoItems/removeById',
+    method: 'post',
+    data: { id: id }
+  })
+}
+
+// 分配执行者
+export function assignExecutor(data) {
+  return request({
+    url: '/todoItems/assignExecutor',
+    method: 'post',
+    data: data
+  })
+}
+
+// 获取可分配的执行者列表
+export function getExecutorList() {
+  return request({
+    url: '/todoItems/getExecutorList',
+    method: 'get'
+  })
+}
+
+// 获取执行人员列表(支持分页和公司名称搜索)
+export function getUserList(param) {
+  return request({
+    url: '/todoItems/getUserList',
+    method: 'post',
+    data: param
+  })
+}

+ 4 - 0
src/store/modules/user.js

@@ -29,6 +29,9 @@ const user = {
     },
     SET_PERMISSIONS: (state, permissions) => {
       state.permissions = permissions
+    },
+    SET_ISADMIN: (state, isAdmin) => {
+      state.isAdmin = isAdmin
     }
   },
 
@@ -65,6 +68,7 @@ const user = {
           commit('SET_NAME', user.userName)
           commit('SET_AVATAR', avatar)
           commit('SET_USER', user)
+          commit('SET_ISADMIN', res.isAdmin)
           resolve(res)
         }).catch(error => {
           reject(error)

+ 17 - 2
src/views/company/company/index.vue

@@ -509,9 +509,15 @@ export default {
         this.form = response.data;
         this.form.status = response.data.status.toString();
         this.form.companyType = response.data.companyType.toString();
-        if(this.form.followDoctorIds!=null){
-           this.form.followDoctorIds= JSON.parse(this.form.followDoctorIds)
+
+        if (this.form.followDoctorIds==null || this.form.followDoctorIds.length==0){
+          this.form.followDoctorIds=null;
+        }
+
+        if(this.form.followDoctorIds!=null && this.form.followDoctorIds.length>0){
+          this.form.followDoctorIds= JSON.stringify(this.form.followDoctorIds)
         }
+
         if(this.form.packageIds!=null){
           var packageList=this.form.packageIds.split(",");
           packageList.forEach(element => {
@@ -527,6 +533,15 @@ export default {
     submitForm() {
       this.$refs["form"].validate(valid => {
         if (valid) {
+
+          if (this.form.followDoctorIds==null || this.form.followDoctorIds.length==0){
+            this.form.followDoctorIds=null;
+          }
+
+          if(this.form.followDoctorIds!=null && this.form.followDoctorIds.length>0){
+            this.form.followDoctorIds= JSON.stringify(this.form.followDoctorIds)
+          }
+
           if (this.form.companyId != null) {
             updateCompany(this.form).then(response => {
               if (response.code === 200) {

+ 261 - 0
src/views/components/his/inquiryOrderDetails.vue

@@ -31,6 +31,9 @@
               <div class="operate-button-container" >
                  <el-button size="mini" @click="handledetails()" v-hasPermi="['his:inquiryOrderReport:query']">咨询报告</el-button>
               </div>
+              <div class="operate-button-container" >
+                 <el-button size="mini" @click="handlePatient()" v-hasPermi="['his:inquiryOrderReport:query']">患者诊断数据</el-button>
+              </div>
 
 
              </div>
@@ -93,6 +96,197 @@
              <el-button type="primary" @click="editStatusOpenOk">确 定</el-button>
            </span>
          </el-dialog>
+
+        <el-dialog
+        title="患者问诊数据"
+        :visible.sync="patientOpen"
+        width="1000px"
+        append-to-body>
+          <el-form ref="patientForm" :model="patientForm" label-width="110px" >
+
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="患者姓名" prop="patientName">
+                  <el-input disabled v-model="item.patientName"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="患者性别" prop="sex">
+                  <el-select disabled v-model="JSON.parse(item.patientJson).sex">
+                    <el-option label="男" :value = "1"></el-option>
+                    <el-option label="女" :value = "0"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="患者年龄" prop="age">
+                  <el-input disabled v-model="JSON.parse(item.patientJson).age"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="患者电话" prop="mobile">
+                  <el-input disabled v-model="JSON.parse(item.patientJson).mobile"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="患者会员电话" prop="userPhone">
+                  <el-input disabled v-model="patientForm.userPhone"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="客户标签" prop="tag">
+                  <el-input  v-model="patientForm.tag"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="客服姓名" prop="companyUserName">
+                  <el-input disabled v-model="patientForm.companyUserName"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="课程档期" prop="courseName">
+                  <el-input  v-model="patientForm.courseName"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="预约医生" prop="doctorName">
+                  <el-input disabled v-model="item.doctorName"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="会诊时间" prop="subTime">
+                  <el-date-picker
+                  v-model="patientForm.subTime"
+                  type="date"
+                  value-format="yyyy-MM-dd"
+                  placeholder="选择日期">
+                  </el-date-picker>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="就诊状态" prop="sex">
+                  <el-select  v-model="patientForm.diagnosisStatus">
+                    <el-option label="初诊" :value = "1"></el-option>
+                    <el-option label="复诊" :value = "2"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="部门负责人" prop="deptManager">
+                  <el-input v-model="patientForm.deptManager"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-form-item label="患者病情主诉">
+              <el-input
+              type="textarea"
+              placeholder="请输入内容"
+              v-model="patientForm.patientCondition">
+              </el-input>
+            </el-form-item>
+
+            <div class="contentx">
+              <div class="desct">
+                医生建议及处置
+              </div>
+            </div>
+            <el-form-item label="诊断">
+              <el-input
+              type="textarea"
+              placeholder="请输入内容"
+              v-model="patientForm.doctorAdviceJson.diagnosis">
+              </el-input>
+            </el-form-item>
+            <el-form-item label="饮食方面">
+              <el-input
+              type="textarea"
+              placeholder="请输入内容"
+              v-model="patientForm.doctorAdviceJson.foodAdvice">
+              </el-input>
+            </el-form-item>
+            <el-form-item label="运动方面">
+              <el-input
+              type="textarea"
+              placeholder="请输入内容"
+              v-model="patientForm.doctorAdviceJson.sportAdvice">
+              </el-input>
+            </el-form-item>
+            <el-form-item label="保健方面">
+              <el-input
+              type="textarea"
+              placeholder="请输入内容"
+              v-model="patientForm.doctorAdviceJson.healthAdvice">
+              </el-input>
+            </el-form-item>
+
+            <el-form-item label="注意禁忌">
+              <el-input
+              type="textarea"
+              placeholder="请输入内容"
+              v-model="patientForm.taboo">
+              </el-input>
+            </el-form-item>
+            <el-form-item label="客户需求">
+              <el-input  v-model="patientForm.customerRequire"></el-input>
+            </el-form-item>
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="职业医师" prop="age">
+                  <el-input  v-model="patientForm.professionalDoctor"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="医生助理" prop="mobile">
+                  <el-input  v-model="patientForm.assistantDoctor"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <div class="contentx">
+              <div class="desct">
+                治疗方面
+              </div>
+              </div>
+            <div v-for="(i,index) in patientForm.doctorAdviceJson.treatmentAdvice" :key="index">
+              <el-row>
+                <el-col :span="8">
+                  <el-form-item label="诊断内容" prop="content">
+                    <el-input  v-model="i.content"></el-input>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8">
+                  <el-form-item label="建议治疗" prop="advice">
+                    <el-input  v-model="i.advice"></el-input>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8">
+                  <el-button style="margin: 5px;" v-if="index+1 == patientForm.doctorAdviceJson.treatmentAdvice.length" @click="addItem(patientForm.doctorAdviceJson.treatmentAdvice.length)" type="primary" size="mini">+</el-button>
+                  <el-button style="margin: 5px;"  v-if="index !== 0" type="danger" size="mini" @click="delItem(i,index)">-</el-button>
+                </el-col>
+                
+              </el-row>
+            </div>
+          </el-form>
+          <span slot="footer" class="dialog-footer">
+             <el-button @click="patientOpen = false">取 消</el-button>
+             <el-button type="primary" @click="patientInquirySubmit">确 定</el-button>
+          </span>
+        </el-dialog>
  </div>
 
 <div class="contentx" v-if="item!=null">
@@ -259,6 +453,7 @@
 
 <script>
 import { msglist, sendMsg,listinquiryOrder,editStatus, logList,getinquiryOrder, delinquiryOrder, addinquiryOrder, updateinquiryOrder, exportinquiryOrder ,cancelOrder,refundOrder} from "@/api/his/inquiryOrder";
+import {addinquiryPatient, updateinquiryPatient, detail} from "@/api/his/inquiryPatient";
 import {getReportId} from "@/api/his/inquiryOrderReport";
 import msgDetails from '../../components/his/msgDetails.vue';
 import msgServiceDetails from '../../components/his/msgServiceDetails.vue';
@@ -273,6 +468,7 @@ import { js } from "js-beautify";
     components: { inquiryOrderReportDetails,msgDetails ,msgServiceDetails},
     data() {
       return {
+        patientOpen: false,
         logs:[],
         editStatusOpen:false,
         usageJson:{},
@@ -313,6 +509,21 @@ import { js } from "js-beautify";
         doctor:[],
         user:[],
         sexOptions: [],
+        patientForm: {
+          doctorAdviceJson: {
+            diagnosis: '',
+            foodAdvice: '',
+            sportAdvice: '',
+            healthAdvice: '',
+            treatmentAdvice: [
+              //默认一条
+              {
+                content: '',
+                advice: '',
+              }
+            ]
+          }
+        },
       }
     },
     created() {
@@ -340,6 +551,37 @@ import { js } from "js-beautify";
 
     },
     methods: {
+      addItem(length){
+        this.patientForm.doctorAdviceJson.treatmentAdvice.push({
+          content:'',
+          advice:'',
+        })
+        let ak = this.patientForm.doctorAdviceJson.treatmentAdvice.filter(obj => obj.content != '');
+      },
+      delItem(item,index){
+        this.patientForm.doctorAdviceJson.treatmentAdvice.splice(index,1)
+      },
+      handlePatient(){
+        this.patientOpen = true;
+        detail(this.item.orderId).then(res => {
+          this.patientForm = res.data;
+          if(!this.patientForm.doctorAdviceJson) {
+            this.patientForm.doctorAdviceJson = {
+              diagnosis: '',
+              foodAdvice: '',
+              sportAdvice: '',
+              healthAdvice: '',
+              treatmentAdvice: [
+                //默认一条
+                {
+                  content: '',
+                  advice: '',
+                }
+              ]
+            }
+          }
+        })
+      },
       cancelorder(){
         var that=this;
         this.$confirm('是否确认取消订单?', "警告", {
@@ -369,6 +611,25 @@ import { js } from "js-beautify";
           });
           });
       },
+      patientInquirySubmit(){
+        this.patientForm.patientId = this.item.patientId;
+        this.patientForm.companyUserId = this.item.companyUserId;
+        this.patientForm.userId = this.item.userId;
+        this.patientForm.inquiryOrderId = this.item.orderId;
+        this.patientForm.subDoctorId = this.item.doctorId;
+        console.log(this.patientForm);
+        if(this.patientForm.id != null) {
+          updateinquiryPatient(this.patientForm).then(res => {
+            this.msgSuccess("更新成功");
+            this.patientOpen = false;
+          })
+        } else {
+          addinquiryPatient(this.patientForm).then(res => {
+            this.msgSuccess("添加成功");
+            this.patientOpen = false;
+          })
+        }
+      },
       msgServiceDetailsClose(){
         this.msgServiceDetails.open = false;
       },

+ 324 - 0
src/views/course/coursePlaySourceConfig/index.vue

@@ -0,0 +1,324 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="appid" prop="appid">
+        <el-input
+          v-model="queryParams.appid"
+          placeholder="请输入appid"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['course:playSourceConfig:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['course:playSourceConfig:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['course:playSourceConfig:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="id" />
+      <el-table-column label="名称" align="center" prop="name" />
+      <el-table-column label="图标" align="center" prop="img">
+        <template slot-scope="scope">
+          <el-image
+            style="width: 80px; height: 80px"
+            :src="scope.row.img"
+            :preview-src-list="[scope.row.img]">
+          </el-image>
+        </template>
+      </el-table-column>
+      <el-table-column label="原始ID" align="center" prop="originalId" />
+      <el-table-column label="appId" align="center" prop="appid" />
+      <el-table-column label="secret" align="center" prop="secret" />
+      <el-table-column label="token" align="center" prop="token" />
+      <el-table-column label="aesKey" align="center" prop="aesKey" />
+      <el-table-column label="msgDataFormat" align="center" prop="msgDataFormat" />
+      <el-table-column label="类型" align="center" prop="type">
+        <template slot-scope="scope">
+          <dict-tag  :options="typesOptions" :value="scope.row.type"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" />
+      <el-table-column label="修改时间" align="center" prop="updateTime" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['course:playSourceConfig:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['course:playSourceConfig:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改点播配置对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="130px">
+        <el-form-item label="名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入名称" />
+        </el-form-item>
+        <el-form-item label="图标" prop="img">
+          <image-upload v-model="form.img" :file-type='["png", "jpg", "jpeg"]' :limit="1"/>
+        </el-form-item>
+        <el-form-item label="类型" prop="type">
+          <el-select
+            v-model="form.type"
+            placeholder="请选择类型">
+            <el-option
+              v-for="item in typesOptions"
+              :key="item.dictValue"
+              :label="item.dictLabel"
+              :value="item.dictValue"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="原始id" prop="originalId">
+          <el-input v-model="form.originalId" placeholder="请输入原始id" />
+        </el-form-item>
+        <el-form-item label="appid" prop="appid">
+          <el-input v-model="form.appid" placeholder="请输入appid" />
+        </el-form-item>
+        <el-form-item label="secret" prop="secret">
+          <el-input v-model="form.secret" placeholder="请输入secret" />
+        </el-form-item>
+        <el-form-item label="token" prop="token">
+          <el-input v-model="form.token" placeholder="请输入token" />
+        </el-form-item>
+        <el-form-item label="aesKey" prop="aesKey">
+          <el-input v-model="form.aesKey" placeholder="请输入aesKey" />
+        </el-form-item>
+        <el-form-item label="msgDataFormat" prop="msgDataFormat">
+          <el-input v-model="form.msgDataFormat" placeholder="请输入msgDataFormat" />
+        </el-form-item>
+
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import {list, get, update, add, del} from '@/api/course/coursePlaySourceConfig'
+
+export default {
+  name: 'CoursePlaySourceConfig',
+  data() {
+    return {
+      queryParams: {},
+      showSearch: true,
+      single: true,
+      multiple: true,
+      ids: [],
+      loading: false,
+      list: [],
+      total: 0,
+      typesOptions: [],
+      title: null,
+      open: false,
+      form: {},
+      rules: {
+        name: [
+          { required: true, message: "名称不能为空", trigger: "blur" }
+        ],
+        appid: [
+          { required: true, message: "appid不能为空", trigger: "blur" }
+        ],
+        secret: [
+          { required: true, message: "secret不能为空", trigger: "blur" }
+        ],
+        token: [
+          { required: true, message: "token不能为空", trigger: "blur" }
+        ],
+        aesKey: [
+          { required: true, message: "aesKey不能为空", trigger: "blur" }
+        ],
+        msgDataFormat: [
+          { required: true, message: "msgDataFormat不能为空", trigger: "blur" }
+        ]
+      }
+    }
+  },
+  created() {
+    this.getDicts("play_source_type").then(response => {
+      this.typesOptions = response.data.map(item =>  {
+        return {
+        ...item,
+        listClass: 'primary'}
+      })
+    });
+    this.getList();
+  },
+  methods: {
+    getList() {
+      this.loading = true;
+      list(this.queryParams).then(response => {
+        this.list = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.getList();
+    },
+    handleAdd() {
+      this.reset()
+      this.open = true
+      this.title = "添加点播配置"
+    },
+    handleUpdate(row) {
+      this.reset()
+      const id = row.id || this.ids
+      get(id).then(response => {
+        this.form = {
+          ...response.data,
+          type: response.data.type.toString()
+        }
+        this.open = true
+        this.title = "修改点播配置"
+      })
+    },
+    handleDelete(row) {
+      const id = row.id || this.ids
+      this.$confirm('是否确认删除点播配置编号为"' + id + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return del(id);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            update(this.form).then(response => {
+              const {code, msg} = response
+              if (code !== 200) {
+                this.msgError(msg)
+                return
+              }
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            add(this.form).then(response => {
+              const {code, msg} = response
+              if (code !== 200) {
+                this.msgError(msg)
+                return
+              }
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    reset() {
+      this.form = {
+        id: null,
+        name: null,
+        appid: null,
+        secret: null,
+        img: null,
+        originalId: null,
+        token: null,
+        aesKey: null,
+        msgDataFormat: null,
+        type: '1'
+      }
+      this.resetForm("form");
+    }
+  },
+}
+</script>
+
+<style scoped>
+
+</style>

+ 302 - 0
src/views/food/record/index.vue

@@ -0,0 +1,302 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="用户ID" prop="userId">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入用户ID"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="用餐日期" prop="recordDate">
+        <el-date-picker clearable
+                        v-model="queryParams.recordDate"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="请选择用餐日期">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="用餐描述" prop="mealDescription">
+        <el-input
+          v-model="queryParams.mealDescription"
+          placeholder="请输入用餐描述"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['food:record:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['food:record:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['food:record:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="foodRecordList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="记录ID" align="center" prop="id" />
+      <el-table-column label="用户" align="center" prop="username" >
+        <template slot-scope="scope">
+          <span>{{scope.row.username}}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="用餐日期" align="center" prop="recordDate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.recordDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="记录时间" align="center" prop="recordTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ scope.row.recordTime }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="用餐描述" align="center" prop="mealDescription" :show-overflow-tooltip="true" />
+      <el-table-column label="创建时间" align="center" prop="createdAt" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createdAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['food:record:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['food:record:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改饮食记录对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="用户ID" prop="userId">
+          <el-input v-model="form.userId" placeholder="请输入用户ID" />
+        </el-form-item>
+        <el-form-item label="用餐日期" prop="recordDate">
+          <el-date-picker clearable
+                          v-model="form.recordDate"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          placeholder="请选择用餐日期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="记录时间" prop="recordTime">
+          <el-time-picker
+            v-model="form.recordTime"
+            value-format="HH:mm:ss"
+            placeholder="请选择记录时间">
+          </el-time-picker>
+        </el-form-item>
+        <el-form-item label="用餐描述" prop="mealDescription">
+          <el-input v-model="form.mealDescription" type="textarea" placeholder="请输入用餐情况描述" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listFoodRecord, getFoodRecord, delFoodRecord, addFoodRecord, updateFoodRecord } from "@/api/food/record";
+import {parseTime} from "../../../utils/common";
+
+export default {
+  name: "FoodRecord",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 饮食记录表格数据
+      foodRecordList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        recordDate: null,
+        mealDescription: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        userId: [
+          { required: true, message: "用户ID不能为空", trigger: "blur" }
+        ],
+        recordDate: [
+          { required: true, message: "用餐日期不能为空", trigger: "blur" }
+        ],
+        mealDescription: [
+          { required: true, message: "用餐描述不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    parseTime,
+    /** 查询饮食记录列表 */
+    getList() {
+      this.loading = true;
+      listFoodRecord(this.queryParams).then(response => {
+        this.foodRecordList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        userId: null,
+        recordDate: null,
+        recordTime: null,
+        mealDescription: null,
+        createdAt: null,
+        updatedAt: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加饮食记录";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getFoodRecord(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改饮食记录";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateFoodRecord(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addFoodRecord(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除饮食记录编号为"' + ids + '"的数据项?').then(function() {
+        return delFoodRecord(ids);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    }
+  }
+};
+</script>

+ 16 - 1
src/views/his/company/index.vue

@@ -472,6 +472,7 @@ export default {
         courseMaAppId: null,
         courseMiniAppId: null,
         miniAppMaster: [],
+        miniAppServer:[],
         miniAppList: [],
       },
       // 表单校验
@@ -753,9 +754,15 @@ export default {
     submitForm() {
       this.$refs["form"].validate(valid => {
         if (valid) {
-          if(this.form.followDoctorIds!=null){
+
+          if (this.form.followDoctorIds==null || this.form.followDoctorIds.length==0){
+            this.form.followDoctorIds=null;
+          }
+
+          if(this.form.followDoctorIds!=null && this.form.followDoctorIds.length>0){
              this.form.followDoctorIds= JSON.stringify(this.form.followDoctorIds)
           }
+
           if(this.form.packageCateIds!=null){
              this.form.packageCateIds= JSON.stringify(this.form.packageCateIds)
           }
@@ -765,6 +772,14 @@ export default {
           if(this.doctorIds!=null){
             this.form.doctorIds= (this.doctorIds).toString()
           }
+          if (this.form.miniAppMaster==null || this.form.miniAppMaster.length ===0 ){
+            return this.$message.error("请选择主小程序")
+          }
+
+          if (this.form.miniAppServer==null || this.form.miniAppServer.length ===0 ){
+            return this.$message.error("请选择备小程序")
+          }
+
           if (this.form.companyId != null) {
             updateCompany(this.form).then(response => {
               this.msgSuccess("修改成功");

+ 1 - 0
src/views/his/user/index.vue

@@ -151,6 +151,7 @@
       </el-table-column>
       <el-table-column label="所属公司" align="center" prop="companyName" />
       <el-table-column label="所属销售" align="center" prop="companyUserNickName" />
+      <el-table-column label="用户备注" align="center" prop="remark" />
       <el-table-column label="上级昵称" align="center" prop="tuiName" />
       <el-table-column label="app来源" align="center" prop="source" />
       <el-table-column label="登陆设备" align="center" prop="loginDevice" />

+ 21 - 4
src/views/his/user/indexProject.vue

@@ -629,10 +629,27 @@ export default {
       const userId = row.userId || this.ids
       getUser(userId).then(response => {
         this.form = response.data;
-        this.form.status = response.data.status.toString();
-        this.form.isShow = response.data.isShow.toString();
-        this.form.level = response.data.level.toString();
-        this.form.isPromoter = response.data.isPromoter.toString();
+        if(response.data.status){
+          this.form.status = response.data.status.toString();
+        } else {
+          this.form.status = null;
+        }
+        if(response.data.isShow){
+          this.form.isShow = response.data.isShow.toString();
+        }else {
+          this.form.isShow = null;
+        }
+        if(response.data.level){
+          this.form.level = response.data.level.toString();
+        }else {
+          this.form.level = null;
+        }
+        if(response.data.isPromoter){
+          this.form.isPromoter = response.data.isPromoter.toString();
+        }else {
+          this.form.status = null;
+        }
+        
         this.open = true;
         this.title = "修改用户";
       });

+ 1 - 1
src/views/qw/sopTemp/updateSopTemp.vue

@@ -728,7 +728,7 @@ export default {
       dayList: [],
       ruleList: [],
       ids: [],
-      courseTypeList: ['3', '4', '9'],
+      courseTypeList: ['1','3', '4', '9'],
       sysFsSopWatchStatus: [],
       //消息内容类型 企微版
       sysQwSopContentType: [],

+ 272 - 0
src/views/saler/competitorInfo/index.vue

@@ -0,0 +1,272 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="竞品公司" prop="competitorCompany">
+        <el-input
+          v-model="queryParams.competitorCompany"
+          placeholder="请输入竞品公司"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="产品" prop="product">
+        <el-input
+          v-model="queryParams.product"
+          placeholder="请输入产品名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['saler:competitorInfo:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['saler:competitorInfo:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['saler:competitorInfo:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="competitorInfoList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="id" v-if="false" />
+      <el-table-column label="竞品公司" align="center" prop="competitorCompany" :show-overflow-tooltip="true" />
+      <el-table-column label="产品" align="center" prop="product" :show-overflow-tooltip="true" />
+      <el-table-column label="价格" align="center" prop="price" />
+      <el-table-column label="服务" align="center" prop="service" :show-overflow-tooltip="true" />
+      <el-table-column label="免费服务次数" align="center" prop="freeServiceTimes" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['saler:competitorInfo:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['saler:competitorInfo:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改竞品信息对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <el-form-item label="竞品公司" prop="competitorCompany">
+          <el-input v-model="form.competitorCompany" placeholder="请输入竞品公司" />
+        </el-form-item>
+        <el-form-item label="产品" prop="product">
+          <el-input v-model="form.product" placeholder="请输入产品" />
+        </el-form-item>
+        <el-form-item label="价格" prop="price">
+          <el-input-number v-model="form.price" :precision="2" :step="0.1" :min="0" placeholder="请输入价格" />
+        </el-form-item>
+        <el-form-item label="服务" prop="service">
+          <el-input v-model="form.service" type="textarea" placeholder="请输入服务内容" />
+        </el-form-item>
+        <el-form-item label="免费服务次数" prop="freeServiceTimes">
+          <el-input-number v-model="form.freeServiceTimes" :min="0" placeholder="请输入免费服务次数" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listCompetitorInfo, getCompetitorInfo, addCompetitorInfo, updateCompetitorInfo, delCompetitorInfo } from "@/api/saler/competitorInfo";
+
+export default {
+  name: "CompetitorInfo",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 竞品信息表格数据
+      competitorInfoList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        competitorCompany: null,
+        product: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        competitorCompany: [
+          { required: true, message: "竞品公司不能为空", trigger: "blur" }
+        ],
+        product: [
+          { required: true, message: "产品不能为空", trigger: "blur" }
+        ],
+        price: [
+          { required: true, message: "价格不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询竞品信息列表 */
+    getList() {
+      this.loading = true;
+      listCompetitorInfo(this.queryParams).then(response => {
+        this.competitorInfoList = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        competitorCompany: null,
+        product: null,
+        price: 0,
+        service: null,
+        freeServiceTimes: 0,
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加竞品信息";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getCompetitorInfo(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改竞品信息";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateCompetitorInfo(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addCompetitorInfo(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除竞品信息编号为"' + ids + '"的数据项?').then(function() {
+        return delCompetitorInfo(ids);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    }
+  }
+};
+</script>

+ 296 - 0
src/views/saler/productInfo/index.vue

@@ -0,0 +1,296 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="商品名称" prop="productName">
+        <el-input
+          v-model="queryParams.productName"
+          placeholder="请输入商品名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="会员情况" prop="memberStatus">
+        <el-input
+          v-model="queryParams.memberStatus"
+          placeholder="请输入会员情况"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['saler:productInfo:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['saler:productInfo:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['saler:productInfo:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="productInfoList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="商品ID" align="center" prop="id" />
+      <el-table-column label="商品名称" align="center" prop="productName" />
+      <el-table-column label="购买数量" align="center" prop="purchaseQuantity" />
+      <el-table-column label="金额" align="center" prop="amount" />
+      <el-table-column label="预计完成时间" align="center" prop="plannedCompletionDate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.plannedCompletionDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="购买次数" align="center" prop="purchaseTimes" />
+      <el-table-column label="剩余次数" align="center" prop="surplusTimes" />
+      <el-table-column label="会员情况" align="center" prop="memberStatus" />
+      <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['saler:productInfo:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['saler:productInfo:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改商品对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <el-form-item label="商品名称" prop="productName">
+          <el-input v-model="form.productName" placeholder="请输入商品名称" />
+        </el-form-item>
+        <el-form-item label="购买数量" prop="purchaseQuantity">
+          <el-input-number v-model="form.purchaseQuantity" :min="0" :max="9999" />
+        </el-form-item>
+        <el-form-item label="金额" prop="amount">
+          <el-input-number v-model="form.amount" :precision="2" :min="0" :step="0.01" />
+        </el-form-item>
+        <el-form-item label="预计完成时间" prop="plannedCompletionDate">
+          <el-date-picker clearable
+                          v-model="form.plannedCompletionDate"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          placeholder="请选择预计完成时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="购买次数" prop="purchaseTimes">
+          <el-input-number v-model="form.purchaseTimes" :min="0" :max="9999" />
+        </el-form-item>
+        <el-form-item label="剩余次数" prop="surplusTimes">
+          <el-input-number v-model="form.surplusTimes" :min="0" :max="9999" />
+        </el-form-item>
+        <el-form-item label="会员情况" prop="memberStatus">
+          <el-input v-model="form.memberStatus" placeholder="请输入会员情况" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listProductInfo, getProductInfo, addProductInfo, updateProductInfo, delProductInfo } from "@/api/saler/productInfo";
+
+export default {
+  name: "ProductInfo",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 商品表格数据
+      productInfoList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        productName: null,
+        memberStatus: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        productName: [
+          { required: true, message: "商品名称不能为空", trigger: "blur" }
+        ],
+        purchaseQuantity: [
+          { required: true, message: "购买数量不能为空", trigger: "blur" }
+        ],
+        amount: [
+          { required: true, message: "金额不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询商品列表 */
+    getList() {
+      this.loading = true;
+      listProductInfo(this.queryParams).then(response => {
+        this.productInfoList = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        productName: null,
+        purchaseQuantity: 0,
+        amount: 0,
+        plannedCompletionDate: null,
+        purchaseTimes: 0,
+        surplusTimes: 0,
+        memberStatus: null,
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加商品";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids[0]
+      getProductInfo(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改商品";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateProductInfo(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addProductInfo(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除商品编号为"' + ids + '"的数据项?').then(function() {
+        return delProductInfo(ids);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    }
+  }
+};
+</script>

+ 4 - 4
src/views/system/config/config.vue

@@ -1417,13 +1417,13 @@
          <el-form ref="form20" :model="form20" :rules="rules20" label-width="120px">
            <el-form-item label="评级天数(天)" prop="levelDay">
              <el-tooltip class="item" effect="dark" content="最小评级天数(天)" placement="top-end">
-               <el-input-number v-model="form20.levelDay" :min="7" :max="365"></el-input-number>
+               <el-input-number v-model="form20.levelDay" :min="4" :max="365"></el-input-number>
              </el-tooltip>
            </el-form-item>
 
            <el-form-item label="超过多少天的客户没看课评E级" prop="levelDay">
              <el-tooltip class="item" effect="dark" content="超过多少天的客户没看课评E级,且不生成sop执行记录了,不发了" placement="top-end">
-               <el-input-number v-model="form20.notStudyDays" :min="7" :max="365"></el-input-number>
+               <el-input-number v-model="form20.notStudyDays" :min="4" :max="365"></el-input-number>
              </el-tooltip>
            </el-form-item>
 
@@ -1633,8 +1633,8 @@ export default {
       form19:{
       },
       form20:{
-        levelDay: 7,
-        notStudyDays:7,
+        levelDay: 4,
+        notStudyDays:4,
         aLevelMin: 80,
         aLevelMax: 100,
         bLevelMin: 40,

+ 4 - 4
src/views/system/config/config2.vue

@@ -1172,13 +1172,13 @@
          <el-form ref="form20" :model="form20" :rules="rules20" label-width="120px">
            <el-form-item label="评级天数(天)" prop="levelDay">
              <el-tooltip class="item" effect="dark" content="最小评级天数(天)" placement="top-end">
-               <el-input-number v-model="form20.levelDay" :min="7" :max="365"></el-input-number>
+               <el-input-number v-model="form20.levelDay" :min="4" :max="365"></el-input-number>
              </el-tooltip>
            </el-form-item>
 
            <el-form-item label="超过多少天的客户没看课评E级" prop="levelDay">
              <el-tooltip class="item" effect="dark" content="超过多少天的客户没看课评E级,且不生成sop执行记录了,不发了" placement="top-end">
-               <el-input-number v-model="form20.notStudyDays" :min="7" :max="365"></el-input-number>
+               <el-input-number v-model="form20.notStudyDays" :min="4" :max="365"></el-input-number>
              </el-tooltip>
            </el-form-item>
 
@@ -1366,8 +1366,8 @@ export default {
       form19:{
       },
       form20:{
-        levelDay: 7,
-        notStudyDays:7,
+        levelDay: 4,
+        notStudyDays:4,
         aLevelMin: 80,
         aLevelMax: 100,
         bLevelMin: 40,

+ 8 - 2
src/views/system/role/index.vue

@@ -189,7 +189,7 @@
             >{{dict.dictLabel}}</el-radio>
           </el-radio-group>
         </el-form-item>
-        <el-form-item label="是否可以查看手机全号" >
+        <el-form-item label="是否可以查看手机全号" v-if="isAdmin == 1">
           <span slot="label">
             <el-tooltip content="是否可以查看手机全号" placement="top">
               <i class="el-icon-question"></i>
@@ -361,7 +361,7 @@ export default {
         roleSort: [
           { required: true, message: "角色顺序不能为空", trigger: "blur" }
         ]
-      }
+      },
     };
   },
   created() {
@@ -370,6 +370,12 @@ export default {
       this.statusOptions = response.data;
     });
   },
+  computed: {
+    isAdmin() {
+      console.log(this.$store.state.user.isAdmin)
+      return this.$store.state.user.isAdmin
+    }
+  },
   methods: {
     /** 查询角色列表 */
     getList() {

+ 619 - 0
src/views/todo/todoItems/index.vue

@@ -0,0 +1,619 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px" >
+      <el-form-item label="标题" prop="title">
+        <el-input
+          v-model="queryParams.title"
+          placeholder="请输入待办事项标题"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="公司名称" prop="companyName">
+        <el-input
+          v-model="queryParams.companyName"
+          placeholder="请输入公司名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['todo:todoItems:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['todo:todoItems:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['todo:todoItems:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table
+      v-loading="loading"
+      :data="todoItemsList"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="id" />
+      <el-table-column label="标题" align="center" prop="title" />
+      <el-table-column label="分配者" align="center" prop="creatorName" />
+      <el-table-column label="执行人" align="center" prop="assigneeName" />
+      <el-table-column label="描述" align="center" prop="description" show-overflow-tooltip />
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <el-tag :type="getStatusType(scope.row.status)" size="small">
+            {{ getStatusLabel(scope.row.status) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="优先级" align="center" prop="priority">
+        <template slot-scope="scope">
+          <el-tag :type="getPriorityType(scope.row.priority)" size="small">
+            {{ getPriorityLabel(scope.row.priority) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="截止时间" align="center" prop="dueDate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.dueDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="220">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['todo:todoItems:edit']"
+          >修改</el-button>
+<!--          <el-button-->
+<!--            size="mini"-->
+<!--            type="text"-->
+<!--            icon="el-icon-check"-->
+<!--            @click="handleUpdateStatus(scope.row)"-->
+<!--            v-hasPermi="['todo:todoItems:edit']"-->
+<!--          >更新状态</el-button>-->
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-user"
+            @click="handleAssignExecutor(scope.row)"
+            v-hasPermi="['todo:todoItems:edit']"
+            class="assign-executor-btn"
+          >分配执行者</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['todo:todoItems:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <div class="pagination-wrapper">
+      <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+      />
+    </div>
+
+    <!-- 添加或修改待办事项对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="标题" prop="title">
+          <el-input v-model="form.title" placeholder="请输入待办事项标题" />
+        </el-form-item>
+        <el-form-item label="描述" prop="description">
+          <el-input v-model="form.description" type="textarea" placeholder="请输入描述" />
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-select v-model="form.status" placeholder="请选择状态" default-first-option>
+            <el-option
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="优先级" prop="priority">
+          <el-select v-model="form.priority" placeholder="请选择优先级">
+            <el-option
+              v-for="dict in priorityOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="截止时间" prop="dueDate">
+          <el-date-picker clearable
+                          v-model="form.dueDate"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          placeholder="请选择截止时间">
+          </el-date-picker>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 更新状态对话框 -->
+    <el-dialog title="更新状态" :visible.sync="statusOpen" width="300px" append-to-body>
+      <el-form ref="statusForm" :model="statusForm" label-width="80px">
+        <el-form-item label="状态" prop="status">
+          <el-select v-model="statusForm.status" placeholder="请选择状态">
+            <el-option
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitStatusForm">确 定</el-button>
+        <el-button @click="cancelStatus">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 分配执行者对话框 -->
+    <el-dialog title="分配执行者" :visible.sync="assignOpen" width="700px" append-to-body>
+      <el-form ref="assignForm" :model="assignForm" :rules="assignRules" label-width="80px">
+        <el-form-item label="待办事项" prop="title">
+          <el-input v-model="assignForm.title" disabled />
+        </el-form-item>
+        <el-form-item label="执行者" prop="executorId">
+          <el-select v-model="assignForm.executorId" placeholder="请选择执行者" filterable class="executor-select">
+            <el-option
+              v-for="executor in executorList"
+              :key="executor.userId"
+              :label="executor.userName"
+              :value="executor.userId"
+            ></el-option>
+          </el-select>
+          <div class="el-form-item__tip">
+            <small>执行者列表会根据搜索条件中的公司名称进行过滤</small>
+          </div>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitAssignForm">确 定</el-button>
+        <el-button @click="cancelAssign">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listTodoItems, getTodoItems, delTodoItems, addTodoItems, updateTodoItems, updateTodoItemsStatus, assignExecutor, getExecutorList, getUserList } from "@/api/todo/todoItems";
+import {parseTime} from "../../../utils/common";
+
+export default {
+  name: "TodoItems",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 待办事项表格数据
+      todoItemsList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 是否显示状态更新弹出层
+      statusOpen: false,
+      // 是否显示分配执行者弹出层
+      assignOpen: false,
+      // 状态选项
+      statusOptions: [],
+      // 优先级选项
+      priorityOptions: [],
+      todoItemTypeOptions: [],
+      // 执行者列表
+      executorList: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        title: null,
+        companyName: null,
+        status: null
+      },
+      // 表单参数
+      form: {
+        status: 0
+      },
+      // 状态表单参数
+      statusForm: {},
+      // 分配执行者表单参数
+      assignForm: {
+        id: null,
+        title: '',
+        executorId: null,
+        remark: ''
+      },
+      // 表单校验
+      rules: {
+        title: [
+          { required: true, message: "标题不能为空", trigger: "blur" }
+        ],
+        status: [
+          { required: true, message: "状态不能为空", trigger: "change" }
+        ]
+      },
+      // 分配执行者表单校验
+      assignRules: {
+        executorId: [
+          { required: true, message: "请选择执行者", trigger: "change" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("todo_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("todo_priority").then(response => {
+      this.priorityOptions = response.data;
+    });
+    this.getDicts("todo_item_type").then(response => {
+      this.todoItemTypeOptions = response.data;
+    });
+    // 获取执行者列表
+    this.getExecutorList();
+  },
+  methods: {
+    parseTime,
+    /** 查询待办事项列表 */
+    getList() {
+      this.loading = true;
+      listTodoItems(this.queryParams).then(response => {
+        this.todoItemsList = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    /** 获取执行者列表 */
+    getExecutorList() {
+      const params = {
+        companyName: this.queryParams.companyName || '',
+        companyId: null,
+        pageNum: 1,
+        pageSize: 10 // 获取足够多的执行者供选择
+      };
+      getUserList(params).then(response => {
+        if (response.code === 200) {
+          this.executorList = response.data || [];
+        }
+      });
+    },
+    /** 获取状态标签 */
+    getStatusLabel(status) {
+      const statusOption = this.statusOptions.find(option => option.dictValue === String(status));
+      return statusOption ? statusOption.dictLabel : '未知';
+    },
+    /** 获取状态标签类型(颜色) */
+    getStatusType(status) {
+      const statusMap = {
+        '0': 'info',      // 待处理 - 蓝色
+        '1': 'warning',   // 进行中 - 橙色
+        '2': 'success',   // 已完成 - 绿色
+        '3': 'danger'     // 已取消 - 红色
+      };
+      return statusMap[String(status)] || 'info';
+    },
+    /** 获取优先级标签 */
+    getPriorityLabel(priority) {
+      const priorityOption = this.priorityOptions.find(option => option.dictValue === String(priority));
+      return priorityOption ? priorityOption.dictLabel : '未知';
+    },
+    /** 获取优先级标签类型(颜色) */
+    getPriorityType(priority) {
+      const priorityMap = {
+        '0': 'info',      // 低 - 蓝色
+        '1': 'success',   // 中 - 绿色
+        '2': 'warning',   // 高 - 橙色
+        '3': 'danger'     // 紧急 - 红色
+      };
+      return priorityMap[String(priority)] || 'info';
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 取消状态更新
+    cancelStatus() {
+      this.statusOpen = false;
+      this.statusForm = {};
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        title: null,
+        description: null,
+        status: null,
+        priority: null,
+        dueDate: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+      // 更新执行者列表
+      this.getExecutorList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+      // 重置后更新执行者列表
+      this.getExecutorList();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加待办事项";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      // 确保id是单个值,如果是数组则取第一个
+      const todoId = Array.isArray(id) ? id[0] : id;
+      getTodoItems(todoId).then(response => {
+        this.form = response.data;
+        // 确保数据类型匹配
+        if (this.form.status !== null && this.form.status !== undefined) {
+          this.form.status = String(this.form.status);
+        }
+        if (this.form.priority !== null && this.form.priority !== undefined) {
+          this.form.priority = String(this.form.priority);
+        }
+        this.open = true;
+        this.title = "修改待办事项";
+      });
+    },
+    /** 更新状态按钮操作 */
+    handleUpdateStatus(row) {
+      this.statusForm = {
+        id: row.id,
+        status: String(row.status)
+      };
+      this.statusOpen = true;
+    },
+    /** 分配执行者按钮操作 */
+    handleAssignExecutor(row) {
+      this.assignForm = {
+        id: row.id,
+        title: row.title,
+        executorId: row.executorId || null,
+        remark: ''
+      };
+      this.assignOpen = true;
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateTodoItems(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addTodoItems(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 提交状态更新 */
+    submitStatusForm() {
+      updateTodoItemsStatus(this.statusForm.id, this.statusForm.status).then(response => {
+        this.$message.success("状态更新成功");
+        this.statusOpen = false;
+        this.getList();
+      });
+    },
+    /** 提交分配执行者 */
+    submitAssignForm() {
+      this.$refs["assignForm"].validate(valid => {
+        if (valid) {
+          assignExecutor(this.assignForm).then(response => {
+            this.$message.success("执行者分配成功");
+            this.assignOpen = false;
+            this.getList();
+          });
+        }
+      });
+    },
+    /** 取消分配执行者 */
+    cancelAssign() {
+      this.assignOpen = false;
+      this.assignForm = {
+        id: null,
+        title: '',
+        executorId: null,
+        remark: ''
+      };
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除待办事项编号为"' + ids + '"的数据项?').then(function() {
+        return delTodoItems(ids);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    }
+  }
+}
+</script>
+
+<style scoped>
+.mb8 {
+  margin-bottom: 8px;
+}
+
+.fixed-width {
+  width: 100px;
+}
+
+
+
+
+
+.assign-executor-btn {
+  margin-left: 5px;
+}
+
+.executor-select {
+  width: 100%;
+}
+
+.el-form-item__tip {
+  margin-top: 5px;
+  color: #909399;
+  font-size: 12px;
+}
+
+
+
+
+/* 标签样式优化 */
+.el-tag {
+  border-radius: 12px;
+  font-weight: 500;
+  padding: 4px 12px;
+  border: none;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+/* 分页样式 */
+.pagination-wrapper {
+  margin-top: 20px;
+}
+
+.el-pagination {
+  text-align: center;
+  padding: 20px;
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+/* 对话框样式 */
+.el-dialog {
+  border-radius: 12px;
+  overflow: hidden;
+}
+
+.el-dialog__header {
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  color: white;
+  padding: 20px;
+}
+
+.el-dialog__title {
+  color: white;
+  font-weight: 600;
+}
+
+.el-dialog__body {
+  padding: 30px;
+}
+
+.el-dialog__footer {
+  padding: 20px;
+  border-top: 1px solid #ebeef5;
+  background: #f8f9fa;
+}
+
+
+</style>

+ 437 - 0
src/views/user/complaint/index.vue

@@ -0,0 +1,437 @@
+<template>
+  <div class="app-container">
+    <!-- 查询条件 -->
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="投诉单号" prop="complaintNo">
+        <el-input
+          v-model="queryParams.complaintNo"
+          placeholder="请输入投诉单号"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="投诉分类" prop="categoryId">
+        <el-select v-model="queryParams.categoryId" placeholder="请选择投诉分类" clearable>
+          <el-option
+            v-for="category in categoryList"
+            :key="category.id"
+            :label="category.categoryName"
+            :value="category.id"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="投诉状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择投诉状态" clearable>
+          <el-option label="待处理" value="0" />
+          <el-option label="已处理" value="1" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="投诉时间">
+        <el-date-picker
+          v-model="dateRange"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 操作按钮 -->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['complaint:add']"
+        >新增投诉</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['complaint:delete']"
+        >批量删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <!-- 投诉列表 -->
+    <el-table v-loading="loading" :data="complaintList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="投诉单号" align="center" prop="complaintNo" />
+      <el-table-column label="投诉人" align="center" prop="complainantName" />
+      <el-table-column label="投诉分类" align="center" prop="categoryName" />
+      <el-table-column label="投诉内容" align="center" prop="content" show-overflow-tooltip />
+      <el-table-column label="投诉状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.status === '0'" type="warning">待处理</el-tag>
+          <el-tag v-else-if="scope.row.status === '1'" type="success">已处理</el-tag>
+          <el-tag v-else type="info">未知</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="投诉时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleDetail(scope.row)"
+            v-hasPermi="['complaint:query']"
+          >详情</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['complaint:edit']"
+          >编辑</el-button>
+          <el-button
+            v-if="scope.row.status === '0'"
+            size="mini"
+            type="text"
+            icon="el-icon-check"
+            @click="handleProcess(scope.row)"
+            v-hasPermi="['complaint:edit']"
+          >处理</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['complaint:delete']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改投诉对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="投诉人" prop="complainantName">
+          <el-input v-model="form.complainantName" placeholder="请输入投诉人姓名" />
+        </el-form-item>
+        <el-form-item label="联系电话" prop="phone">
+          <el-input v-model="form.phone" placeholder="请输入联系电话" />
+        </el-form-item>
+
+        <el-form-item label="投诉分类" prop="type">
+          <el-select v-model="form.type" placeholder="请选择投诉分类" style="width: 100%">
+            <el-option
+              v-for="category in categoryList"
+              :key="category.id"
+              :label="category.categoryName"
+              :value="category.id"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="投诉内容" prop="content">
+          <el-input v-model="form.content" type="textarea" placeholder="请输入投诉内容" :rows="4" />
+        </el-form-item>
+        <!-- 图片上传 -->
+        <el-form-item label="投诉凭证" prop="url">
+          <image-upload
+            v-model="form.url"
+            :limit="0"
+            :file-size="5"
+            @change="handleImageChange"
+          />
+          <el-button type="primary" @click="submitForm">提交</el-button>
+        </el-form-item>
+        <el-form-item label="投诉状态" prop="status" v-if="form.id">
+          <el-select v-model="form.status" placeholder="请选择投诉状态">
+            <el-option label="待处理" value="0" />
+            <el-option label="已处理" value="1" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="处理备注" prop="remark" v-if="form.id">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入处理备注" :rows="3" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 投诉详情对话框 -->
+    <el-dialog title="投诉详情" :visible.sync="detailOpen" width="600px" append-to-body>
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="投诉单号">{{ detailData.complaintNo }}</el-descriptions-item>
+        <el-descriptions-item label="投诉状态">
+          <el-tag v-if="detailData.status === '0'" type="warning">待处理</el-tag>
+          <el-tag v-else-if="detailData.status === '1'" type="success">已处理</el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="投诉人">{{ detailData.complainantName }}</el-descriptions-item>
+        <el-descriptions-item label="联系电话">{{ detailData.phone }}</el-descriptions-item>
+        <el-descriptions-item label="投诉分类">{{ detailData.categoryName }}</el-descriptions-item>
+        <el-descriptions-item label="投诉时间" :span="2">
+          {{ parseTime(detailData.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}
+        </el-descriptions-item>
+        <el-descriptions-item label="投诉内容" :span="2">{{ detailData.content }}</el-descriptions-item>
+        <el-descriptions-item label="处理备注" :span="2" v-if="detailData.remark">
+          {{ detailData.remark }}
+        </el-descriptions-item>
+      </el-descriptions>
+      <div slot="footer" class="dialog--footer">
+        <el-button @click="detailOpen = false">关 闭</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  getComplaintPage,
+  getComplaintById,
+  submitComplaint,
+  updateComplaint,
+  deleteComplaint,
+  handleComplaint,
+  getAllCategory
+} from "@/api/complaint/complaint";
+import {parseTime} from "../../../utils/common";
+import ImageUpload from "@/components/ImageUpload/index.vue";
+
+export default {
+  name: "Complaint",
+  components: {ImageUpload},
+  data() {
+    return {
+      categoryList: [],
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 投诉表格数据
+      complaintList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 是否显示详情弹出层
+      detailOpen: false,
+      // 详情数据
+      detailData: {},
+      // 日期范围
+      dateRange: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        complaintNo: null,
+        status: null,
+        startTime: null,
+        endTime: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        complainantName: [
+          { required: true, message: "投诉人姓名不能为空", trigger: "blur" }
+        ],
+        phone: [
+          { required: true, message: "联系电话不能为空", trigger: "blur" },
+          { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }
+        ],
+        type: [
+          { required: true, message: "投诉分类不能为空", trigger: "change" }
+        ],
+        content: [
+          { required: true, message: "投诉内容不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getCategoryList();
+    this.getList();
+  },
+  methods: {
+    handleImageChange(newImages) {
+      this.form.url = newImages;
+    },
+    /** 获取投诉分类列表 */
+    getCategoryList() {
+      getAllCategory().then(response => {
+        this.categoryList = response.data || [];
+      }).catch(() => {
+        this.$message.error('获取投诉分类失败');
+        this.categoryList = [];
+      });
+    },
+    parseTime,
+    /** 查询投诉列表 */
+    getList() {
+      this.loading = true;
+      if (this.dateRange != null && this.dateRange.length === 2) {
+        this.queryParams.startTime = this.dateRange[0];
+        this.queryParams.endTime = this.dateRange[1];
+      } else {
+        this.queryParams.startTime = null;
+        this.queryParams.endTime = null;
+      }
+      getComplaintPage(this.queryParams).then(response => {
+        this.complaintList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        complainantName: null,
+        phone: null,
+        content: null,
+        status: "0",
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加投诉";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getComplaintById(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改投诉";
+      });
+    },
+    /** 查看详情 */
+    handleDetail(row) {
+      getComplaintById(row.id).then(response => {
+        this.detailData = response.data;
+        this.detailOpen = true;
+      });
+    },
+    /** 处理投诉 */
+    handleProcess(row) {
+      this.$confirm('是否确认将投诉单号为"' + row.complaintNo + '"的投诉标记为已处理?').then(() => {
+        handleComplaint(row.id).then(() => {
+          this.$message.success('处理成功');
+          this.getList();
+        }).catch(() => {
+          this.$message.error('处理失败');
+        });
+      });
+    },
+    /** 删除投诉 */
+    handleDelete(row) {
+      const ids = row ? [row.id] : this.ids;
+      this.$confirm('确认删除选中的投诉吗?').then(() => {
+        deleteComplaint(ids).then(() => {
+          this.$message.success('删除成功');
+          this.getList();
+        }).catch(() => {
+          this.$message.error('删除失败');
+        });
+      });
+    },
+    /** 提交表单 */
+    submitForm() {
+      this.$refs['form'].validate((valid) => {
+        if (valid) {
+          if (this.form.id) {
+            updateComplaint(this.form.id, this.form).then(() => {
+              this.$message.success('修改成功');
+              this.getList();
+              this.cancel();
+            }).catch(() => {
+              this.$message.error('修改失败');
+            });
+          } else {
+            submitComplaint(this.form).then(() => {
+              this.$message.success('添加成功');
+              this.getList();
+              this.cancel();
+            }).catch(() => {
+              this.$message.error('添加失败');
+            });
+          }
+        } else {
+          return false;
+        }
+      });
+    }
+  }
+};
+</script>
+
+<style scoped>
+.app-container {
+  padding: 20px;
+}
+.mb8 {
+  margin-bottom: 8px;
+}
+.fixed-width {
+  width: 120px;
+}
+</style>