浏览代码

feat:新增质检管理(质检中心,已质检列表,质检项管理,质检模板,质检词库);
feat:质检项管理,质检模板,质检词库对接完成;

zhangchong 1 年之前
父节点
当前提交
8bb6fea4a2

+ 29 - 0
src/api/quality/index.ts

@@ -0,0 +1,29 @@
+/*
+ * @Author: zc
+ * @description 质检管理-质检中心
+ * @version:
+ * @Date: 2022-08-09 16:19:55
+ * @LastEditors: Please set LastEditors
+ * @LastEditTime: 2022-11-16 14:49:01
+ */
+import request from '/@/utils/request';
+/**
+ * @description 质检中心基础信息
+ */
+export const qualityBaseData = () => {
+    return request({
+        url: `/api/v1/Quality/base`,
+        method: 'get'
+    });
+};
+/**
+ * @description 质检中心基础信息
+ * @param {object}  params
+ */
+export const qualityList = (params: object) => {
+    return request({
+        url: `/api/v1/Quality/list`,
+        method: 'get',
+        params
+    });
+};

+ 72 - 0
src/api/quality/lexicon.ts

@@ -0,0 +1,72 @@
+/*
+ * @Author: zc
+ * @description 质检管理-词库管理
+ * @version:
+ * @Date: 2022-08-09 16:19:55
+ * @LastEditors: Please set LastEditors
+ * @LastEditTime: 2022-11-16 14:49:01
+ */
+import request from '/@/utils/request';
+/**
+ * @description 违禁词基础信息
+ */
+export const lexiconBaseData = () => {
+    return request({
+        url: `/api/v1/Quality/prohibited_base`,
+        method: 'get'
+    });
+};
+/**
+ * @description 违禁词列表
+ * @param {object}  params
+ */
+export const lexiconList = (params: object) => {
+    return request({
+        url: `/api/v1/Quality/prohibited/list`,
+        method: 'get',
+        params,
+    });
+};
+/**
+ * @description 违禁词实体
+ * @param {string} id
+ */
+export const lexiconDetail = (id: string) => {
+    return request({
+        url: `/api/v1/Quality/prohibited/${id}`,
+        method: 'get'
+    });
+};
+/**
+ * @description 新增违禁词
+ * @param {object} data
+ */
+export const lexiconAdd = (data: object) => {
+    return request({
+        url: `/api/v1/Quality/prohibited`,
+        method: 'post',
+        data
+    });
+};
+/**
+ * @description 修改违禁词
+ * @param {object} data
+ */
+export const lexiconUpdate = (data: object) => {
+    return request({
+        url: `/api/v1/Quality/prohibited`,
+        method: 'put',
+        data
+    });
+};
+/**
+ * @description 新增违禁词
+ * @param {object} data
+ */
+export const lexiconDelete = (data: object) => {
+    return request({
+        url: `/api/v1/Quality/prohibitedBatch`,
+        method: 'delete',
+        data
+    });
+};

+ 72 - 0
src/api/quality/project.ts

@@ -0,0 +1,72 @@
+/*
+ * @Author: zc
+ * @description 质检管理-项目管理
+ * @version:
+ * @Date: 2022-08-09 16:19:55
+ * @LastEditors: Please set LastEditors
+ * @LastEditTime: 2022-11-16 14:49:01
+ */
+import request from '/@/utils/request';
+/**
+ * @description 项目管理基础信息
+ */
+export const projectBaseData = () => {
+    return request({
+        url: `/api/v1/Quality/item_base`,
+        method: 'get'
+    });
+};
+/**
+ * @description 项目管理列表
+ * @param {object}  params
+ */
+export const projectList = (params: object) => {
+    return request({
+        url: `/api/v1/Quality/item/list`,
+        method: 'get',
+        params,
+    });
+};
+/**
+ * @description 项目管理实体
+ * @param {string} id
+ */
+export const projectDetail = (id: string) => {
+    return request({
+        url: `/api/v1/Quality/item/${id}`,
+        method: 'get'
+    });
+};
+/**
+ * @description 项目管理新增
+ * @param {object} data
+ */
+export const projectAdd = (data: object) => {
+    return request({
+        url: `/api/v1/Quality/item`,
+        method: 'post',
+        data
+    });
+};
+/**
+ * @description 项目管理修改
+ * @param {object} data
+ */
+export const projectUpdate = (data: object) => {
+    return request({
+        url: `/api/v1/Quality/item`,
+        method: 'put',
+        data
+    });
+};
+/**
+ * @description 项目管理删除
+ * @param {object} data
+ */
+export const projectDelete = (data: object) => {
+    return request({
+        url: `/api/v1/Quality/itemBatch`,
+        method: 'delete',
+        data
+    });
+};

+ 72 - 0
src/api/quality/template.ts

@@ -0,0 +1,72 @@
+/*
+ * @Author: zc
+ * @description 质检管理-模板管理
+ * @version:
+ * @Date: 2022-08-09 16:19:55
+ * @LastEditors: Please set LastEditors
+ * @LastEditTime: 2022-11-16 14:49:01
+ */
+import request from '/@/utils/request';
+/**
+ * @description 模板基础信息
+ */
+export const templateBaseData = () => {
+    return request({
+        url: `/api/v1/Quality/template_base`,
+        method: 'get'
+    });
+};
+/**
+ * @description 模板列表
+ * @param {object}  params
+ */
+export const templateList = (params: object) => {
+    return request({
+        url: `/api/v1/Quality/template/list`,
+        method: 'get',
+        params,
+    });
+};
+/**
+ * @description 模板实体
+ * @param {string} id
+ */
+export const templateDetail = (id: string) => {
+    return request({
+        url: `/api/v1/Quality/template/${id}`,
+        method: 'get'
+    });
+};
+/**
+ * @description 新增模板
+ * @param {object} data
+ */
+export const templateAdd = (data: object) => {
+    return request({
+        url: `/api/v1/Quality/template`,
+        method: 'post',
+        data
+    });
+};
+/**
+ * @description 修改模板
+ * @param {object} data
+ */
+export const templateUpdate = (data: object) => {
+    return request({
+        url: `/api/v1/Quality/template`,
+        method: 'put',
+        data
+    });
+};
+/**
+ * @description 删除模板
+ * @param {object} data
+ */
+export const templateDelete = (data: object) => {
+    return request({
+        url: `/api/v1/Quality/templateBatch`,
+        method: 'delete',
+        data
+    });
+};

+ 5 - 3
src/components/ProcessApproval/index.vue

@@ -440,7 +440,7 @@
 					</el-col>
 					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
 						<el-form-item label="附件" prop="additions" :rules="[{ required: false, message: '请填写诉求内容', trigger: 'change' }]">
-							<annex-list name="办理附件" ref="annexListRef" :businessId="state.orderDetail.id" classify="办理上传" />
+							<annex-list :name="state.annexName" ref="annexListRef" :businessId="state.orderDetail.id" :classify="state.classify" />
 						</el-form-item>
 					</el-col>
 				</el-row>
@@ -555,7 +555,7 @@ const ruleFormRef = ref<RefType>(); //表单组件
 const storesUserInfo = useUserInfo();
 const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
 const showStepsArr = ['延期申请', '甄别申请', '工单重办','新增通知','新增公告']; // 显示步骤条的流程
-const handelArr = ['工单办理']; // 处于办理状态的流程 (如果是汇总节点 需要填写处理人等  办理流程才有期满时间)
+const handelArr = ['工单办理','甄别审批']; // 处于办理状态的流程 (如果是汇总节点 需要填写处理人等  办理流程才有期满时间)
 const returnArr = ['工单退回']; // 退回流程 (退回流程不需要展示其他 只需要填写意见和附件即可)
 const formComponents = ref<EmptyArrayType>([]); // 表单组件
 const communicationModeOptions = ref<EmptyArrayType>([]); // 沟通方式
@@ -593,9 +593,10 @@ const openDialog = async (val: any) => {
 	state.ruleForm.workflowId = state.workflowId = id ?? ''; // 流程id
 	state.processType = processType ?? '办理流程'; // 业务类型
 	state.orderDetail = orderDetail ?? {}; // 工单详情
-	const { dialogTitle, inputPlaceholder, annexName } = extra ?? {};
+	const { dialogTitle, inputPlaceholder, annexName,classify } = extra ?? {};
 	state.dialogTitle = dialogTitle ?? '提交流程'; // 流程标题
 	state.annexName = annexName ?? '办理附件'; // 附件标题
+  state.classify = classify ?? '办理上传'; // 附件分类
 	state.inputPlaceholder = inputPlaceholder ?? '办理意见'; // 意见提示
 	let res: any = {};
 	switch (state.processType) {
@@ -754,6 +755,7 @@ const restForm = (formEl: FormInstance | undefined) => {
 	delayFormRef.value?.resetFields();
 	discernFormRef.value?.clearValidate();
 	discernFormRef.value?.resetFields();
+  state.delayForm.endTime = '';
 	formEl.resetFields();
 	formEl.clearValidate();
 };

+ 2 - 1
src/views/business/discern/backlog/index.vue

@@ -212,8 +212,9 @@ const approve = async (row: any) => {
       orderDetail: row.order,
       extra: {
         dialogTitle: '甄别审批',
-        inputPlaceholder: '办理意见',
+        inputPlaceholder: '审批意见',
         annexName: '甄别附件',
+        classify:'甄别上传'
       },
     };
     processApprovalRef.value.openDialog(params);

+ 8 - 5
src/views/business/discern/index.vue

@@ -16,13 +16,13 @@
 							<el-input v-model="state.queryParams.Keyword" placeholder="工单编码/标题" clearable @keyup.enter="queryList" />
 						</el-form-item>
 					</el-col>
-					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
+<!--					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
 						<el-form-item label="甄别类型" prop="AcceptType">
 							<el-select v-model="state.queryParams.AcceptType" placeholder="请选择甄别类型" class="w100">
 								<el-option v-for="item in state.screenType" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
 							</el-select>
 						</el-form-item>
-					</el-col>
+					</el-col>-->
 					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
 						<el-form-item label="甄别时间" prop="exTime">
 							<el-date-picker
@@ -106,7 +106,7 @@
 				<el-table-column prop="visit.employee" label="回访人" show-overflow-tooltip></el-table-column>
 				<el-table-column label="被回访部门" show-overflow-tooltip width="150">
 					<template #default="{ row }">
-						<span v-if="row.visit.visitTarget === 20">{{ row.visit.visitOrgName }}</span>
+						<span >{{ row.visitDetail.visitOrgName }}</span>
 					</template>
 				</el-table-column>
 				<el-table-column prop="creationTime" label="甄别申请时间" show-overflow-tooltip width="170">
@@ -247,8 +247,9 @@ const onDetail = async (row: any) => {
           orderDetail,
           extra: {
             dialogTitle: '甄别审批',
-            inputPlaceholder: '办理意见',
+            inputPlaceholder: '审批意见',
             annexName:'甄别附件',
+            classify:'甄别上传'
           },
         };
         processApprovalRef.value.openDialog(params);
@@ -261,8 +262,9 @@ const onDetail = async (row: any) => {
           orderDetail,
           extra: {
             dialogTitle: '甄别审批',
-            inputPlaceholder: '办理意见',
+            inputPlaceholder: '审批意见',
             annexName:'甄别附件',
+            classify:'甄别上传'
           },
         };
         processApprovalRef.value.openDialog(params);
@@ -280,6 +282,7 @@ const onDetail = async (row: any) => {
             dialogTitle: '甄别申请',
             inputPlaceholder: '请输入甄别意见',
             annexName:'甄别附件',
+            classify:'甄别上传'
           },
         };
         processApprovalRef.value.openDialog(params);

+ 1 - 1
src/views/business/followUp/index.vue

@@ -11,7 +11,7 @@
 					</el-col>
           <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
             <el-form-item label="回访状态" prop="VisitState">
-              <el-select v-model="state.queryParams.VisitState" placeholder="请选择回访状态" clearable class="w100">
+              <el-select v-model="state.queryParams.VisitState" placeholder="请选择回访状态" class="w100">
                 <el-option v-for="item in state.visitStateOptions" :value="item.value" :key="item.value" :label="item.label" />
               </el-select>
             </el-form-item>

+ 188 - 0
src/views/quality/done/index.vue

@@ -0,0 +1,188 @@
+<template>
+  <div class="quality-lexicon-container layout-pd">
+    <el-card shadow="never">
+      <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
+        <el-tab-pane label="User" name="first">User</el-tab-pane>
+        <el-tab-pane label="Config" name="second">Config</el-tab-pane>
+        <el-tab-pane label="Role" name="third">Role</el-tab-pane>
+        <el-tab-pane label="Task" name="fourth">Task</el-tab-pane>
+      </el-tabs>
+
+      <el-form :model="state.queryParams" ref="ruleFormRef" :inline="true" @submit.native.prevent>
+        <el-form-item label="违禁词分类" prop="Classify">
+          <el-select v-model="state.queryParams.Classify" placeholder="请选择违禁词分类">
+            <el-option v-for="item in prohibitedClassify" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="违禁词属性" prop="Type">
+          <el-select v-model="state.queryParams.Type" placeholder="请选择违禁词属性">
+            <el-option v-for="item in prohibitedType" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="违禁词" prop="Name">
+          <el-input v-model="state.queryParams.Name" placeholder="请输入违禁词" clearable @keyup.enter="queryList" style="width: 250px" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="queryList" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+          <el-button @click="resetQuery(ruleFormRef)" v-waves class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+    <el-card shadow="never">
+      <div class="mb20">
+        <el-button type="primary" @click="onLexiconAdd" v-waves v-auth="'quality:lexicon:add'">
+          <SvgIcon name="ele-Plus" class="mr5" />新增
+        </el-button>
+        <el-button type="primary" @click="onLexiconDelete" v-waves v-auth="'quality:lexicon:delete'" :disabled="!multipleSelection.length">
+          <SvgIcon name="ele-Delete" class="mr5" />删除
+        </el-button>
+      </div>
+      <!-- 表格 -->
+      <el-table :data="state.tableData" v-loading="state.loading" row-key="id" ref="multipleTableRef" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="name" label="违禁词" show-overflow-tooltip width="400"></el-table-column>
+        <el-table-column prop="classify" label="违禁词分类" show-overflow-tooltip width="130"></el-table-column>
+        <el-table-column prop="type" label="违禁词属性" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="creatorName" label="创建人" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="creationTime" label="创建时间" show-overflow-tooltip width="170">
+          <template #default="{ row }">
+            <span>{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="lastModificationName" label="更新人" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="lastModificationTime" label="更新时间" show-overflow-tooltip width="170">
+          <template #default="{ row }">
+            <span>{{ formatDate(row.lastModificationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="120" fixed="right" align="center">
+          <template #default="{ row }">
+            <el-button link type="primary" @click="onLexiconEdit(row)" v-auth="'quality:lexicon:edit'" title="修改违禁词"> 修改 </el-button>
+          </template>
+        </el-table-column>
+        <template #empty>
+          <Empty />
+        </template>
+      </el-table>
+      <!-- 分页 -->
+      <pagination
+          :total="state.total"
+          v-model:page="state.queryParams.PageIndex"
+          v-model:limit="state.queryParams.PageSize"
+          @pagination="queryList"
+      />
+    </el-card>
+    <!--  违禁词新增  -->
+    <lexicon-add ref="lexiconAddRef" @updateList="queryList" :prohibitedClassify="prohibitedClassify" :prohibitedType="prohibitedType"/>
+    <!--  违禁词编辑  -->
+    <lexicon-edit ref="lexiconEditRef" @updateList="queryList" :prohibitedClassify="prohibitedClassify" :prohibitedType="prohibitedType"/>
+  </div>
+</template>
+
+<script lang="ts" setup name="quality">
+import { reactive, ref, onMounted, defineAsyncComponent } from 'vue';
+import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+import { formatDate } from '/@/utils/formatTime';
+import {auth} from "/@/utils/authFunction";
+import {lexiconList,lexiconDelete,lexiconBaseData} from '/@/api/quality/lexicon';
+
+// 引入组件
+const LexiconAdd = defineAsyncComponent(() => import('/@/views/quality/lexicon/components/Lexicon-add.vue')); // 违禁词新增
+const LexiconEdit = defineAsyncComponent(() => import('/@/views/quality/lexicon/components/Lexicon-edit.vue')); // 违禁词编辑
+
+// 定义变量内容
+const state = reactive<any>({
+  loading: false, // 加载状态
+  queryParams: {
+    // 查询参数
+    PageIndex: 1,
+    PageSize: 10,
+    Classify: null,
+    Type: null,
+    Name:''
+  },
+  total: 0, // 总条数
+  tableData: [], // 表格数据
+});
+const ruleFormRef = ref<RefType>(null); // 表单ref
+const prohibitedClassify = ref<EmptyArrayType>([]); // 违禁词分类
+const prohibitedType = ref<EmptyArrayType>([]); // 违禁词属性
+const getBaseData = async ()=>{
+  try {
+    const res = await lexiconBaseData();
+    prohibitedClassify.value = res.result?.prohibitedClassify ?? [];
+    prohibitedType.value = res.result?.prohibitedType ?? [];
+  } catch (error) {
+    console.log(error);
+  }
+}
+// 获取参数列表
+const queryList = () => {
+  state.loading = true;
+  if (!auth('quality:query')) ElMessage.error('抱歉,您没有权限获取质检词库列表!');
+  else {
+    lexiconList(state.queryParams)
+        .then((res) => {
+          state.loading = false;
+          state.tableData = res.result.items ?? [];
+          state.total = res.result.total ?? 0;
+        })
+        .finally(() => {
+          state.loading = false;
+        });
+  }
+};
+// 重置表单
+const resetQuery = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  queryList();
+};
+// 新增意见
+const lexiconAddRef = ref<RefType>(); // 意见新增
+const onLexiconAdd = () => {
+  lexiconAddRef.value.openDialog();
+};
+// 修改意见
+const lexiconEditRef = ref<RefType>(); // 修改意见
+const onLexiconEdit = (row: any) => {
+  lexiconEditRef.value.openDialog(row);
+};
+// 表格多选
+const multipleTableRef = ref<RefType>();
+const multipleSelection = ref<any>([]);
+const handleSelectionChange = (val: any[]) => {
+  multipleSelection.value = val;
+};
+// 删除参数
+const onLexiconDelete = () => {
+  const names = multipleSelection.value.map((item: any) => item.name).join('、');
+  const ids = multipleSelection.value.map((item: any) => item.id);
+  ElMessageBox.confirm(`您确定要删除:【${names}】违禁词,是否继续?`, '提示', {
+    confirmButtonText: '确认',
+    cancelButtonText: '取消',
+    type: 'warning',
+    draggable: true,
+    cancelButtonClass: 'default-button',
+    autofocus: false,
+  })
+      .then(() => {
+        lexiconDelete({ids}).then(() => {
+          ElMessage.success('操作成功');
+          queryList();
+        });
+      })
+      .catch(() => {});
+};
+// 页面加载时
+onMounted(() => {
+  getBaseData();
+  queryList();
+});
+</script>
+
+<style lang="scss" scoped>
+.quality-lexicon-container {
+
+}
+</style>

+ 267 - 0
src/views/quality/index/index.vue

@@ -0,0 +1,267 @@
+<template>
+  <div class="quality-container layout-pd">
+    <el-card shadow="never">
+      <el-tabs v-model="state.queryParams.Source" class="demo-tabs" @tab-change="queryList">
+        <el-tab-pane :label="item.value" :name="item.key" v-for="item in qualitySourceOptions" :key="item.key"></el-tab-pane>
+      </el-tabs>
+      <el-form :model="state.queryParams" ref="ruleFormRef" :inline="true" @submit.native.prevent>
+        <el-form-item label="质检状态" prop="State">
+          <el-select v-model="state.queryParams.State" placeholder="请选择质检状态">
+            <el-option v-for="item in qualityStateOptions" :value="item.key" :key="item.key" :label="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="关键词" prop="Keyword">
+          <el-input v-model="state.queryParams.Keyword" placeholder="关键词" clearable @keyup.enter="queryList" />
+        </el-form-item>
+        <el-form-item label="创建时间" prop="exTime">
+          <el-date-picker
+              v-model="state.queryParams.exTime"
+              type="datetimerange"
+              unlink-panels
+              range-separator="至"
+              start-placeholder="开始时间"
+              end-placeholder="结束时间"
+              :shortcuts="shortcuts"
+              @change="timeStartChangeCr"
+              value-format="YYYY-MM-DD[T]HH:mm:ss"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="queryList" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+          <el-button @click="resetQuery(ruleFormRef)" v-waves class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+        </el-form-item>
+      </el-form>
+
+      <!-- 表格 -->
+      <el-table :data="state.tableData" v-loading="state.loading" row-key="id" ref="multipleTableRef" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" />
+        <template v-if="state.queryParams.Source === 0">
+          <el-table-column prop="name" label="工单编码" show-overflow-tooltip width="150"></el-table-column>
+          <el-table-column prop="name" label="质检方式" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="name" label="来源方式" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="creationTime" label="受理时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="name" label="受理类型" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="name" label="工单状态" show-overflow-tooltip></el-table-column>
+          <el-table-column label="工单标题" show-overflow-tooltip width="300">
+            <template #default="{ row }">
+              <span class="color-primary">{{ row.title }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="name" label="热点分类" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="employeeName" label="受理人" show-overflow-tooltip width="120">
+            <template #default="{ row }">
+              <span>{{ row.acceptorName}} <span v-if="row.acceptorStaffNo">[{{row.acceptorStaffNo}}]</span> </span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="name" label="来电电话" show-overflow-tooltip></el-table-column>
+        </template>
+        <template v-if="state.queryParams.Source === 1">
+          <el-table-column prop="name" label="工单编码" show-overflow-tooltip width="150"></el-table-column>
+          <el-table-column prop="name" label="质检方式" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="name" label="来源方式" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="creationTime" label="受理时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="name" label="受理类型" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="name" label="工单状态" show-overflow-tooltip></el-table-column>
+          <el-table-column label="工单标题" show-overflow-tooltip width="300">
+            <template #default="{ row }">
+              <span class="color-primary">{{ row.title }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="name" label="热点分类" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="employeeName" label="受理人" show-overflow-tooltip width="120">
+            <template #default="{ row }">
+              <span>{{ row.acceptorName}} <span v-if="row.acceptorStaffNo">[{{row.acceptorStaffNo}}]</span> </span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="creationTime" label="交办时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="name" label="来电电话" show-overflow-tooltip></el-table-column>
+        </template>
+        <template v-if="state.queryParams.Source === 2">
+          <el-table-column prop="name" label="工单编码" show-overflow-tooltip width="150"></el-table-column>
+          <el-table-column prop="name" label="质检方式" show-overflow-tooltip></el-table-column>
+          <el-table-column label="工单标题" show-overflow-tooltip width="300">
+            <template #default="{ row }">
+              <span class="color-primary">{{ row.title }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="name" label="来源方式" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="name" label="回访状态" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="name" label="回访方式" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="name" label="受理类型" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="name" label="热点分类" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="employeeName" label="受理人" show-overflow-tooltip width="120">
+            <template #default="{ row }">
+              <span>{{ row.acceptorName}} <span v-if="row.acceptorStaffNo">[{{row.acceptorStaffNo}}]</span> </span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="actualHandleOrgName" label="接办部门" show-overflow-tooltip width="170"></el-table-column>
+          <el-table-column prop="startTime" label="受理时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.startTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="startTime" label="办结时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.startTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="startTime" label="发布时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.startTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="startTime" label="回访任务创建时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.startTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="actualHandleOrgName" label="回访人" show-overflow-tooltip width="170"></el-table-column>
+          <el-table-column prop="startTime" label="回访时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.startTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="actualHandleOrgName" label="中心会签" show-overflow-tooltip></el-table-column>
+        </template>
+        <el-table-column label="操作" width="120" fixed="right" align="center">
+          <template #default="{ row }">
+            <el-button link type="primary" @click="onLexiconEdit(row)" v-auth="'quality:lexicon:edit'" title="修改违禁词"> 修改 </el-button>
+          </template>
+        </el-table-column>
+        <template #empty>
+          <Empty />
+        </template>
+      </el-table>
+      <!-- 分页 -->
+      <pagination
+          :total="state.total"
+          v-model:page="state.queryParams.PageIndex"
+          v-model:limit="state.queryParams.PageSize"
+          @pagination="queryList"
+      />
+    </el-card>
+    <!--  违禁词新增  -->
+    <lexicon-add ref="lexiconAddRef" @updateList="queryList" />
+    <!--  违禁词编辑  -->
+    <lexicon-edit ref="lexiconEditRef" @updateList="queryList"/>
+  </div>
+</template>
+
+<script lang="ts" setup name="quality">
+import { reactive, ref, onMounted, defineAsyncComponent } from 'vue';
+import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+import { formatDate } from '/@/utils/formatTime';
+import {auth} from "/@/utils/authFunction";
+import {qualityBaseData,qualityList} from '/@/api/quality'
+import {shortcuts} from "/@/utils/constants";
+
+// 引入组件
+const LexiconAdd = defineAsyncComponent(() => import('/@/views/quality/lexicon/components/Lexicon-add.vue')); // 违禁词新增
+const LexiconEdit = defineAsyncComponent(() => import('/@/views/quality/lexicon/components/Lexicon-edit.vue')); // 违禁词编辑
+
+// 定义变量内容
+const state = reactive<any>({
+  loading: false, // 加载状态
+  queryParams: {
+    // 查询参数
+    PageIndex: 1,
+    PageSize: 10,
+    Source: 0,
+    CreationTimeStart: '', // 创建时间 开始
+    CreationTimeEnd: '', // 创建时间 结束
+    exTime: [], // 办理期限
+    State: null,
+    Keyword:''
+  },
+  total: 0, // 总条数
+  tableData: [], // 表格数据
+});
+const ruleFormRef = ref<RefType>(null); // 表单ref
+const qualitySourceOptions = ref<EmptyArrayType>([]); // 违禁词分类
+const qualityStateOptions = ref<EmptyArrayType>([]); // 违禁词属性
+const getBaseData = async ()=>{
+  try {
+    const res = await qualityBaseData();
+    qualitySourceOptions.value = res.result?.qualitySource ?? [];
+    qualityStateOptions.value = res.result?.qualityState ?? [];
+  } catch (error) {
+    console.log(error);
+  }
+}
+const handleTimeChange = (val: string[], startKey: string, endKey: string) => {
+  if (val) {
+    state.queryParams[startKey] = val[0];
+    state.queryParams[endKey] = val[1];
+  } else {
+    state.queryParams[startKey] = '';
+    state.queryParams[endKey] = '';
+  }
+};
+// 甄别时间
+const timeStartChangeCr = (val: string[]) => {
+  handleTimeChange(val, 'CreationTimeStart', 'CreationTimeEnd');
+};
+// 获取参数列表
+const queryList = () => {
+  state.loading = true;
+  if (!auth('quality:query')) ElMessage.error('抱歉,您没有权限获取质检词库列表!');
+  else {
+    qualityList(state.queryParams)
+        .then((res) => {
+          state.loading = false;
+          state.tableData = res.result.items ?? [];
+          state.total = res.result.total ?? 0;
+        })
+        .finally(() => {
+          state.loading = false;
+        });
+  }
+};
+// 重置表单
+const resetQuery = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  state.queryParams.CreationTimeStart = '';
+  state.queryParams.CreationTimeEnd = '';
+  queryList();
+};
+// 新增意见
+const lexiconAddRef = ref<RefType>(); // 意见新增
+const onLexiconAdd = () => {
+  lexiconAddRef.value.openDialog();
+};
+// 修改意见
+const lexiconEditRef = ref<RefType>(); // 修改意见
+const onLexiconEdit = (row: any) => {
+  lexiconEditRef.value.openDialog(row);
+};
+// 表格多选
+const multipleTableRef = ref<RefType>();
+const multipleSelection = ref<any>([]);
+const handleSelectionChange = (val: any[]) => {
+  multipleSelection.value = val;
+};
+// 页面加载时
+onMounted(() => {
+  getBaseData();
+  queryList();
+});
+</script>
+
+<style lang="scss" scoped>
+.quality-container {
+
+}
+</style>

+ 151 - 0
src/views/quality/lexicon/components/Lexicon-add.vue

@@ -0,0 +1,151 @@
+<template>
+	<el-dialog title="新增违禁词" v-model="state.dialogVisible" width="769px" draggable @close="close">
+		<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="100px">
+			<el-row :gutter="10">
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="违禁词" prop="name" :rules="[{ required: true, message: '请输入违禁词', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.name" placeholder="请输入违禁词" clearable></el-input>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="违禁词分类" prop="classify" :rules="[{ required: true, message: '请选择违禁词分类', trigger: 'change' }]">
+						<el-select v-model="state.ruleForm.classify" placeholder="请选择违禁词分类" class="w100">
+							<el-option v-for="item in props.prohibitedClassify" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="违禁词属性" prop="type" :rules="[{ required: true, message: '请选择违禁词属性', trigger: 'change' }]">
+						<el-select v-model="state.ruleForm.type" placeholder="请选择违禁词属性" class="w100">
+							<el-option v-for="item in props.prohibitedType" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="违禁同义词" prop="synonym" :rules="[{ required: false, message: '请选择违禁同义词', trigger: 'change' }]">
+						<el-tag v-for="tag in dynamicTags" :key="tag" class="mr10" closable :disable-transitions="false" @close="handleClose(tag)">
+							{{ tag }}
+						</el-tag>
+						<el-input
+							v-if="inputVisible"
+							ref="InputRef"
+							v-model="inputValue"
+							size="small"
+							@keyup.enter="handleInputConfirm"
+							@blur="handleInputConfirm"
+							style="max-width: 200px"
+						/>
+						<el-button v-else size="small" @click="showInput"> 添加同义词 </el-button>
+					</el-form-item>
+				</el-col>
+			</el-row>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="onCancel" class="default-button">取 消</el-button>
+				<el-button type="primary" @click="onSubmit(ruleFormRef)" v-waves="'light'" :loading="state.loading">确 定 </el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script setup lang="ts" name="qualityLexiconAdd">
+import { nextTick, reactive, ref } from 'vue';
+import { ElInput, ElMessage, FormInstance } from 'element-plus';
+import { lexiconAdd } from '/@/api/quality/lexicon';
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+const props = defineProps({
+	prohibitedClassify: {
+		type: Array,
+		default: () => [],
+	},
+	prohibitedType: {
+		type: Array,
+		default: () => [],
+	},
+});
+
+const inputValue = ref('');
+const dynamicTags = ref<EmptyArrayType>([]);
+const inputVisible = ref(false);
+const InputRef = ref<InstanceType<typeof ElInput>>();
+// 删除同义词
+const handleClose = (tag: string) => {
+	dynamicTags.value.splice(dynamicTags.value.indexOf(tag), 1);
+};
+// 展示输入框
+const showInput = () => {
+	inputVisible.value = true;
+	nextTick(() => {
+		InputRef.value!.input!.focus();
+	});
+};
+// 确定添加
+const handleInputConfirm = () => {
+	if (inputValue.value) {
+		dynamicTags.value.push(inputValue.value);
+	}
+	inputVisible.value = false;
+	inputValue.value = '';
+};
+
+// 定义变量内容
+const ruleFormRef = ref<FormInstance>();
+const state = reactive<any>({
+	dialogVisible: false, // 弹窗显示隐藏
+	ruleForm: {
+		name: '', // 违禁词
+		classify: '', // 违禁词分类
+		type: '', // 违禁词属性
+	},
+	loading: false, // 确定按钮loading
+});
+
+// 打开弹窗
+const openDialog = async () => {
+	state.dialogVisible = true;
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+// 取消
+const onCancel = () => {
+	closeDialog();
+};
+const close = () => {
+	dynamicTags.value = [];
+	ruleFormRef.value?.clearValidate();
+	ruleFormRef.value?.resetFields();
+};
+// 新增
+const onSubmit = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.validate((valid: boolean) => {
+		if (!valid) return;
+		state.loading = true;
+		const request = {
+			...state.ruleForm,
+			synonym: dynamicTags.value.join(','),
+		};
+		lexiconAdd(request)
+			.then(() => {
+				emit('updateList');
+				closeDialog(); // 关闭弹窗
+				ElMessage.success('操作成功');
+				state.loading = false;
+			})
+			.catch(() => {
+				emit('updateList');
+				state.loading = false;
+			});
+	});
+};
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>

+ 158 - 0
src/views/quality/lexicon/components/Lexicon-edit.vue

@@ -0,0 +1,158 @@
+<template>
+	<el-dialog title="编辑违禁词" v-model="state.dialogVisible" width="769px" draggable @close="close">
+		<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="100px">
+			<el-row :gutter="10">
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="违禁词" prop="name" :rules="[{ required: true, message: '请输入违禁词', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.name" placeholder="请输入违禁词" clearable></el-input>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="违禁词分类" prop="classify" :rules="[{ required: true, message: '请选择违禁词分类', trigger: 'change' }]">
+						<el-select v-model="state.ruleForm.classify" placeholder="请选择违禁词分类" class="w100">
+							<el-option v-for="item in props.prohibitedClassify" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="违禁词属性" prop="type" :rules="[{ required: true, message: '请选择违禁词属性', trigger: 'change' }]">
+						<el-select v-model="state.ruleForm.type" placeholder="请选择违禁词属性" class="w100">
+							<el-option v-for="item in props.prohibitedType" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="违禁同义词" prop="synonym" :rules="[{ required: false, message: '请选择违禁同义词', trigger: 'change' }]">
+						<el-tag v-for="tag in dynamicTags" :key="tag" class="mr10" closable :disable-transitions="false" @close="handleClose(tag)">
+							{{ tag }}
+						</el-tag>
+						<el-input
+							v-if="inputVisible"
+							ref="InputRef"
+							v-model="inputValue"
+							size="small"
+							@keyup.enter="handleInputConfirm"
+							@blur="handleInputConfirm"
+							style="max-width: 200px"
+						/>
+						<el-button v-else size="small" @click="showInput"> 添加同义词 </el-button>
+					</el-form-item>
+				</el-col>
+			</el-row>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="onCancel" class="default-button">取 消</el-button>
+				<el-button type="primary" @click="onSubmit(ruleFormRef)" v-waves="'light'" :loading="state.loading">确 定 </el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script setup lang="ts" name="qualityLexiconEdit">
+import { nextTick, reactive, ref } from 'vue';
+import { ElInput, ElMessage, FormInstance } from 'element-plus';
+import { lexiconDetail, lexiconUpdate } from '/@/api/quality/lexicon';
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+const props = defineProps({
+	prohibitedClassify: {
+		type: Array,
+		default: () => [],
+	},
+	prohibitedType: {
+		type: Array,
+		default: () => [],
+	},
+});
+
+const inputValue = ref('');
+const dynamicTags = ref<EmptyArrayType>([]);
+const inputVisible = ref(false);
+const InputRef = ref<InstanceType<typeof ElInput>>();
+// 删除同义词
+const handleClose = (tag: string) => {
+	dynamicTags.value.splice(dynamicTags.value.indexOf(tag), 1);
+};
+// 展示输入框
+const showInput = () => {
+	inputVisible.value = true;
+	nextTick(() => {
+		InputRef.value!.input!.focus();
+	});
+};
+// 确定添加
+const handleInputConfirm = () => {
+	if (inputValue.value) {
+		dynamicTags.value.push(inputValue.value);
+	}
+	inputVisible.value = false;
+	inputValue.value = '';
+};
+
+// 定义变量内容
+const ruleFormRef = ref<FormInstance>();
+const state = reactive<any>({
+	dialogVisible: false, // 弹窗显示隐藏
+	ruleForm: {
+		name: '', // 违禁词
+		classify: '', // 违禁词分类
+		type: '', // 违禁词属性
+	},
+	loading: false, // 确定按钮loading
+});
+
+// 打开弹窗
+const openDialog = async (row: any) => {
+	try {
+		const res = await lexiconDetail(row.id);
+		state.ruleForm = res.result ?? {};
+		dynamicTags.value = res.result.synonym?.split(',') ?? [];
+		state.dialogVisible = true;
+	} catch (e) {
+		console.log(e);
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+// 取消
+const onCancel = () => {
+	closeDialog();
+};
+const close = () => {
+	dynamicTags.value = [];
+	ruleFormRef.value?.clearValidate();
+	ruleFormRef.value?.resetFields();
+};
+// 新增
+const onSubmit = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.validate((valid: boolean) => {
+		if (!valid) return;
+		state.loading = true;
+		const request = {
+			...state.ruleForm,
+			synonym: dynamicTags.value.join(','),
+		};
+		lexiconUpdate(request)
+			.then(() => {
+				emit('updateList');
+				closeDialog(); // 关闭弹窗
+				ElMessage.success('操作成功');
+				state.loading = false;
+			})
+			.catch(() => {
+				emit('updateList');
+				state.loading = false;
+			});
+	});
+};
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>

+ 181 - 0
src/views/quality/lexicon/index.vue

@@ -0,0 +1,181 @@
+<template>
+  <div class="quality-lexicon-container layout-pd">
+    <el-card shadow="never">
+      <el-form :model="state.queryParams" ref="ruleFormRef" :inline="true" @submit.native.prevent>
+        <el-form-item label="违禁词分类" prop="Classify">
+          <el-select v-model="state.queryParams.Classify" placeholder="请选择违禁词分类">
+            <el-option v-for="item in prohibitedClassify" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="违禁词属性" prop="Type">
+          <el-select v-model="state.queryParams.Type" placeholder="请选择违禁词属性">
+            <el-option v-for="item in prohibitedType" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="违禁词" prop="Name">
+          <el-input v-model="state.queryParams.Name" placeholder="请输入违禁词" clearable @keyup.enter="queryList" style="width: 250px" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="queryList" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+          <el-button @click="resetQuery(ruleFormRef)" v-waves class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+    <el-card shadow="never">
+      <div class="mb20">
+        <el-button type="primary" @click="onLexiconAdd" v-waves v-auth="'quality:lexicon:add'">
+          <SvgIcon name="ele-Plus" class="mr5" />新增
+        </el-button>
+        <el-button type="primary" @click="onLexiconDelete" v-waves v-auth="'quality:lexicon:delete'" :disabled="!multipleSelection.length">
+          <SvgIcon name="ele-Delete" class="mr5" />删除
+        </el-button>
+      </div>
+      <!-- 表格 -->
+      <el-table :data="state.tableData" v-loading="state.loading" row-key="id" ref="multipleTableRef" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="name" label="违禁词" show-overflow-tooltip width="400"></el-table-column>
+        <el-table-column prop="classify" label="违禁词分类" show-overflow-tooltip width="130"></el-table-column>
+        <el-table-column prop="type" label="违禁词属性" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="creatorName" label="创建人" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="creationTime" label="创建时间" show-overflow-tooltip width="170">
+          <template #default="{ row }">
+            <span>{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="lastModificationName" label="更新人" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="lastModificationTime" label="更新时间" show-overflow-tooltip width="170">
+          <template #default="{ row }">
+            <span>{{ formatDate(row.lastModificationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="120" fixed="right" align="center">
+          <template #default="{ row }">
+            <el-button link type="primary" @click="onLexiconEdit(row)" v-auth="'quality:lexicon:edit'" title="修改违禁词"> 修改 </el-button>
+          </template>
+        </el-table-column>
+        <template #empty>
+          <Empty />
+        </template>
+      </el-table>
+      <!-- 分页 -->
+      <pagination
+          :total="state.total"
+          v-model:page="state.queryParams.PageIndex"
+          v-model:limit="state.queryParams.PageSize"
+          @pagination="queryList"
+      />
+    </el-card>
+    <!--  违禁词新增  -->
+    <lexicon-add ref="lexiconAddRef" @updateList="queryList" :prohibitedClassify="prohibitedClassify" :prohibitedType="prohibitedType"/>
+    <!--  违禁词编辑  -->
+    <lexicon-edit ref="lexiconEditRef" @updateList="queryList" :prohibitedClassify="prohibitedClassify" :prohibitedType="prohibitedType"/>
+  </div>
+</template>
+
+<script lang="ts" setup name="qualityLexicon">
+import { reactive, ref, onMounted, defineAsyncComponent } from 'vue';
+import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+import { formatDate } from '/@/utils/formatTime';
+import {auth} from "/@/utils/authFunction";
+import {lexiconList,lexiconDelete,lexiconBaseData} from '/@/api/quality/lexicon';
+
+// 引入组件
+const LexiconAdd = defineAsyncComponent(() => import('/@/views/quality/lexicon/components/Lexicon-add.vue')); // 违禁词新增
+const LexiconEdit = defineAsyncComponent(() => import('/@/views/quality/lexicon/components/Lexicon-edit.vue')); // 违禁词编辑
+
+// 定义变量内容
+const state = reactive<any>({
+  loading: false, // 加载状态
+  queryParams: {
+    // 查询参数
+    PageIndex: 1,
+    PageSize: 10,
+    Classify: null,
+    Type: null,
+    Name:''
+  },
+  total: 0, // 总条数
+  tableData: [], // 表格数据
+});
+const ruleFormRef = ref<RefType>(null); // 表单ref
+const prohibitedClassify = ref<EmptyArrayType>([]); // 违禁词分类
+const prohibitedType = ref<EmptyArrayType>([]); // 违禁词属性
+const getBaseData = async ()=>{
+  try {
+    const res = await lexiconBaseData();
+    prohibitedClassify.value = res.result?.prohibitedClassify ?? [];
+    prohibitedType.value = res.result?.prohibitedType ?? [];
+  } catch (error) {
+    console.log(error);
+  }
+}
+// 获取参数列表
+const queryList = () => {
+  state.loading = true;
+  if (!auth('quality:lexicon:query')) ElMessage.error('抱歉,您没有权限获取质检词库列表!');
+  else {
+    lexiconList(state.queryParams)
+        .then((res) => {
+          state.loading = false;
+          state.tableData = res.result.items ?? [];
+          state.total = res.result.total ?? 0;
+        })
+        .finally(() => {
+          state.loading = false;
+        });
+  }
+};
+// 重置表单
+const resetQuery = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  queryList();
+};
+// 新增意见
+const lexiconAddRef = ref<RefType>(); // 意见新增
+const onLexiconAdd = () => {
+  lexiconAddRef.value.openDialog();
+};
+// 修改意见
+const lexiconEditRef = ref<RefType>(); // 修改意见
+const onLexiconEdit = (row: any) => {
+  lexiconEditRef.value.openDialog(row);
+};
+// 表格多选
+const multipleTableRef = ref<RefType>();
+const multipleSelection = ref<any>([]);
+const handleSelectionChange = (val: any[]) => {
+  multipleSelection.value = val;
+};
+// 删除参数
+const onLexiconDelete = () => {
+  const names = multipleSelection.value.map((item: any) => item.name).join('、');
+  const ids = multipleSelection.value.map((item: any) => item.id);
+  ElMessageBox.confirm(`您确定要删除:【${names}】违禁词,是否继续?`, '提示', {
+    confirmButtonText: '确认',
+    cancelButtonText: '取消',
+    type: 'warning',
+    draggable: true,
+    cancelButtonClass: 'default-button',
+    autofocus: false,
+  })
+      .then(() => {
+        lexiconDelete({ids}).then(() => {
+          ElMessage.success('操作成功');
+          queryList();
+        });
+      })
+      .catch(() => {});
+};
+// 页面加载时
+onMounted(() => {
+  getBaseData();
+  queryList();
+});
+</script>
+
+<style lang="scss" scoped>
+.quality-lexicon-container {
+
+}
+</style>

+ 142 - 0
src/views/quality/project/components/Project-add.vue

@@ -0,0 +1,142 @@
+<template>
+  <el-dialog title="新增质检项" v-model="state.dialogVisible" width="769px" draggable @close="close">
+    <el-form :model="state.ruleForm" ref="ruleFormRef" label-width="110px">
+      <el-row :gutter="10">
+        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+          <el-form-item label="质检项名称" prop="name" :rules="[{ required: true, message: '请输入质检项名称', trigger: 'blur' }]">
+            <el-input v-model="state.ruleForm.name" placeholder="请输入质检项名称" clearable></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+          <el-form-item label="质检项分组" prop="groupingName" :rules="[{ required: true, message: '请选择质检项分组', trigger: 'change' }]">
+            <el-select v-model="state.ruleForm.groupingName" placeholder="请选择质检项分组" class="w100">
+              <el-option v-for="item in props.qualityItemGrouping" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+          <el-form-item label="质检项分值" prop="grade" :rules="[{ required: true, message: '请输入质检项分值', trigger: 'blur' }]">
+            <el-input-number
+                v-model="state.ruleForm.grade"
+                :precision="0"
+                :min="1"
+                :max="100"
+                placeholder="请输入质检项分值"
+            />
+            <span class="ml10">分</span>
+          </el-form-item>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+          <el-form-item label="是否智能质检" prop="isIntelligent" :rules="[{ required: false, message: '请选择是否智能质检', trigger: 'change' }]">
+            <el-switch
+                v-model="state.ruleForm.isIntelligent"
+                inline-prompt
+                active-text="是"
+                inactive-text="否"
+                :active-value="1"
+                :inactive-value="0"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+          <el-form-item label="是否启用" prop="isEnable" :rules="[{ required: false, message: '请选择是否启用性', trigger: 'change' }]">
+            <el-switch
+                v-model="state.ruleForm.isEnable"
+                inline-prompt
+                active-text="是"
+                inactive-text="否"
+                :active-value="1"
+                :inactive-value="0"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+          <el-form-item label="质检项描述" prop="describe" :rules="[{ required: false, message: '请输入质检项描述', trigger: 'blur' }]">
+            <el-input v-model="state.ruleForm.describe" placeholder="请输入质检项描述" type="textarea"></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template #footer>
+				<span class="dialog-footer">
+					<el-button @click="onCancel" class="default-button">取 消</el-button>
+					<el-button type="primary" @click="onSubmit(ruleFormRef)" v-waves="'light'" :loading="state.loading">确 定 </el-button>
+				</span>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts" name="qualityProjectAdd">
+import {reactive, ref} from 'vue';
+import {ElInput, ElMessage, FormInstance} from 'element-plus';
+import {projectAdd} from '/@/api/quality/project';
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+const props = defineProps({
+  qualityItemGrouping: {
+    type: Array,
+    default: () => [],
+  }
+})
+
+
+// 定义变量内容
+const ruleFormRef = ref<FormInstance>();
+const state = reactive<any>({
+  dialogVisible: false, // 弹窗显示隐藏
+  ruleForm: {
+    name: '', // 质检项名称
+    groupingName: '', // 质检项分组
+    grade: 1, // 质检项分值
+    isIntelligent: 0, // 是否智能质检
+    isEnable: 1, // 是否启用
+    describe: '', // 质检项描述
+  },
+  loading: false, // 确定按钮loading
+});
+
+// 打开弹窗
+const openDialog = async () => {
+  state.dialogVisible = true;
+};
+// 关闭弹窗
+const closeDialog = () => {
+  state.dialogVisible = false;
+};
+// 取消
+const onCancel = () => {
+  closeDialog();
+};
+const close = ()=>{
+  ruleFormRef.value?.clearValidate();
+  ruleFormRef.value?.resetFields();
+}
+// 新增
+const onSubmit = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.validate((valid: boolean) => {
+    if (!valid) return;
+    state.loading = true;
+    const request = {
+      ...state.ruleForm
+    }
+    projectAdd(request)
+        .then(() => {
+          emit('updateList');
+          closeDialog(); // 关闭弹窗
+          ElMessage.success('操作成功');
+          state.loading = false;
+        })
+        .catch(() => {
+          emit('updateList');
+          state.loading = false;
+        });
+  });
+};
+// 暴露变量
+defineExpose({
+  openDialog,
+  closeDialog,
+});
+</script>

+ 145 - 0
src/views/quality/project/components/Project-edit.vue

@@ -0,0 +1,145 @@
+<template>
+  <el-dialog title="编辑违禁词" v-model="state.dialogVisible" width="769px" draggable @close="close">
+    <el-form :model="state.ruleForm" ref="ruleFormRef" label-width="110px">
+      <el-row :gutter="10">
+        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+          <el-form-item label="质检项名称" prop="name" :rules="[{ required: true, message: '请输入质检项名称', trigger: 'blur' }]">
+            <el-input v-model="state.ruleForm.name" placeholder="请输入质检项名称" clearable></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+          <el-form-item label="质检项分组" prop="groupingName" :rules="[{ required: true, message: '请选择质检项分组', trigger: 'change' }]">
+            <el-select v-model="state.ruleForm.groupingName" placeholder="请选择质检项分组" class="w100">
+              <el-option v-for="item in props.qualityItemGrouping" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+          <el-form-item label="质检项分值" prop="grade" :rules="[{ required: true, message: '请输入质检项分值', trigger: 'blur' }]">
+            <el-input-number
+                v-model="state.ruleForm.grade"
+                :precision="0"
+                :min="1"
+                :max="100"
+                placeholder="请输入质检项分值"
+            />
+            <span class="ml10">分</span>
+          </el-form-item>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+          <el-form-item label="是否智能质检" prop="isIntelligent" :rules="[{ required: false, message: '请选择是否智能质检', trigger: 'change' }]">
+            <el-switch
+                v-model="state.ruleForm.isIntelligent"
+                inline-prompt
+                active-text="是"
+                inactive-text="否"
+                :active-value="1"
+                :inactive-value="0"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+          <el-form-item label="是否启用" prop="isEnable" :rules="[{ required: false, message: '请选择是否启用性', trigger: 'change' }]">
+            <el-switch
+                v-model="state.ruleForm.isEnable"
+                inline-prompt
+                active-text="是"
+                inactive-text="否"
+                :active-value="1"
+                :inactive-value="0"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+          <el-form-item label="质检项描述" prop="describe" :rules="[{ required: false, message: '请输入质检项描述', trigger: 'blur' }]">
+            <el-input v-model="state.ruleForm.describe" placeholder="请输入质检项描述" type="textarea"></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template #footer>
+				<span class="dialog-footer">
+					<el-button @click="closeDialog" class="default-button">取 消</el-button>
+					<el-button type="primary" @click="onSubmit(ruleFormRef)" v-waves="'light'" :loading="state.loading">确 定 </el-button>
+				</span>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts" name="qualityProjectEdit">
+import {reactive, ref} from 'vue';
+import {ElInput, ElMessage, FormInstance} from 'element-plus';
+import {projectDetail,projectUpdate} from '/@/api/quality/project'
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+const props = defineProps({
+  qualityItemGrouping: {
+    type: Array,
+    default: () => [],
+  }
+})
+
+
+// 定义变量内容
+const ruleFormRef = ref<FormInstance>();
+const state = reactive<any>({
+  dialogVisible: false, // 弹窗显示隐藏
+  ruleForm: {
+    name: '', // 质检项名称
+    groupingName: '', // 质检项分组
+    grade: 1, // 质检项分值
+    isIntelligent: 0, // 是否智能质检
+    isEnable: 1, // 是否启用
+    describe: '', // 质检项描述
+  },
+  loading: false, // 确定按钮loading
+});
+
+// 打开弹窗
+const openDialog = async (row: any) => {
+  try {
+    const res = await projectDetail(row.id);
+    state.ruleForm = res.result ?? {};
+    state.dialogVisible = true;
+  }catch (e) {
+    console.log(e);
+  }
+
+};
+// 关闭弹窗
+const closeDialog = () => {
+  state.dialogVisible = false;
+};
+const close = ()=>{
+  ruleFormRef.value?.clearValidate();
+  ruleFormRef.value?.resetFields();
+}
+// 保存
+const onSubmit = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.validate((valid: boolean) => {
+    if (!valid) return;
+    state.loading = true;
+    const request = {
+      ...state.ruleForm
+    }
+    projectUpdate(request)
+        .then(() => {
+          emit('updateList');
+          closeDialog(); // 关闭弹窗
+          ElMessage.success('操作成功');
+          state.loading = false;
+        })
+        .catch(() => {
+          emit('updateList');
+          state.loading = false;
+        });
+  });
+};
+// 暴露变量
+defineExpose({
+  openDialog,
+  closeDialog,
+});
+</script>

+ 220 - 0
src/views/quality/project/index.vue

@@ -0,0 +1,220 @@
+<template>
+	<div class="quality-project-container layout-pd">
+		<el-card shadow="never">
+			<el-form :model="state.queryParams" ref="ruleFormRef" :inline="true" @submit.native.prevent>
+				<el-form-item label="质检项分组" prop="GroupingName">
+					<el-select v-model="state.queryParams.GroupingName" placeholder="请选择质检项目分组">
+						<el-option v-for="item in qualityItemGrouping" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+					</el-select>
+				</el-form-item>
+				<el-form-item label="质检项名称" prop="Name">
+					<el-input v-model="state.queryParams.Name" placeholder="请输入质检项目名称" clearable @keyup.enter="queryList" style="width: 250px" />
+				</el-form-item>
+				<el-form-item>
+					<el-button type="primary" @click="queryList" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+					<el-button @click="resetQuery(ruleFormRef)" v-waves class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+				</el-form-item>
+			</el-form>
+		</el-card>
+		<el-card shadow="never">
+			<div class="mb20">
+				<el-button type="primary" @click="onProjectAdd" v-waves v-auth="'quality:project:add'">
+					<SvgIcon name="ele-Plus" class="mr5" />新增
+				</el-button>
+				<el-button type="primary" @click="onProjectDelete" v-waves v-auth="'quality:project:delete'" :disabled="!multipleSelection.length">
+					<SvgIcon name="ele-Delete" class="mr5" />删除
+				</el-button>
+			</div>
+			<!-- 表格 -->
+			<el-table :data="state.tableData" v-loading="state.loading" row-key="id" ref="multipleTableRef" @selection-change="handleSelectionChange">
+				<el-table-column type="selection" width="55" />
+				<el-table-column prop="name" label="质检项名称" show-overflow-tooltip></el-table-column>
+				<el-table-column prop="describe" label="质检项描述" show-overflow-tooltip width="130"></el-table-column>
+				<el-table-column prop="groupingName" label="质检项分组" show-overflow-tooltip></el-table-column>
+				<el-table-column prop="type" label="是否智能质检" show-overflow-tooltip>
+          <template #default="{ row }">
+            {{row.isIntelligent === 1 ? '是' : '否'}}
+          </template>
+        </el-table-column>
+				<el-table-column prop="grade" label="分值(分)" show-overflow-tooltip></el-table-column>
+				<el-table-column label="是否启用" show-overflow-tooltip>
+					<template #default="{ row }">
+						<el-switch
+							v-model="row.isEnable"
+							:active-value="1"
+							:inactive-value="0"
+							inline-prompt
+							active-text="启用"
+							inactive-text="禁用"
+							@change="changeIsEnable(row)"
+						/>
+					</template>
+				</el-table-column>
+				<el-table-column prop="creatorName" label="创建人" show-overflow-tooltip></el-table-column>
+				<el-table-column prop="creationTime" label="创建时间" show-overflow-tooltip width="170">
+					<template #default="{ row }">
+						<span>{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+					</template>
+				</el-table-column>
+				<el-table-column prop="lastModificationName" label="更新人" show-overflow-tooltip></el-table-column>
+				<el-table-column prop="lastModificationTime" label="更新时间" show-overflow-tooltip width="170">
+					<template #default="{ row }">
+						<span>{{ formatDate(row.lastModificationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+					</template>
+				</el-table-column>
+				<el-table-column label="操作" width="120" fixed="right" align="center">
+					<template #default="{ row }">
+						<el-button link type="primary" @click="onProjectEdit(row)" v-auth="'quality:project:edit'" title="修改质检项目"> 修改 </el-button>
+					</template>
+				</el-table-column>
+				<template #empty>
+					<Empty />
+				</template>
+			</el-table>
+			<!-- 分页 -->
+			<pagination
+				:total="state.total"
+				v-model:page="state.queryParams.PageIndex"
+				v-model:limit="state.queryParams.PageSize"
+				@pagination="queryList"
+			/>
+		</el-card>
+		<!--  质检项目新增  -->
+		<project-add ref="projectAddRef" @updateList="queryList" :qualityItemGrouping="qualityItemGrouping" />
+		<!--  质检项目编辑  -->
+		<project-edit ref="projectEditRef" @updateList="queryList" :qualityItemGrouping="qualityItemGrouping" />
+	</div>
+</template>
+
+<script lang="ts" setup name="qualityProject">
+import { reactive, ref, onMounted, defineAsyncComponent } from 'vue';
+import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+import { formatDate } from '/@/utils/formatTime';
+import { auth } from '/@/utils/authFunction';
+import { projectBaseData, projectList, projectDelete, projectUpdate } from '/@/api/quality/project';
+
+// 引入组件
+const ProjectAdd = defineAsyncComponent(() => import('/@/views/quality/project/components/Project-add.vue')); // 质检项目新增
+const ProjectEdit = defineAsyncComponent(() => import('/@/views/quality/project/components/Project-edit.vue')); // 质检项目编辑
+
+// 定义变量内容
+const state = reactive<any>({
+	loading: false, // 加载状态
+	queryParams: {
+		// 查询参数
+		PageIndex: 1,
+		PageSize: 10,
+		GroupingName: null,
+		Type: null,
+		Name: '',
+	},
+	total: 0, // 总条数
+	tableData: [], // 表格数据
+});
+const ruleFormRef = ref<RefType>(null); // 表单ref
+const qualityItemGrouping = ref<EmptyArrayType>([]); // 质检项目分组
+const getBaseData = async () => {
+	try {
+		const res = await projectBaseData();
+		qualityItemGrouping.value = res.result?.qualityItemGrouping ?? [];
+	} catch (error) {
+		console.log(error);
+	}
+};
+// 获取参数列表
+const queryList = () => {
+	state.loading = true;
+	if (!auth('quality:project:query')) ElMessage.error('抱歉,您没有权限获取质检项目列表!');
+	else {
+		projectList(state.queryParams)
+			.then((res) => {
+				state.loading = false;
+				state.tableData = res.result.items ?? [];
+				state.total = res.result.total ?? 0;
+			})
+			.finally(() => {
+				state.loading = false;
+			});
+	}
+};
+// 重置表单
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	queryList();
+};
+// 新增质检项目
+const projectAddRef = ref<RefType>();
+const onProjectAdd = () => {
+	projectAddRef.value.openDialog();
+};
+// 编辑质检项目
+const projectEditRef = ref<RefType>();
+const onProjectEdit = (row: any) => {
+	projectEditRef.value.openDialog(row);
+};
+// 表格多选
+const multipleTableRef = ref<RefType>();
+const multipleSelection = ref<any>([]);
+const handleSelectionChange = (val: any[]) => {
+	multipleSelection.value = val;
+};
+// 删除质检项目
+const onProjectDelete = () => {
+	const names = multipleSelection.value.map((item: any) => item.name).join('、');
+	const ids = multipleSelection.value.map((item: any) => item.id);
+	ElMessageBox.confirm(`您确定要删除:【${names}】质检项目,是否继续?`, '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		cancelButtonClass: 'default-button',
+		autofocus: false,
+	})
+		.then(() => {
+			projectDelete({ ids }).then(() => {
+				ElMessage.success('操作成功');
+				queryList();
+			});
+		})
+		.catch(() => {});
+};
+//  修改是否启用
+const changeIsEnable = (row: any) => {
+	ElMessageBox.confirm(`您确定要${row.isEnable ? '启用' : '禁用'}:【${row.name}】质检项,是否继续?`, '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		cancelButtonClass: 'default-button',
+		autofocus: false,
+	})
+		.then(() => {
+			const request = {
+				...row,
+				isEnable: row.isEnable,
+			};
+			projectUpdate(request)
+				.then(() => {
+					ElMessage.success('操作成功');
+					queryList();
+				})
+				.catch(() => {
+          queryList();
+        });
+		})
+		.catch(() => {
+      queryList();
+    });
+};
+// 页面加载时
+onMounted(() => {
+	getBaseData();
+	queryList();
+});
+</script>
+
+<style lang="scss" scoped>
+.quality-project-container {
+}
+</style>

+ 181 - 0
src/views/quality/template/components/Template-add.vue

@@ -0,0 +1,181 @@
+<template>
+	<el-dialog title="新增质检模板" v-model="state.dialogVisible" width="800px" draggable @close="close">
+		<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="100px">
+			<el-row :gutter="10">
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="模板名称" prop="name" :rules="[{ required: true, message: '请输入模板名称', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.name" placeholder="请输入模板名称" clearable></el-input>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="质检分类" prop="grouping" :rules="[{ required: true, message: '请选择质检分类', trigger: 'change' }]">
+						<el-select v-model="state.ruleForm.grouping" placeholder="请选择质检分类" class="w100">
+							<el-option v-for="item in props.templateGrouping" :value="item.key" :key="item.key" :label="item.value" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="模板说明" prop="content" :rules="[{ required: false, message: '请输入模板说明', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.content" placeholder="请输入模板说明" type="textarea"></el-input>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="是否启用" prop="isEnable" :rules="[{ required: false, message: '请选择是否启用', trigger: 'change' }]">
+						<el-switch
+							v-model="state.ruleForm.isEnable"
+							inline-prompt
+							active-text="启用"
+							inactive-text="禁用"
+							:active-value="1"
+							:inactive-value="0"
+						/>
+					</el-form-item>
+				</el-col>
+			</el-row>
+			<el-divider content-position="left">
+				<span class="font-bold font16 mr20">模板内容</span>
+				<el-button link type="primary" @click="addItems"><SvgIcon name="ele-CirclePlus" size="18px" class="mr3" /> 质检项</el-button>
+			</el-divider>
+			<el-row v-for="(item, index) in state.ruleForm.templateDetails" :key="item.id" :gutter="10">
+				<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
+					<el-form-item
+						label="质检项"
+						:prop="`templateDetails.${index}.obj`"
+						:rules="[{ required: true, message: '请选择质检项', trigger: 'change' }]"
+					>
+						<el-select v-model="item.obj" placeholder="请选择质检项" class="w100" value-key="name" @change="changeProject($event, index)">
+							<el-option v-for="items in projectArray" :key="items.id" :label="items.name" :value="items" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
+					<el-form-item label="AI质检">
+						{{ item.isIntelligent === 1 ? '是' : '否' }}
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
+					<el-form-item label="扣分值"> {{ item.grade }} <span class="ml5">分</span> </el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
+					<el-form-item label="">
+						<el-button link type="primary" @click="deleteProject(index)"> <SvgIcon name="ele-Delete" /> </el-button>
+					</el-form-item>
+				</el-col>
+			</el-row>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="closeDialog" class="default-button">取 消</el-button>
+				<el-button type="primary" @click="onSubmit(ruleFormRef)" v-waves="'light'" :loading="state.loading">确 定 </el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script setup lang="ts" name="qualityLexiconAdd">
+import { reactive, ref } from 'vue';
+import { ElInput, ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+import { projectList } from '/@/api/quality/project';
+import { templateAdd, templateDelete } from '/@/api/quality/template';
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+const props = defineProps({
+	templateGrouping: {
+		type: Array,
+		default: () => [],
+	},
+});
+
+// 定义变量内容
+const ruleFormRef = ref<FormInstance>();
+const state = reactive<any>({
+	dialogVisible: false, // 弹窗显示隐藏
+	ruleForm: {
+		name: '', // 模板名称
+		grouping: '', // 质检分类
+		content: '', // 模板说明
+		isEnable: 1, // 是否启用
+		templateDetails: [],
+	},
+	loading: false, // 确定按钮loading
+});
+const projectArray = ref<EmptyArrayType>([]); // 质检项
+// 打开弹窗
+const openDialog = async () => {
+	try {
+		const res = await projectList({ PageIndex: 1, PageSize: 999, IsEnable: 1 });
+		projectArray.value = res.result?.items ?? [];
+		state.dialogVisible = true;
+	} catch (e) {
+		console.log(e);
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+// 新增质检项
+const addItems = () => {
+	state.ruleForm.templateDetails.push({
+		name: '',
+		content: '',
+		grade: 0,
+		isIntelligent: 0,
+	});
+};
+// 选择质检项
+const changeProject = (item: any, index: number | string) => {
+	state.ruleForm.templateDetails[index].name = item.name;
+	state.ruleForm.templateDetails[index].content = item.describe;
+	state.ruleForm.templateDetails[index].grade = item.grade;
+	state.ruleForm.templateDetails[index].isIntelligent = item.isIntelligent;
+};
+// 删除质检项
+const deleteProject = (index: number) => {
+	ElMessageBox.confirm(`您确定要删除此质检项,是否继续?`, '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		cancelButtonClass: 'default-button',
+		autofocus: false,
+	})
+		.then(() => {
+			state.ruleForm.templateDetails.splice(index, 1);
+		})
+		.catch(() => {});
+};
+const close = () => {
+	ruleFormRef.value?.clearValidate();
+	ruleFormRef.value?.resetFields();
+  state.ruleForm.templateDetails = [];
+};
+// 新增
+const onSubmit = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.validate((valid: boolean) => {
+		if (!valid) return;
+		state.loading = true;
+		const request = {
+			...state.ruleForm,
+		};
+		templateAdd(request)
+			.then(() => {
+				emit('updateList');
+				closeDialog(); // 关闭弹窗
+				ElMessage.success('操作成功');
+				state.loading = false;
+			})
+			.catch(() => {
+				emit('updateList');
+				state.loading = false;
+			});
+	});
+};
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>

+ 201 - 0
src/views/quality/template/components/Template-edit.vue

@@ -0,0 +1,201 @@
+<template>
+	<el-dialog title="编辑质检模板" v-model="state.dialogVisible" width="769px" draggable @close="close">
+		<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="100px">
+			<el-row :gutter="10">
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="模板名称" prop="name" :rules="[{ required: true, message: '请输入模板名称', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.name" placeholder="请输入模板名称" clearable></el-input>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="质检分类" prop="grouping" :rules="[{ required: true, message: '请选择质检分类', trigger: 'change' }]">
+						<el-select v-model="state.ruleForm.grouping" placeholder="请选择质检分类" class="w100">
+							<el-option v-for="item in props.templateGrouping" :value="item.key" :key="item.key" :label="item.value" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="模板说明" prop="content" :rules="[{ required: false, message: '请输入模板说明', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.content" placeholder="请输入模板说明" type="textarea"></el-input>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="是否启用" prop="isEnable" :rules="[{ required: false, message: '请选择是否启用', trigger: 'change' }]">
+						<el-switch
+							v-model="state.ruleForm.isEnable"
+							inline-prompt
+							active-text="启用"
+							inactive-text="禁用"
+							:active-value="1"
+							:inactive-value="0"
+						/>
+					</el-form-item>
+				</el-col>
+			</el-row>
+			<el-divider content-position="left">
+				<span class="font-bold font16 mr20">模板内容</span>
+				<el-button link type="primary" @click="addItems"><SvgIcon name="ele-CirclePlus" size="18px" class="mr3" /> 质检项</el-button>
+			</el-divider>
+			<el-row v-for="(item, index) in state.ruleForm.templateDetails" :key="item.id" :gutter="10">
+				<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
+					<el-form-item
+						label="质检项"
+						:prop="`templateDetails.${index}.obj`"
+						:rules="[{ required: true, message: '请选择质检项', trigger: 'change' }]"
+					>
+						<el-select v-model="item.obj" placeholder="请选择质检项" class="w100" value-key="name" @change="changeProject($event, index)">
+							<el-option v-for="items in projectArray" :key="items.id" :label="items.name" :value="items" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
+					<el-form-item
+						label="AI质检"
+						:prop="`templateDetails.${index}.isIntelligent`"
+						:rules="[{ required: false, message: '请选择是否AI质检', trigger: 'change' }]"
+					>
+						{{ item.isIntelligent === 1 ? '是' : '否' }}
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
+					<el-form-item
+						label="扣分值"
+						:prop="`templateDetails.${index}.grade`"
+						:rules="[{ required: false, message: '请选择扣分值', trigger: 'change' }]"
+					>
+						{{ item.grade }} <span class="ml5">分</span>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
+					<el-form-item
+						label=""
+						:prop="`templateDetails.${index}.isIntelligent`"
+						:rules="[{ required: false, message: '请选择是否AI质检', trigger: 'change' }]"
+					>
+						<el-button link type="primary" @click="deleteProject(index)"> <SvgIcon name="ele-Delete" /> </el-button>
+					</el-form-item>
+				</el-col>
+			</el-row>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="closeDialog" class="default-button">取 消</el-button>
+				<el-button type="primary" @click="onSubmit(ruleFormRef)" v-waves="'light'" :loading="state.loading">确 定 </el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script setup lang="ts" name="qualityLexiconEdit">
+import { reactive, ref } from 'vue';
+import {ElInput, ElMessage, ElMessageBox, FormInstance} from 'element-plus';
+import { templateDetail, templateUpdate } from '/@/api/quality/template';
+import { projectList } from '/@/api/quality/project';
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+const props = defineProps({
+	templateGrouping: {
+		type: Array,
+		default: () => [],
+	},
+});
+// 定义变量内容
+const ruleFormRef = ref<FormInstance>();
+const state = reactive<any>({
+	dialogVisible: false, // 弹窗显示隐藏
+	ruleForm: {
+    name: '', // 模板名称
+    grouping: '', // 质检分类
+    content: '', // 模板说明
+    isEnable: 1, // 是否启用
+    templateDetails: [],
+	},
+	loading: false, // 确定按钮loading
+});
+const projectArray = ref<EmptyArrayType>([]); // 质检项
+// 打开弹窗
+const openDialog = async (row: any) => {
+	try {
+		const res = await templateDetail(row.id);
+		state.ruleForm = res.result ?? {};
+    if(state.ruleForm.templateDetails && state.ruleForm.templateDetails.length){
+      for(let i of state.ruleForm.templateDetails){
+        i.obj = {...i}
+      }
+    }
+    const response = await projectList({ PageIndex: 1, PageSize: 999, IsEnable: 1 });
+    projectArray.value = response.result?.items ?? [];
+		state.dialogVisible = true;
+	} catch (e) {
+		console.log(e);
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+const close = () => {
+  state.ruleForm.templateDetails = [];
+	ruleFormRef.value?.clearValidate();
+	ruleFormRef.value?.resetFields();
+};
+// 新增质检项
+const addItems = () => {
+  state.ruleForm.templateDetails.push({
+    name: '',
+    content: '',
+    grade: 0,
+    isIntelligent: 0,
+  });
+};
+// 选择质检项
+const changeProject = (item: any, index: number | string) => {
+  state.ruleForm.templateDetails[index].name = item.name;
+  state.ruleForm.templateDetails[index].content = item.describe;
+  state.ruleForm.templateDetails[index].grade = item.grade;
+  state.ruleForm.templateDetails[index].isIntelligent = item.isIntelligent;
+};
+// 删除质检项
+const deleteProject = (index: number) => {
+  ElMessageBox.confirm(`您确定要删除此质检项,是否继续?`, '提示', {
+    confirmButtonText: '确认',
+    cancelButtonText: '取消',
+    type: 'warning',
+    draggable: true,
+    cancelButtonClass: 'default-button',
+    autofocus: false,
+  })
+      .then(() => {
+        state.ruleForm.templateDetails.splice(index, 1);
+      })
+      .catch(() => {});
+};
+// 新增
+const onSubmit = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.validate((valid: boolean) => {
+		if (!valid) return;
+		state.loading = true;
+		const request = {
+			...state.ruleForm,
+		};
+		templateUpdate(request)
+			.then(() => {
+				emit('updateList');
+				closeDialog(); // 关闭弹窗
+				ElMessage.success('操作成功');
+				state.loading = false;
+			})
+			.catch(() => {
+				emit('updateList');
+				state.loading = false;
+			});
+	});
+};
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>

+ 212 - 0
src/views/quality/template/index.vue

@@ -0,0 +1,212 @@
+<template>
+	<div class="quality-template-container layout-pd">
+		<el-card shadow="never">
+			<el-form :model="state.queryParams" ref="ruleFormRef" :inline="true" @submit.native.prevent>
+				<el-form-item label="模版名称" prop="Name">
+					<el-input v-model="state.queryParams.Name" placeholder="请输入模版名称" clearable @keyup.enter="queryList" style="width: 250px" />
+				</el-form-item>
+				<el-form-item label="质检分类" prop="Grouping">
+					<el-select v-model="state.queryParams.Grouping" placeholder="请选择质检分类">
+						<el-option v-for="item in templateGrouping" :value="item.key" :key="item.key" :label="item.value" />
+					</el-select>
+				</el-form-item>
+				<el-form-item>
+					<el-button type="primary" @click="queryList" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+					<el-button @click="resetQuery(ruleFormRef)" v-waves class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+				</el-form-item>
+			</el-form>
+		</el-card>
+		<el-card shadow="never">
+			<div class="mb20">
+				<el-button type="primary" @click="onTemplateAdd" v-waves v-auth="'quality:template:add'">
+					<SvgIcon name="ele-Plus" class="mr5" />新增
+				</el-button>
+				<el-button type="primary" @click="onTemplateDelete" v-waves v-auth="'quality:template:delete'" :disabled="!multipleSelection.length">
+					<SvgIcon name="ele-Delete" class="mr5" />删除
+				</el-button>
+			</div>
+			<!-- 表格 -->
+			<el-table :data="state.tableData" v-loading="state.loading" row-key="id" ref="multipleTableRef" @selection-change="handleSelectionChange">
+				<el-table-column type="selection" width="55" />
+				<el-table-column prop="name" label="模版名称" show-overflow-tooltip width="130"></el-table-column>
+				<el-table-column prop="groupingText" label="质检分类" show-overflow-tooltip></el-table-column>
+        <el-table-column label="是否启用" show-overflow-tooltip>
+          <template #default="{ row }">
+            <el-switch
+                v-model="row.isEnable"
+                :active-value="1"
+                :inactive-value="0"
+                inline-prompt
+                active-text="启用"
+                inactive-text="禁用"
+                @change="changeIsEnable(row)"
+            />
+          </template>
+        </el-table-column>
+				<el-table-column prop="creatorName" label="创建人" show-overflow-tooltip></el-table-column>
+				<el-table-column prop="creationTime" label="创建时间" show-overflow-tooltip width="170">
+					<template #default="{ row }">
+						<span>{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+					</template>
+				</el-table-column>
+				<el-table-column prop="lastModificationName" label="更新人" show-overflow-tooltip></el-table-column>
+				<el-table-column prop="lastModificationTime" label="更新时间" show-overflow-tooltip width="170">
+					<template #default="{ row }">
+						<span>{{ formatDate(row.lastModificationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+					</template>
+				</el-table-column>
+				<el-table-column label="操作" width="120" fixed="right" align="center">
+					<template #default="{ row }">
+						<el-button link type="primary" @click="onTemplateEdit(row)" v-auth="'quality:template:edit'" title="修改模板"> 修改 </el-button>
+					</template>
+				</el-table-column>
+				<template #empty>
+					<Empty />
+				</template>
+			</el-table>
+			<!-- 分页 -->
+			<pagination
+				:total="state.total"
+				v-model:page="state.queryParams.PageIndex"
+				v-model:limit="state.queryParams.PageSize"
+				@pagination="queryList"
+			/>
+		</el-card>
+		<!--  模板新增  -->
+		<quality-template-add ref="templateAdd" @updateList="queryList"  :templateGrouping="templateGrouping"/>
+		<!--  模板编辑  -->
+		<quality-template-edit ref="templateEditRef" @updateList="queryList" :templateGrouping="templateGrouping" />
+	</div>
+</template>
+
+<script lang="ts" setup name="qualityTemplate">
+import { reactive, ref, onMounted, defineAsyncComponent } from 'vue';
+import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+import { formatDate } from '/@/utils/formatTime';
+import { auth } from '/@/utils/authFunction';
+import {templateBaseData,templateList,templateDelete,templateUpdate} from "/@/api/quality/template"
+
+// 引入组件
+const QualityTemplateAdd = defineAsyncComponent(() => import('/@/views/quality/template/components/Template-add.vue')); // 模板新增
+const QualityTemplateEdit = defineAsyncComponent(() => import('/@/views/quality/template/components/Template-edit.vue')); // 模板编辑
+
+// 定义变量内容
+const state = reactive<any>({
+	loading: false, // 加载状态
+	queryParams: {
+		// 查询参数
+		PageIndex: 1,
+		PageSize: 10,
+    Grouping: null,
+		Name: '',
+	},
+	total: 0, // 总条数
+	tableData: [], // 表格数据
+});
+const ruleFormRef = ref<RefType>(null); // 表单ref
+const templateGrouping = ref<EmptyArrayType>([]); // 质检分组
+const getBaseData = async () => {
+	try {
+		const res = await templateBaseData();
+    templateGrouping.value = res.result?.templateGrouping ?? [];
+	} catch (error) {
+		console.log(error);
+	}
+};
+// 获取参数列表
+const queryList = () => {
+	state.loading = true;
+	if (!auth('quality:template:query')) ElMessage.error('抱歉,您没有权限获取质检模板列表!');
+	else {
+    templateList(state.queryParams)
+			.then((res) => {
+				state.loading = false;
+				state.tableData = res.result.items ?? [];
+				state.total = res.result.total ?? 0;
+			})
+			.finally(() => {
+				state.loading = false;
+			});
+	}
+};
+// 重置表单
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	queryList();
+};
+// 新增意见
+const templateAdd = ref<RefType>(); // 意见新增
+const onTemplateAdd = () => {
+	templateAdd.value.openDialog();
+};
+// 修改意见
+const templateEditRef = ref<RefType>(); // 修改意见
+const onTemplateEdit = (row: any) => {
+	templateEditRef.value.openDialog(row);
+};
+// 表格多选
+const multipleTableRef = ref<RefType>();
+const multipleSelection = ref<any>([]);
+const handleSelectionChange = (val: any[]) => {
+	multipleSelection.value = val;
+};
+//  修改是否启用
+const changeIsEnable = (row: any) => {
+  ElMessageBox.confirm(`您确定要${row.isEnable ? '启用' : '禁用'}:【${row.name}】模板,是否继续?`, '提示', {
+    confirmButtonText: '确认',
+    cancelButtonText: '取消',
+    type: 'warning',
+    draggable: true,
+    cancelButtonClass: 'default-button',
+    autofocus: false,
+  })
+      .then(() => {
+        const request = {
+          ...row,
+          isEnable: row.isEnable,
+        };
+        templateUpdate(request)
+            .then(() => {
+              ElMessage.success('操作成功');
+              queryList();
+            })
+            .catch(() => {
+              queryList();
+            });
+      })
+      .catch(() => {
+        queryList();
+      });
+};
+// 删除参数
+const onTemplateDelete = () => {
+	const names = multipleSelection.value.map((item: any) => item.name).join('、');
+	const ids = multipleSelection.value.map((item: any) => item.id);
+	ElMessageBox.confirm(`您确定要删除:【${names}】模板,是否继续?`, '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		cancelButtonClass: 'default-button',
+		autofocus: false,
+	})
+		.then(() => {
+      templateDelete({ ids }).then(() => {
+				ElMessage.success('操作成功');
+				queryList();
+			});
+		})
+		.catch(() => {});
+};
+// 页面加载时
+onMounted(() => {
+	getBaseData();
+	queryList();
+});
+</script>
+
+<style lang="scss" scoped>
+.quality-template-container {
+}
+</style>

+ 1 - 1
src/views/system/menu/index.vue

@@ -79,7 +79,7 @@ const state = reactive({
 			title: '菜单名称',
 			width: 300,
 			cellRenderer: (data: any) => {
-				return h('p', { style: { justifyContent: 'flex-end' } }, [
+				return h('p', { style: { display:'flex',alignItems:'center' } }, [
 					h(MenuSvgIcon, { name: data.rowData.icon }, ''),
 					h('span', { class: 'pl5' }, { default: () => data.rowData.pageName }),
 				]);