ソースを参照

Merge remote-tracking branch 'origin/master'

yuhongqi 6 日 前
コミット
525bf6ea8a

+ 1 - 1
package.json

@@ -137,8 +137,8 @@
     "eslint": "7.15.0",
     "eslint-plugin-vue": "7.2.0",
     "lint-staged": "10.5.3",
-    "node-sass": "4.14.1",
     "runjs": "4.4.2",
+    "sass": "^1.98.0",
     "sass-loader": "8.0.2",
     "script-ext-html-webpack-plugin": "2.1.5",
     "svg-sprite-loader": "5.1.1",

+ 78 - 0
src/api/crm/customerProperty.js

@@ -0,0 +1,78 @@
+import request from '@/utils/request'
+
+export function listByCustomerId(customerId) {
+  return request({
+    url: '/crm/customerProperty/list/' + customerId,
+    method: 'get'
+  })
+}
+
+export function getById(id) {
+  return request({
+    url: '/crm/customerProperty/' + id,
+    method: 'get'
+  })
+}
+
+export function add(data) {
+  return request({
+    url: '/crm/customerProperty/add',
+    method: 'post',
+    data: data
+  })
+}
+
+export function addOrUpdate(data) {
+  return request({
+    url: '/crm/customerProperty/addOrUpdate',
+    method: 'post',
+    data: data
+  })
+}
+
+export function addByTemplateId(customerId, templateId, propertyValue) {
+  return request({
+    url: '/crm/customerProperty/addByTemplateId',
+    method: 'post',
+    params: { customerId, templateId, propertyValue }
+  })
+}
+
+export function addOrUpdateByTemplateId(customerId, templateId, propertyValue) {
+  return request({
+    url: '/crm/customerProperty/addOrUpdateByTemplateId',
+    method: 'post',
+    params: { customerId, templateId, propertyValue }
+  })
+}
+
+export function batchAddByTemplateIds(customerId, propertyMap) {
+  return request({
+    url: '/crm/customerProperty/batchAddByTemplateIds/' + customerId,
+    method: 'post',
+    data: propertyMap
+  })
+}
+
+export function update(data) {
+  return request({
+    url: '/crm/customerProperty',
+    method: 'put',
+    data: data
+  })
+}
+
+export function del(ids) {
+  return request({
+    url: '/crm/customerProperty/' + ids,
+    method: 'delete'
+  })
+}
+
+export function deleteByPropertyId(customerId, propertyId) {
+  return request({
+    url: '/crm/customerProperty/deleteByPropertyId',
+    method: 'delete',
+    params: { customerId, propertyId }
+  })
+}

+ 47 - 0
src/api/crm/propertyTemplate.js

@@ -0,0 +1,47 @@
+import request from '@/utils/request'
+
+export function listPropertyTemplate(query) {
+  return request({
+    url: '/crm/customerPropertyTemplate/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function getPropertyTemplate(id) {
+  return request({
+    url: '/crm/customerPropertyTemplate/' + id,
+    method: 'get'
+  })
+}
+
+export function addPropertyTemplate(data) {
+  return request({
+    url: '/crm/customerPropertyTemplate',
+    method: 'post',
+    data: data
+  })
+}
+
+export function updatePropertyTemplate(data) {
+  return request({
+    url: '/crm/customerPropertyTemplate',
+    method: 'put',
+    data: data
+  })
+}
+
+export function delPropertyTemplate(id) {
+  return request({
+    url: '/crm/customerPropertyTemplate/' + id,
+    method: 'delete'
+  })
+}
+
+export function exportPropertyTemplate(query) {
+  return request({
+    url: '/crm/customerPropertyTemplate/export',
+    method: 'get',
+    params: query
+  })
+}

+ 9 - 0
src/api/his/courserCoupon.js

@@ -50,4 +50,13 @@ export function exportCourserCoupon(query) {
     method: 'get',
     params: query
   })
+}
+
+
+// 课程优惠券选项列表
+export function options() {
+  return request({
+    url: '/his/courserCoupon/options',
+    method: 'get'
+  })
 }

+ 60 - 0
src/api/qw/qwPushCount.js

@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+// 查询定义销售推送不同类型的企业消息的次数列表
+export function listQwPushCount(query) {
+  return request({
+    url: '/qw/qwPushCount/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询定义销售推送不同类型的企业消息的次数详细
+export function getQwPushCount(id) {
+  return request({
+    url: '/qw/qwPushCount/' + id,
+    method: 'get'
+  })
+}
+
+// 新增定义销售推送不同类型的企业消息的次数
+export function addQwPushCount(data) {
+  return request({
+    url: '/qw/qwPushCount',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改定义销售推送不同类型的企业消息的次数
+export function updateQwPushCount(data) {
+  return request({
+    url: '/qw/qwPushCount',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除定义销售推送不同类型的企业消息的次数
+export function delQwPushCount(id) {
+  return request({
+    url: '/qw/qwPushCount/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出定义销售推送不同类型的企业消息的次数
+export function exportQwPushCount(query) {
+  return request({
+    url: '/qw/qwPushCount/export',
+    method: 'get',
+    params: query
+  })
+}
+//查询对应的公司
+export function getCompanyList() {
+  return request({
+    url: '/qw/qwPushCount/getCompanyList',
+    method: 'get'
+  })
+}

+ 19 - 1
src/views/components/course/userCourseCatalogDetails.vue

@@ -344,6 +344,16 @@
             <el-radio :label="1">下架</el-radio>
           </el-radio-group>
         </el-form-item>
+        <el-form-item label="课程优惠券" prop="courseCouponId">
+          <el-select v-model="form.courseCouponId" clearable placeholder="请选择课程优惠券">
+            <el-option
+              v-for="item in courseCouponList"
+              :key="item.id"
+              :label="item.title"
+              :value="item.id">
+            </el-option>
+          </el-select>
+        </el-form-item>
         <el-form-item label="商品选择" v-if="form.isProduct === 1">
           <el-button size="small" type="primary" @click="chooseCourseProduct">选取商品</el-button>
           <el-table border width="100%" style="margin-top:5px;" :data="form.courseProducts">
@@ -704,6 +714,7 @@ import {getCateListByPid, getCatePidList, getPublicCateListByPid, getPublicCateP
 import {downloadCommentImportTemplate, importComments, listFeaturedComments, delUserCourseComment} from '@/api/course/userCourseComment'
 import draggable from 'vuedraggable'
 import { getConfigByKey } from '@/api/system/config'
+import { options as courserCouponOptions} from "@/api/his/courserCoupon";
 
 export default {
   name: "userCourseCatalog",
@@ -727,6 +738,7 @@ export default {
   },
   data() {
     return {
+      courseCouponList: [],
       duration: null,
       packageList: [],
       //课题
@@ -913,7 +925,13 @@ export default {
         }
     }).catch(res=>{
 
-    })
+    });
+    courserCouponOptions().then(res=>{ 
+      this.courseCouponList = res.data;
+    }).catch(res=>{
+
+    });
+    
   },
   methods: {
     getPickerOptions() {

+ 388 - 0
src/views/crm/components/AiTagPanel.vue

@@ -0,0 +1,388 @@
+<template>
+  <div class="ai-tag-container">
+    <div class="ai-tag-header">
+      <div class="header-left">
+        <i class="el-icon-magic-sticker" style="color: #6b5fff; font-size: 18px; margin-right: 6px;"></i>
+        <span class="tag-title">AI 标签</span>
+        <el-tooltip content="AI 自动打标签" placement="bottom">
+          <span class="tag-subtitle">(AI 自动打标签)</span>
+        </el-tooltip>
+      </div>
+      <div class="header-right">
+        <el-button type="text" icon="el-icon-plus" size="mini" @click="handleAddTag" style="color: #ff9800;">
+          点击增加 AI 标签维度
+        </el-button>
+        <el-button type="text" icon="el-icon-view" size="mini" @click="toggleView" style="margin-left: 10px;">
+          <i class="el-icon-view"></i>
+        </el-button>
+      </div>
+    </div>
+
+    <div class="ai-tag-content" v-loading="loading">
+      <div v-if="tagList.length === 0" class="empty-tips">
+        <i class="el-icon-info"></i>
+        <span>暂无标签,点击"添加标签"开始设置</span>
+      </div>
+
+      <div v-else class="tag-list">
+        <div v-for="(tag, index) in tagList" :key="tag.id" class="tag-item">
+          <div class="tag-name">
+            <i class="el-icon-more"></i>
+            <span>{{ tag.propertyName }}</span>
+          </div>
+          <div class="tag-values">
+            <el-tag
+              v-if="tag.propertyValue"
+              size="small"
+              closable
+              @close="handleDeleteTag(tag)"
+              @click="handleEditTag(tag)"
+              style="cursor: pointer; margin-right: 8px; margin-bottom: 8px;"
+            >
+              {{ tag.propertyValue }}
+            </el-tag>
+            <span v-else class="no-value">未设置</span>
+            <el-button
+              v-if="!tag.propertyValue"
+              type="text"
+              size="mini"
+              icon="el-icon-edit"
+              @click="handleEditTag(tag)"
+            >
+              批注
+            </el-button>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 添加/编辑标签弹窗 -->
+    <el-dialog
+      :title="dialogTitle"
+      :visible.sync="dialogVisible"
+      width="600px"
+      append-to-body
+      :close-on-click-modal="false"
+    >
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="标签维度" prop="propertyId">
+          <el-select
+            v-model="form.propertyId"
+            placeholder="请选择标签维度"
+            style="width: 100%"
+            :disabled="isEdit"
+            @change="handlePropertyChange"
+          >
+            <el-option
+              v-for="item in propertyTemplateList"
+              :key="item.id"
+              :label="item.name"
+              :value="item.id"
+            >
+              <span style="float: left">{{ item.name }}</span>
+              <span style="float: right; color: #8492a6; font-size: 13px">{{ getValueTypeText(item.valueType) }}</span>
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="标签值" prop="propertyValue">
+          <el-input
+            v-if="currentValueType === 'text'"
+            v-model="form.propertyValue"
+            placeholder="请输入标签值"
+            maxlength="100"
+            show-word-limit
+          />
+          <el-select
+            v-else-if="currentValueType === 'select'"
+            v-model="form.propertyValue"
+            placeholder="请选择标签值"
+            style="width: 100%"
+            clearable
+          >
+            <el-option label="是" value="是" />
+            <el-option label="否" value="否" />
+          </el-select>
+          <el-input
+            v-else-if="currentValueType === 'number'"
+            v-model="form.propertyValue"
+            placeholder="请输入数字"
+            maxlength="20"
+          />
+          <el-input
+            v-else-if="currentValueType === 'date'"
+            v-model="form.propertyValue"
+            type="date"
+            placeholder="选择日期"
+            style="width: 100%"
+          />
+          <span v-else class="unknown-type">未知的属性类型</span>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input
+            v-model="form.remark"
+            type="textarea"
+            :rows="2"
+            placeholder="请输入备注"
+            maxlength="200"
+            show-word-limit
+          />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="dialogVisible = false">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listPropertyTemplate } from "@/api/crm/propertyTemplate";
+import { listByCustomerId, addOrUpdateByTemplateId, deleteByPropertyId } from "@/api/crm/customerProperty";
+
+export default {
+  name: "AiTagPanel",
+  props: {
+    customerId: {
+      type: Number,
+      required: true,
+      default: null
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      tagList: [],
+      propertyTemplateList: [],
+      dialogVisible: false,
+      dialogTitle: "",
+      isEdit: false,
+      currentValueType: "text",
+      form: {
+        customerId: null,
+        propertyId: null,
+        propertyName: null,
+        propertyValue: null,
+        propertyValueType: null,
+        tradeType: null,
+        remark: null
+      },
+      rules: {
+        propertyId: [
+          { required: true, message: "请选择标签维度", trigger: "change" }
+        ],
+        propertyValue: [
+          { required: true, message: "请输入标签值", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    if (this.customerId) {
+      this.loadTags();
+    }
+  },
+  watch: {
+    customerId(newVal) {
+      if (newVal) {
+        this.loadTags();
+      }
+    }
+  },
+  methods: {
+    loadTags() {
+      this.loading = true;
+      listByCustomerId(this.customerId).then(response => {
+        this.tagList = response.data || [];
+        this.loading = false;
+      }).catch(() => {
+        this.loading = false;
+      });
+    },
+    loadPropertyTemplates() {
+      listPropertyTemplate({ pageNum: 1, pageSize: 100 }).then(response => {
+        this.propertyTemplateList = response.rows || [];
+      });
+    },
+    toggleView() {
+      this.$emit("toggle-view");
+    },
+    handleAddTag() {
+      this.loadPropertyTemplates();
+      this.reset();
+      this.dialogTitle = "添加标签";
+      this.isEdit = false;
+      this.dialogVisible = true;
+    },
+    handleEditTag(tag) {
+      this.loadPropertyTemplates();
+      this.form = {
+        customerId: tag.customerId,
+        propertyId: tag.propertyId,
+        propertyName: tag.propertyName,
+        propertyValue: tag.propertyValue,
+        propertyValueType: tag.propertyValueType,
+        tradeType: tag.tradeType,
+        remark: tag.remark
+      };
+      this.currentValueType = tag.propertyValueType || "text";
+      this.dialogTitle = "编辑标签";
+      this.isEdit = true;
+      this.dialogVisible = true;
+    },
+    handleDeleteTag(tag) {
+      this.$confirm(`确认删除标签"${tag.propertyName}"吗?`, "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        return deleteByPropertyId(this.customerId, tag.propertyId);
+      }).then(() => {
+        this.msgSuccess("删除成功");
+        this.loadTags();
+        this.$emit("tag-change");
+      }).catch(() => {});
+    },
+    handlePropertyChange(propertyId) {
+      const template = this.propertyTemplateList.find(item => item.id === propertyId);
+      if (template) {
+        this.form.propertyName = template.name;
+        this.form.propertyValueType = template.valueType;
+        this.form.tradeType = template.tradeType;
+        this.currentValueType = template.valueType;
+      }
+    },
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.customerId = this.customerId;
+          addOrUpdateByTemplateId(
+            this.customerId,
+            this.form.propertyId,
+            this.form.propertyValue
+          ).then(response => {
+            this.msgSuccess("保存成功");
+            this.dialogVisible = false;
+            this.loadTags();
+            this.$emit("tag-change");
+          });
+        }
+      });
+    },
+    reset() {
+      this.form = {
+        customerId: this.customerId,
+        propertyId: null,
+        propertyName: null,
+        propertyValue: null,
+        propertyValueType: null,
+        tradeType: null,
+        remark: null
+      };
+      this.currentValueType = "text";
+      this.isEdit = false;
+      if (this.$refs.form) {
+        this.$refs.form.clearValidate();
+      }
+    },
+    getValueTypeText(valueType) {
+      const typeMap = {
+        text: "文本",
+        number: "数字",
+        date: "日期",
+        select: "单选",
+        multiSelect: "多选"
+      };
+      return typeMap[valueType] || valueType;
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.ai-tag-container {
+  padding: 16px;
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+
+  .ai-tag-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 16px;
+    padding-bottom: 12px;
+    border-bottom: 1px solid #ebeef5;
+
+    .header-left {
+      display: flex;
+      align-items: center;
+
+      .tag-title {
+        font-size: 16px;
+        font-weight: 600;
+        color: #303133;
+      }
+
+      .tag-subtitle {
+        font-size: 12px;
+        color: #909399;
+        margin-left: 8px;
+      }
+    }
+
+    .header-right {
+      display: flex;
+      align-items: center;
+    }
+  }
+
+  .ai-tag-content {
+    min-height: 200px;
+
+    .empty-tips {
+      text-align: center;
+      color: #909399;
+      padding: 40px 0;
+
+      i {
+        font-size: 40px;
+        display: block;
+        margin-bottom: 8px;
+      }
+    }
+
+    .tag-list {
+      .tag-item {
+        margin-bottom: 16px;
+
+        .tag-name {
+          display: flex;
+          align-items: center;
+          margin-bottom: 8px;
+          font-size: 14px;
+          font-weight: 500;
+          color: #303133;
+
+          i {
+            color: #409eff;
+            margin-right: 6px;
+            font-size: 12px;
+          }
+        }
+
+        .tag-values {
+          display: flex;
+          align-items: center;
+          flex-wrap: wrap;
+
+          .no-value {
+            color: #c0c4cc;
+            font-size: 13px;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 19 - 6
src/views/crm/components/customerDetails.vue

@@ -107,6 +107,14 @@
             </el-descriptions-item>
         </el-descriptions>
 
+        <!-- AI 标签模块 -->
+        <div style="margin-top: 20px;" v-if="item && item.customerId">
+            <ai-tag-panel ref="aiTagPanel" :customer-id="item.customerId" @tag-change="handleTagChange"></ai-tag-panel>
+        </div>
+        <div v-else style="margin-top: 20px; color: #999; text-align: center;">
+            客户信息加载中...
+        </div>
+
         <el-tabs style="margin-top:20px;"  z-index = "99" type="border-card" v-model="activeName" @tab-click="handleClick">
             <el-tab-pane label="联系人" name="contacts">
                 <customer-contacts ref="contacts"></customer-contacts>
@@ -139,10 +147,11 @@
     import customerVoiceLogsList from '../components/customerVoiceLogsList.vue';
     import customerStoreOrderList from '../components/customerStoreOrderList.vue';
     import customerContacts from './customerContacts.vue';
+    import AiTagPanel from './AiTagPanel.vue';
     import { getCustomer } from "@/api/crm/customer";
     export default {
         name: "customer",
-        components: { customerContacts,customerVisitList,customerLogsList,customerVoiceLogsList,customerStoreOrderList,customerSmsLogsList },
+        components: { customerContacts,customerVisitList,customerLogsList,customerVoiceLogsList,customerStoreOrderList,customerSmsLogsList,AiTagPanel },
         data() {
             return {
                 customerExts:[],
@@ -222,12 +231,16 @@
                         });
                     }
                     this.activeName="contacts"
-                    setTimeout(() => {
-                        that.$refs.contacts.getData(this.item.customerId);
-                    }, 500);
+            setTimeout(() => {
+                that.$refs.contacts.getData(this.item.customerId);
+            }, 500);
 
-                });
-            },
+        });
+    },
+    handleTagChange() {
+      // 标签变化时的回调
+      console.log("标签发生变化");
+    }
         }
     };
 </script>

+ 392 - 0
src/views/crm/propertyTemplate/index.vue

@@ -0,0 +1,392 @@
+<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="属性类型" prop="valueType">
+        <el-select v-model="queryParams.valueType" placeholder="请选择属性类型" clearable size="small">
+          <el-option label="文本" value="text" />
+          <el-option label="数字" value="number" />
+          <el-option label="日期" value="date" />
+          <el-option label="单选" value="select" />
+          <el-option label="多选" value="multiSelect" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="行业类型" prop="tradeType">
+        <el-select v-model="queryParams.tradeType" placeholder="请选择行业类型" clearable size="small">
+          <el-option
+            v-for="dict in tradeTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" 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"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['crm:customerPropertyTemplate:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['crm:customerPropertyTemplate:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="templateList" @selection-change="handleSelectionChange" border stripe>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column type="index" label="序号" width="60" align="center" />
+      <el-table-column label="属性名称" align="center" prop="name" min-width="120">
+        <template slot-scope="scope">
+          <span class="property-name">{{ scope.row.name }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="属性类型" align="center" prop="valueType" width="100">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.valueType === 'text'" type="info" size="small">文本</el-tag>
+          <el-tag v-else-if="scope.row.valueType === 'number'" type="warning" size="small">数字</el-tag>
+          <el-tag v-else-if="scope.row.valueType === 'date'" type="success" size="small">日期</el-tag>
+          <el-tag v-else-if="scope.row.valueType === 'select'" type="primary" size="small">单选</el-tag>
+          <el-tag v-else-if="scope.row.valueType === 'multiSelect'" type="danger" size="small">多选</el-tag>
+          <span v-else>{{ scope.row.valueType }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="行业类型" align="center" prop="tradeType" width="120">
+        <template slot-scope="scope">
+          <dict-tag v-if="scope.row.tradeType" :options="tradeTypeOptions" :value="scope.row.tradeType"/>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="AI提取提示" align="left" prop="aiHint" min-width="200" show-overflow-tooltip>
+        <template slot-scope="scope">
+          <span class="ai-hint-text">{{ scope.row.aiHint || '-' }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="意向开关" align="center" prop="intention" width="120">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.intention === 1 || scope.row.intention === '1'" type="success" size="small">开启</el-tag>
+          <el-tag v-else-if="scope.row.intention === 0 || scope.row.intention === '0'" type="info" size="small">关闭</el-tag>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="160">
+        <template slot-scope="scope">
+          <i class="el-icon-time"></i>
+          <span style="margin-left: 5px">{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['crm:customerPropertyTemplate:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            style="color: #f56c6c"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['crm:customerPropertyTemplate: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="700px" append-to-body :close-on-click-modal="false">
+      <el-form ref="form" :model="form" :rules="rules" label-width="110px" class="property-form">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="属性名称" prop="name">
+              <el-input v-model="form.name" placeholder="请输入属性名称" maxlength="50" show-word-limit />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="属性类型" prop="valueType">
+              <el-select v-model="form.valueType" placeholder="请选择属性类型" style="width: 100%">
+                <el-option label="文本" value="text" />
+                <el-option label="数字" value="number" />
+                <el-option label="日期" value="date" />
+                <el-option label="单选" value="select" />
+                <el-option label="多选" value="multiSelect" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="行业类型" prop="tradeType">
+              <el-select v-model="form.tradeType" placeholder="请选择行业类型" style="width: 100%" clearable>
+                <el-option
+                  v-for="dict in tradeTypeOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-divider content-position="left">AI配置</el-divider>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="AI提取提示" prop="aiHint">
+              <el-input 
+                v-model="form.aiHint" 
+                type="textarea" 
+                :rows="4" 
+                placeholder="请输入AI属性提取提示,用于指导AI从对话中提取该属性的值。例如:请从对话中提取患者的年龄信息,注意识别数字和单位" 
+                maxlength="500"
+                show-word-limit
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-divider content-position="left">其他信息</el-divider>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="意向开关" prop="intention">
+              <el-switch v-model="form.intention" active-value="1" inactive-value="0" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="备注" prop="remark">
+              <el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注信息" maxlength="200" show-word-limit />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </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 { listPropertyTemplate, getPropertyTemplate, delPropertyTemplate, addPropertyTemplate, updatePropertyTemplate, exportPropertyTemplate } from "@/api/crm/propertyTemplate";
+
+export default {
+  name: "PropertyTemplate",
+  data() {
+    return {
+      loading: true,
+      ids: [],
+      single: true,
+      multiple: true,
+      showSearch: true,
+      total: 0,
+      templateList: [],
+      title: "",
+      open: false,
+      tradeTypeOptions: [],
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        valueType: null,
+        tradeType: null
+      },
+      form: {},
+      rules: {
+        name: [
+          { required: true, message: "属性名称不能为空", trigger: "blur" }
+        ],
+        valueType: [
+          { required: true, message: "属性类型不能为空", trigger: "change" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("trade_type").then(response => {
+      this.tradeTypeOptions = response.data;
+    });
+  },
+  methods: {
+    getList() {
+      this.loading = true;
+      listPropertyTemplate(this.queryParams).then(response => {
+        this.templateList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    reset() {
+      this.form = {
+        id: null,
+        name: null,
+        valueType: null,
+        aiHint: null,
+        tradeType: null,
+        intention: 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
+      getPropertyTemplate(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) {
+            updatePropertyTemplate(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          } else {
+            addPropertyTemplate(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          }
+        }
+      });
+    },
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除客户属性模板编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delPropertyTemplate(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有客户属性模板数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportPropertyTemplate(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
+    }
+  }
+};
+</script>
+
+<style scoped>
+.app-container {
+  padding: 20px;
+}
+
+.property-form {
+  padding: 10px 20px;
+}
+
+.property-form .el-divider {
+  margin: 15px 0;
+}
+
+.property-form .el-divider__text {
+  font-weight: 500;
+  color: #606266;
+}
+
+.property-form .el-form-item {
+  margin-bottom: 18px;
+}
+
+.property-form .el-textarea ::v-deep .el-textarea__inner {
+  resize: none;
+}
+
+.property-name {
+  font-weight: 500;
+  color: #303133;
+}
+
+.ai-hint-text {
+  color: #606266;
+  font-size: 13px;
+  line-height: 1.5;
+}
+
+.el-table ::v-deep .el-table__row {
+  height: 50px;
+}
+
+.el-table ::v-deep .el-tag {
+  border-radius: 4px;
+}
+</style>

+ 149 - 73
src/views/his/courserCoupon/index.vue

@@ -1,6 +1,12 @@
 <template>
   <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+    <el-form
+      :model="queryParams"
+      ref="queryForm"
+      :inline="true"
+      v-show="showSearch"
+      label-width="68px"
+    >
       <!-- <el-form-item label="有效期" prop="limitTime">
         <el-date-picker clearable size="small"
           v-model="queryParams.limitTime"
@@ -65,8 +71,16 @@
         />
       </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-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>
 
@@ -79,7 +93,8 @@
           size="mini"
           @click="handleAdd"
           v-hasPermi="['his:courserCoupon:add']"
-        >新增</el-button>
+          >新增</el-button
+        >
       </el-col>
       <el-col :span="1.5">
         <el-button
@@ -90,7 +105,8 @@
           :disabled="single"
           @click="handleUpdate"
           v-hasPermi="['his:courserCoupon:edit']"
-        >修改</el-button>
+          >修改</el-button
+        >
       </el-col>
       <el-col :span="1.5">
         <el-button
@@ -101,7 +117,8 @@
           :disabled="multiple"
           @click="handleDelete"
           v-hasPermi="['his:courserCoupon:remove']"
-        >删除</el-button>
+          >删除</el-button
+        >
       </el-col>
       <el-col :span="1.5">
         <el-button
@@ -112,27 +129,51 @@
           :loading="exportLoading"
           @click="handleExport"
           v-hasPermi="['his:courserCoupon:export']"
-        >导出</el-button>
+          >导出</el-button
+        >
       </el-col>
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+      <right-toolbar
+        :showSearch.sync="showSearch"
+        @queryTable="getList"
+      ></right-toolbar>
     </el-row>
 
-    <el-table border v-loading="loading" :data="courserCouponList" @selection-change="handleSelectionChange">
+    <el-table
+      border
+      v-loading="loading"
+      :data="courserCouponList"
+      @selection-change="handleSelectionChange"
+    >
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="标题" align="center" prop="id" />
-      <el-table-column label="有效期" align="center" prop="limitTime" width="180">
+      <el-table-column
+        label="有效期"
+        align="center"
+        prop="limitTime"
+        width="180"
+      >
         <template slot-scope="scope">
-          <span>{{ parseTime(scope.row.limitTime, '{y}-{m}-{d}') }}</span>
+          <span>{{ parseTime(scope.row.limitTime, "{y}-{m}-{d}") }}</span>
         </template>
       </el-table-column>
       <el-table-column label="数量" align="center" prop="number" />
       <el-table-column label="剩余数量" align="center" prop="remainNumber" />
-      <el-table-column label="状态" align="center" prop="status" />
-      <el-table-column label="领取后有效期" align="center" prop="limitDay" />
-      <el-table-column label="有效期类别 1 过期时间 2 领取后有效期" align="center" prop="limitType" />
-      <el-table-column label="每人可领取数量" align="center" prop="limitCount" />
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status" />
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="每人可领取数量"
+        align="center"
+        prop="limitCount"
+      />
       <el-table-column label="标题" align="center" prop="title" />
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+      <el-table-column
+        label="操作"
+        align="center"
+        class-name="small-padding fixed-width"
+      >
         <template slot-scope="scope">
           <el-button
             size="mini"
@@ -140,20 +181,22 @@
             icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
             v-hasPermi="['his:courserCoupon:edit']"
-          >修改</el-button>
+            >修改</el-button
+          >
           <el-button
             size="mini"
             type="text"
             icon="el-icon-delete"
             @click="handleDelete(scope.row)"
             v-hasPermi="['his:courserCoupon:remove']"
-          >删除</el-button>
+            >删除</el-button
+          >
         </template>
       </el-table-column>
     </el-table>
 
     <pagination
-      v-show="total>0"
+      v-show="total > 0"
       :total="total"
       :page.sync="queryParams.pageNum"
       :limit.sync="queryParams.pageSize"
@@ -161,41 +204,42 @@
     />
 
     <!-- 添加或修改课程优惠券对话框 -->
-    <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="有效期" prop="limitTime">
-          <el-date-picker clearable size="small"
+    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <el-form-item label="优惠券名称" prop="title">
+          <el-input v-model="form.title" placeholder="请输入优惠券名称" />
+        </el-form-item>
+        <el-form-item label="过期时间" prop="limitTime">
+          <el-date-picker
+            clearable
+            size="small"
             v-model="form.limitTime"
             type="date"
             value-format="yyyy-MM-dd"
-            placeholder="选择有效期">
+            placeholder="选择过期时间"
+          >
           </el-date-picker>
         </el-form-item>
         <el-form-item label="数量" prop="number">
-          <el-input v-model="form.number" placeholder="请输入数量" />
+          <el-input-number
+            v-model="form.number"
+            :min="0"
+            label="请输入数量"
+          ></el-input-number>
         </el-form-item>
-        <el-form-item label="剩余数量" prop="remainNumber">
-          <el-input v-model="form.remainNumber" placeholder="请输入剩余数量" />
+        <el-form-item label="用户可领取数量" prop="limitCount">
+          <el-input-number
+            v-model="form.limitCount"
+            :min="1"
+            label="请输入用户可领取数量"
+          ></el-input-number>
         </el-form-item>
-        <el-form-item label="状态">
+        <el-form-item label="状态" prop="status">
           <el-radio-group v-model="form.status">
-            <el-radio label="1">请选择字典生成</el-radio>
+            <el-radio :label="1">正常</el-radio>
+            <el-radio :label="0">停用</el-radio>
           </el-radio-group>
         </el-form-item>
-        <el-form-item label="领取后有效期" prop="limitDay">
-          <el-input v-model="form.limitDay" placeholder="请输入领取后有效期" />
-        </el-form-item>
-        <el-form-item label="有效期类别 1 过期时间 2 领取后有效期" prop="limitType">
-          <el-select v-model="form.limitType" placeholder="请选择有效期类别 1 过期时间 2 领取后有效期">
-            <el-option label="请选择字典生成" value="" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="每人可领取数量" prop="limitCount">
-          <el-input v-model="form.limitCount" placeholder="请输入每人可领取数量" />
-        </el-form-item>
-        <el-form-item label="标题" prop="title">
-          <el-input v-model="form.title" placeholder="请输入标题" />
-        </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
@@ -206,7 +250,14 @@
 </template>
 
 <script>
-import { listCourserCoupon, getCourserCoupon, delCourserCoupon, addCourserCoupon, updateCourserCoupon, exportCourserCoupon } from "@/api/his/courserCoupon";
+import {
+  listCourserCoupon,
+  getCourserCoupon,
+  delCourserCoupon,
+  addCourserCoupon,
+  updateCourserCoupon,
+  exportCourserCoupon,
+} from "@/api/his/courserCoupon";
 
 export default {
   name: "CourserCoupon",
@@ -243,23 +294,37 @@ export default {
         limitDay: null,
         limitType: null,
         limitCount: null,
-        title: null
+        title: null,
       },
       // 表单参数
       form: {},
       // 表单校验
       rules: {
-      }
+        title: [{ required: true, message: "标题不能为空", trigger: "blur" }],
+        limitTime: [
+          { required: true, message: "有效期不能为空", trigger: "blur" },
+        ],
+        status: [
+          { required: true, message: "状态不能为空", trigger: "change" },
+        ],
+      },
+      statusOptions: [
+        { dictLabel: "正常", dictValue: 1 },
+        { dictLabel: "停用", dictValue: 0 },
+      ],
     };
   },
   created() {
     this.getList();
+    this.getDicts("sys_company_status").then((response) => {
+      this.statusOptions = response.data;
+    });
   },
   methods: {
     /** 查询课程优惠券列表 */
     getList() {
       this.loading = true;
-      listCourserCoupon(this.queryParams).then(response => {
+      listCourserCoupon(this.queryParams).then((response) => {
         this.courserCouponList = response.rows;
         this.total = response.total;
         this.loading = false;
@@ -278,12 +343,12 @@ export default {
         limitTime: null,
         number: null,
         remainNumber: null,
-        status: 0,
+        status: 1,
         updateTime: null,
-        limitDay: null,
+        limitDay: 1,
         limitType: null,
-        limitCount: null,
-        title: null
+        limitCount: 1,
+        title: null,
       };
       this.resetForm("form");
     },
@@ -299,9 +364,9 @@ export default {
     },
     // 多选框选中数据
     handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.id)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
+      this.ids = selection.map((item) => item.id);
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length;
     },
     /** 新增按钮操作 */
     handleAdd() {
@@ -309,11 +374,12 @@ export default {
       this.open = true;
       this.title = "添加课程优惠券";
     },
+
     /** 修改按钮操作 */
     handleUpdate(row) {
       this.reset();
-      const id = row.id || this.ids
-      getCourserCoupon(id).then(response => {
+      const id = row.id || this.ids;
+      getCourserCoupon(id).then((response) => {
         this.form = response.data;
         this.open = true;
         this.title = "修改课程优惠券";
@@ -321,16 +387,16 @@ export default {
     },
     /** 提交按钮 */
     submitForm() {
-      this.$refs["form"].validate(valid => {
+      this.$refs["form"].validate((valid) => {
         if (valid) {
           if (this.form.id != null) {
-            updateCourserCoupon(this.form).then(response => {
+            updateCourserCoupon(this.form).then((response) => {
               this.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
-            addCourserCoupon(this.form).then(response => {
+            addCourserCoupon(this.form).then((response) => {
               this.msgSuccess("新增成功");
               this.open = false;
               this.getList();
@@ -342,32 +408,42 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const ids = row.id || this.ids;
-      this.$confirm('是否确认删除课程优惠券编号为"' + ids + '"的数据项?', "警告", {
+      this.$confirm(
+        '是否确认删除课程优惠券编号为"' + ids + '"的数据项?',
+        "警告",
+        {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
+          type: "warning",
+        }
+      )
+        .then(function () {
           return delCourserCoupon(ids);
-        }).then(() => {
+        })
+        .then(() => {
           this.getList();
           this.msgSuccess("删除成功");
-        }).catch(() => {});
+        })
+        .catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有课程优惠券数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
+      this.$confirm("是否确认导出所有课程优惠券数据项?", "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
           this.exportLoading = true;
           return exportCourserCoupon(queryParams);
-        }).then(response => {
+        })
+        .then((response) => {
           this.download(response.msg);
           this.exportLoading = false;
-        }).catch(() => {});
-    }
-  }
+        })
+        .catch(() => {});
+    },
+  },
 };
 </script>

+ 4 - 4
src/views/his/userIntegralLogs/index.vue

@@ -10,10 +10,10 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="用户电话" prop="phone">
+      <el-form-item label="用户昵称" prop="nickName">
         <el-input
-          v-model="queryParams.phone"
-          placeholder="请输入用户电话"
+          v-model="queryParams.nickName"
+          placeholder="请输入用户昵称"
           clearable
           size="small"
           @keyup.enter.native="handleQuery"
@@ -77,7 +77,6 @@
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="用户id" align="center" prop="userId" />
       <el-table-column label="用户昵称" align="center" prop="nickName" />
-      <el-table-column label="用户电话" align="center" prop="phone" />
       <el-table-column label="类别" align="center" prop="logType" >
         <template slot-scope="scope">
           <dict-tag :options="intefralLogTypeOptions" :value="scope.row.logType"/>
@@ -162,6 +161,7 @@ export default {
         pageSize: 10,
         userId: null,
         logtype: null,
+        nickName: null,
         integral: null,
         balance: null,
         businessId: null,

+ 455 - 0
src/views/qw/qwPushCount/index.vue

@@ -0,0 +1,455 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="类型" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择推送类型" clearable size="small">
+          <el-option
+            v-for="dict in pushCountTypeList"
+            :key="dict.dictSort"
+            :label="dict.dictLabel"
+            :value="dict.dictSort"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="限定次数" prop="pushCount">
+        <el-input
+          v-model="queryParams.pushCount"
+          placeholder="请输入限定次数"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="推送公司" prop="companyId">
+        <el-select
+          v-model="queryParams.companyId"
+          placeholder="请选择推送公司"
+          clearable
+          filterable
+          size="small"
+          @change="handleQuery"
+        >
+          <!-- 公司选项 -->
+          <el-option
+            v-for="company in companys"
+            :key="company.companyId"
+            :label="company.companyName"
+            :value="company.companyId"
+          />
+        </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="['qw:qwPushCount: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="['qw:qwPushCount:remove']"
+        >删除
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['qw:qwPushCount:export']"
+        >导出
+        </el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="qwPushCountList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center"/>
+      <el-table-column label="类型" align="center" prop="type">
+        <template slot-scope="scope">
+          <dict-tag :options="pushCountTypeList" :value="scope.row.type"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="推送公司" align="center" prop="companyId">
+        <template slot-scope="scope">
+          <span>{{ getCompanyNameById(scope.row.companyId) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="限定次数" align="center" prop="pushCount"/>
+      <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="['qw:qwPushCount:edit']"
+          >修改
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['qw:qwPushCount: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="80px">
+        <el-form-item label="推送类型" prop="type">
+          <el-select v-model="form.type" placeholder="请选择推送类型" clearable size="small">
+            <el-option
+              v-for="dict in pushCountTypeList"
+              :key="dict.dictSort"
+              :label="dict.dictLabel"
+              :value="dict.dictSort"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="限定次数" prop="pushCount">
+          <el-input-number v-model="form.pushCount" placeholder="限定次数"/>
+        </el-form-item>
+
+        <el-form-item label="销售公司" prop="companyId">
+          <el-select v-model="form.companyIdList"
+                     placeholder="请选择推送公司"
+                     multiple
+                     size="small">
+            <!-- 公司选项 -->
+            <el-option
+              v-for="company in companys"
+              :key="company.companyId"
+              :label="company.companyName"
+              :value="company.companyId"
+            />
+          </el-select>
+        </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="title" :visible.sync="openSingle" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="推送类型" prop="type">
+          <el-select
+            v-model="form.type"
+            placeholder="请选择推送类型"
+            clearable
+            size="small"
+            value-key="dictValue"
+          >
+            <el-option
+              v-for="dict in pushCountTypeList"
+              :key="dict.dictSort"
+              :label="dict.dictLabel"
+              :value="dict.dictSort"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="限定次数" prop="pushCount">
+          <el-input v-model="form.pushCount" placeholder="限定次数"/>
+        </el-form-item>
+
+        <el-form-item label="推送公司" prop="companyId">
+          <el-select
+            v-model="form.companyId"
+            placeholder="请选择推送公司"
+            clearable
+            filterable
+            collapse-tags
+            size="small">
+            <!-- 公司选项 -->
+            <el-option
+              v-for="company in companys"
+              :key="company.companyId"
+              :label="company.companyName"
+              :value="company.companyId"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitFormSingle">确 定</el-button>
+        <el-button @click="updateCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import {
+  listQwPushCount,
+  getQwPushCount,
+  delQwPushCount,
+  addQwPushCount,
+  updateQwPushCount,
+  exportQwPushCount
+} from "@/api/qw/qwPushCount";
+import {getCompanyList} from "@/api/company/company";
+
+export default {
+  name: "QwPushCount",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 定义销售推送不同类型的企业消息的次数表格数据
+      qwPushCountList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      openSingle: false,
+      pushCountTypeList: [],
+      pushCountStatusList: [],
+      companys: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        type: null,
+        pushCount: null,
+        companyId: null,
+        status: null
+      },
+      // 表单参数
+      form: {
+        companyIdList: []
+      },
+      // 表单校验
+      rules: {
+        type: [
+          {required: true, message: '推送类型不能为空', trigger: 'change'}
+        ],
+        pushCount: [
+          {required: true, message: '限定次数不能为空', trigger: 'blur'},
+          {
+            validator: (rule, value, callback) => {
+              if (value === '') {
+                callback(new Error('限定次数不能为空'));
+              } else if (isNaN(Number(value))) {
+                callback(new Error('请输入有效的数字'));
+              } else if (Number(value) < 0) {
+                callback(new Error('次数不能为负数'));
+              } else if (!Number.isInteger(Number(value))) {
+                callback(new Error('请输入整数'));
+              } else {
+                callback();
+              }
+            },
+            trigger: 'blur'
+          }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_qwSopAi_contentType").then(response => {
+      this.pushCountTypeList = response.data;
+    });
+
+    this.getDicts("sys_company_status").then(response => {
+      this.pushCountStatusList = response.data;
+    });
+
+    getCompanyList().then(response => {
+      this.companys = response.data;
+    });
+  },
+  methods: {
+    // 公司选择变化事件
+    handleCompanyChange(selectedCompanyIds) {
+    },
+    getCompanyNameById(companyId) {
+      if (!companyId) return '-';
+      const company = this.companys.find(item => item.companyId === companyId);
+      return company ? company.companyName : '未知公司';
+    },
+    /** 查询定义销售推送不同类型的企业消息的次数列表 */
+    getList() {
+      this.loading = true;
+      listQwPushCount(this.queryParams).then(response => {
+        this.qwPushCountList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    //修改取消
+    updateCancel() {
+      this.openSingle = false;
+      this.reset();
+    },
+
+
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        type: null,
+        pushCount: null,
+        companyId: null,
+        status: 0,
+      };
+      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
+      getQwPushCount(id).then(response => {
+        this.form = response.data;
+        this.openSingle = true;
+        this.title = "修改企微推送信息次数";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateQwPushCount(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addQwPushCount(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            }).catch(error => {
+              this.msgError("新增部分限定类型已存在:失败条数"+error.data().size());
+            });
+          }
+        }
+      });
+    },
+
+    /** 修改时不能批量选择公司名 */
+    submitFormSingle() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateQwPushCount(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.openSingle = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除定义销售推送不同类型的企业消息的次数编号为"' + ids + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return delQwPushCount(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {
+      });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有定义销售推送不同类型的企业消息的次数数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportQwPushCount(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {
+      });
+    }
+  }
+};
+</script>