Эх сурвалжийг харах

reactor: 【标书】新增【录音上传】功能;

zhangchong 4 сар өмнө
parent
commit
805c407b80

+ 36 - 0
src/api/statistics/center.ts

@@ -722,4 +722,40 @@ export const centerSatisfactionDetailDataExport = (data: object) => {
   }, {
     reduce_data_format: false
   });
+}
+/**
+ * @description 工单热词分析列表
+ * @param {object} params
+ */
+export const centerHotWord = (params: object) => {
+  return request({
+    url: `/api/v1/BiOrder/query_order_ts_details_list`,
+    method: 'get',
+    params,
+  });
+}
+/**
+ * @description 工单热词分析列表导出
+ * @param {object} data
+ */
+export const centerHotWordExport = (data: object) => {
+  return request({
+    url: `/api/v1/BiOrder/query_order_ts_details_list/export`,
+    method: 'post',
+    data,
+    responseType: 'blob',
+  }, {
+    reduce_data_format: false
+  });
+}
+/**
+ * @description 根据热词查询工单
+ * @param {object} params
+ */
+export const centerHotWordQuery = (params: object) => {
+  return request({
+    url: `/api/v1/BiOrder/get_query_order_ts_details_order_list`,
+    method: 'get',
+    params,
+  });
 }

+ 346 - 292
src/api/statistics/department.ts

@@ -3,500 +3,554 @@
  * @description 数据统计-部门统计
  */
 import request from '@/utils/request';
-import qs from "qs";
+import qs from 'qs';
 /**
  * @description 部门延期统计
  * @param {object} params
  */
 export const departmentDelay = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/order-delay-data-list`,
-    method: 'get',
-    params,
-  });
+	return request({
+		url: `/api/v1/BiOrder/order-delay-data-list`,
+		method: 'get',
+		params,
+	});
 };
 /**
  * @description 部门延期统计导出
  * @param {object} data
  */
 export const departmentDelayExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/order-delay-data-list-export`,
-    method: 'post',
-    data,
-    responseType: 'blob'
-  }, {
-    reduce_data_format: false
-  });
+	return request(
+		{
+			url: `/api/v1/BiOrder/order-delay-data-list-export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
 };
 /**
  * @description 部门延期统计明细
  * @param {object} params
  */
 export const departmentDelayDetail = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/order-delay-data-detail`,
-    method: 'get',
-    params,
-  });
+	return request({
+		url: `/api/v1/BiOrder/order-delay-data-detail`,
+		method: 'get',
+		params,
+	});
 };
 /**
  * @description 部门延期统计明细(列表)
  * @param {object} params
  */
 export const departmentDelayDetailList = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/order_delay_detail`,
-    method: 'get',
-    params,
-  });
+	return request({
+		url: `/api/v1/BiOrder/order_delay_detail`,
+		method: 'get',
+		params,
+	});
 };
 /**
  * @description 部门延期统计明细导出
  * @param {object} data
  */
 export const departmentDelayDetailExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/order-delay-data-detail-export`,
-    method: 'post',
-    data,
-    responseType: 'blob'
-  }, {
-    reduce_data_format: false
-  });
+	return request(
+		{
+			url: `/api/v1/BiOrder/order-delay-data-detail-export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
 };
 /**
  * @description 部门超期统计
  * @param {object} params
  */
 export const departmentOverdue = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/org_data_list`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/org_data_list`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 部门超期统计导出
  * @param {object} data
  */
 export const departmentOverdueExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/org_data_list/_export`,
-    method: 'post',
-    data,
-    responseType: 'blob'
-  }, {
-    reduce_data_format: false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/org_data_list/_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 部门超期统计明细
  * @param {object} params
  */
 export const departmentOverdueDetail = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/org_data_list_detail`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/org_data_list_detail`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 部门超期统计明细导出
  * @param {object} data
  */
 export const departmentOverdueDetailExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/org_data_list_detail/_export`,
-    method: 'post',
-    data,
-    responseType: 'blob'
-  }, {
-    reduce_data_format: false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/org_data_list_detail/_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 部门超期列表基础数据
  * @param {object} params
  */
 export const departmentOverdueBase = (params?: object) => {
-  return request({
-    url: `/api/v1/BiOrder/org_data_list_detail_all/base-data`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/org_data_list_detail_all/base-data`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 部门超期列表明细
  * @param {object} params
  */
 export const departmentOverdueList = (params?: object) => {
-  return request({
-    url: `/api/v1/BiOrder/org_data_list_detail_all`,
-    method: 'get',
-    params,
-    paramsSerializer: (params:any) => qs.stringify(params)
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/org_data_list_detail_all`,
+		method: 'get',
+		params,
+		paramsSerializer: (params: any) => qs.stringify(params),
+	});
+};
 /**
  * @description 部门超期列表明细导出
  * @param {object} data
  */
 export const departmentOverdueListExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/org_data_list_detail_all/_export`,
-    method: 'post',
-    data,
-    responseType: 'blob'
-  }, {
-    reduce_data_format: false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/org_data_list_detail_all/_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 部门满意度统计
  * @param {object} params
  */
 export const departmentSatisfaction = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/visit-org-satisfaction-statistics`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/visit-org-satisfaction-statistics`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 部门满意度统计-基础数据
  * @param {object} params
  */
 export const departmentSatisfactionBase = (params?: object) => {
-  return request({
-    url: `/api/v1/BiOrder/visit-org-satisfaction-statisticsBaseData`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/visit-org-satisfaction-statisticsBaseData`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 部门满意度统计导出
  * @param {object} data
  */
 export const departmentSatisfactionExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/visit-org-satisfaction-statistics/_export`,
-    method: 'post',
-    data,
-    responseType: 'blob'
-  }, {
-    reduce_data_format: false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/visit-org-satisfaction-statistics/_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 部门满意度统计明细
  * @param {object} params
  */
 export const departmentSatisfactionDetail = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/visit-org-satisfaction-detail`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/visit-org-satisfaction-detail`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 部门满意度统计明细导出
  * @param {object} data
  */
 export const departmentSatisfactionDetailExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/visit-org-satisfaction-detail/_export`,
-    method: 'post',
-    data,
-    responseType: 'blob'
-  }, {
-    reduce_data_format: false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/visit-org-satisfaction-detail/_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 部门满意度统计明细列表基础数据
  * @param {object} params
  */
 export const departmentSatisfactionDetailBase = (params?: object) => {
-  return request({
-    url: `/api/v1/biorder/org-visitdetail-list-basedata`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/biorder/org-visitdetail-list-basedata`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 部门满意度统计明细列表
  * @param {object} params
  */
 export const departmentSatisfactionList = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/org-visitdetail-list`,
-    method: 'get',
-    params,
-    paramsSerializer: (params:any) => qs.stringify(params)
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/org-visitdetail-list`,
+		method: 'get',
+		params,
+		paramsSerializer: (params: any) => qs.stringify(params),
+	});
+};
 /**
  * @description 部门满意度统计明细列表导出
  * @param {object} data
  */
 export const departmentSatisfactionListExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/org-visitdetail-list-export`,
-    method: 'post',
-    data,
-    responseType: 'blob'
-  }, {
-    reduce_data_format: false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/org-visitdetail-list-export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 子部门满意度统计明细
  * @param {object} params
  */
 export const departmentSatisfactionOrg = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/visit-org-statisfaction-org-detail`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/visit-org-statisfaction-org-detail`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 子部门满意度统计明细导出
  * @param {object} data
  */
 export const departmentSatisfactionOrgExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/visit-org-statisfaction-org-detail/_export`,
-    method: 'post',
-    data,
-    responseType: 'blob'
-  }, {
-    reduce_data_format: false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/visit-org-statisfaction-org-detail/_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 部门办件统计表
  * @param {object} params
  */
 export const departmentOrder = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/departmental_processing_statistics`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/departmental_processing_statistics`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 部门办件统计表导出
  * @param {object} data
  */
 export const departmentOrderExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/departmental_processing_statistics_export`,
-    method: 'post',
-    data,
-    responseType: 'blob'
-  }, {
-    reduce_data_format: false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/departmental_processing_statistics_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 部门办件统计表明细
  * @param {object} params
  */
 export const departmentOrderDetail = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/departmental_processing_statistics_list`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/departmental_processing_statistics_list`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 部门办件统计表明细导出
  * @param {object} data
  */
 export const departmentOrderDetailExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/departmental_processing_statistics_list_export`,
-    method: 'post',
-    data,
-    responseType: 'blob'
-  }, {
-    reduce_data_format: false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/departmental_processing_statistics_list_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 部门办件列表明细
  * @param {object} params
  */
 export const departmentOrderList = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/departmental_processing_statistics_details_list`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/departmental_processing_statistics_details_list`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 部门办件列表明细导出
  * @param {object} data
  */
 export const departmentOrderListExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/departmental_processing_statistics_details_list_export`,
-    method: 'post',
-    data,
-    responseType: 'blob'
-  }, {
-    reduce_data_format: false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/departmental_processing_statistics_details_list_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 部门办件统计表子级部门
  * @param {object} params
  */
 export const departmentOrderOrg = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/departmental_processing_child_statistics`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/departmental_processing_child_statistics`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 部门办件统计表子级部门导出
  * @param {object} data
  */
 export const departmentOrderOrgExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/departmental_processing_child_statistics_export`,
-    method: 'post',
-    data,
-    responseType: 'blob'
-  }, {
-    reduce_data_format: false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/departmental_processing_child_statistics_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 二次办理统计
  * @param {object} params
  */
 export const departmentSecond = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/secondary_handling_report`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/secondary_handling_report`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 二次办理统计导出
  * @param {object} data
  */
 export const departmentSecondExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/secondary_handling_report/_export`,
-    method: 'post',
-    data,
-    responseType: 'blob',
-  },{
-    reduce_data_format:false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/secondary_handling_report/_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 二次办理统计明细
  * @param {object} params
  */
 export const departmentSecondDetail = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/secondary_handling_detail_report`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/secondary_handling_detail_report`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 二次办理统计明细导出
  * @param {object} data
  */
 export const departmentSecondDetailExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/secondary_handling_detail_report/_export`,
-    method: 'post',
-    data,
-    responseType: 'blob',
-  },{
-    reduce_data_format:false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/secondary_handling_detail_report/_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 二次办理满意度统计
  * @param {object} params
  */
 export const departmentSecondSatisfaction = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/secondary_handling_satisfaction_report`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/secondary_handling_satisfaction_report`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 二次办理满意度统计导出
  * @param {object} data
  */
 export const departmentSecondSatisfactionExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/secondary_handling_satisfaction_report/_export`,
-    method: 'post',
-    data,
-    responseType: 'blob',
-  },{
-    reduce_data_format:false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/secondary_handling_satisfaction_report/_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 二次办理满意度统计明细
  * @param {object} params
  */
 export const departmentSecondSatisfactionDetail = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/secondary_handling_satisfaction_detail_report`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/secondary_handling_satisfaction_detail_report`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 二次办理满意度统计明细导出
  * @param {object} data
  */
 export const departmentSecondSatisfactionDetailExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/secondary_handling_satisfaction_detail_report/_export`,
-    method: 'post',
-    data,
-    responseType: 'blob',
-  },{
-    reduce_data_format:false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/secondary_handling_satisfaction_detail_report/_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
 /**
  * @description 部门未签收统计
  * @param {object} params
  */
 export const departmentUnSign = (params: object) => {
-  return request({
-    url: `/api/v1/BiOrder/unsigned_order_report`,
-    method: 'get',
-    params,
-  });
-}
+	return request({
+		url: `/api/v1/BiOrder/unsigned_order_report`,
+		method: 'get',
+		params,
+	});
+};
 /**
  * @description 部门未签收统计导出
  * @param {object} data
  */
 export const departmentUnSignExport = (data: object) => {
-  return request({
-    url: `/api/v1/BiOrder/unsigned_order_report/_export`,
-    method: 'post',
-    data,
-    responseType: 'blob',
-  },{
-    reduce_data_format:false
-  });
-}
+	return request(
+		{
+			url: `/api/v1/BiOrder/unsigned_order_report/_export`,
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};

+ 36 - 0
src/api/statistics/knowledge.ts

@@ -27,4 +27,40 @@ export const knowledgeExport = (data: object) => {
     },{
         reduce_data_format:false
     });
+}
+/**
+ * @description 知识库类型引用
+ * @param {object} params
+ */
+export const centerKnowledgeType = (params: object) => {
+    return request({
+        url: `/api/v1/BiOrder/query_knowledge_quote_list`,
+        method: 'get',
+        params,
+    });
+}
+/**
+ * @description 知识库类型引用导出
+ * @param {object} data
+ */
+export const centerKnowledgeTypeExport = (data: object) => {
+    return request({
+        url: `/api/v1/BiOrder/query_knowledge_quote_list/export`,
+        method: 'post',
+        data,
+        responseType: 'blob',
+    }, {
+        reduce_data_format: false
+    });
+}
+/**
+ * @description 根据知识库引用查询工单
+ * @param {object} params
+ */
+export const centerKnowledgeTypeQuery = (params: object) => {
+    return request({
+        url: `/api/v1/BiOrder/get_query_knowledge_quote_order_list`,
+        method: 'get',
+        params,
+    });
 }

+ 63 - 0
src/api/tels/uploadRecord.ts

@@ -0,0 +1,63 @@
+/*
+ * @Author: zc
+ * @description 话务管理 - 上传录音
+ */
+
+import request from '@/utils/request';
+import qs from 'qs';
+
+/**
+ * @description 获取录音列表
+ * @param {object} params
+ * @return {*}
+ */
+export const uploadRecordList = (params?: object) => {
+	return request({
+		url: '/api/v1/File/getaudiofileslist',
+		method: 'get',
+		params,
+	});
+};
+/**
+ * @description 导出录音列表
+ * @param {object} data
+ * @return {*}
+ */
+export const uploadRecordExport = (data: object) => {
+	return request(
+		{
+			url: '/api/v1/File/getaudiofileslist/export',
+			method: 'post',
+			data,
+			responseType: 'blob',
+		},
+		{
+			reduce_data_format: false,
+		}
+	);
+};
+/**
+ * @description 保存录音
+ * @param {object} data
+ * @return {*}
+ */
+export const uploadRecordSave = (data: object) => {
+	return request({
+		url: '/api/v1/File/adduploadaudiofiles',
+		method: 'post',
+		data,
+	});
+};
+/**
+ * @description 删除录音
+ * @param {object} params
+ * @return {*}
+ */
+export const uploadRecordDelete = (params: object) => {
+	return request({
+		url: '/api/v1/File/deleteuploadaudiofiles',
+		method: 'get',
+		params,
+		paramsSerializer: (params: any) => qs.stringify(params),
+	});
+};

+ 141 - 0
src/components/OrderDetail/History.vue

@@ -0,0 +1,141 @@
+<template>
+	<el-form :model="state.queryParams" ref="queryParamsRef" inline @submit.native.prevent>
+		<el-form-item label="关键词" prop="Keyword">
+			<el-input v-model="state.queryParams.Keyword" placeholder="工单标题/工单编码" clearable @keyup.enter="handleQuery" class="keyword-input" />
+		</el-form-item>
+		<el-form-item>
+			<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+			<el-button @click="resetQuery(queryParamsRef)" :loading="state.loading" class="default-button">
+				<SvgIcon name="ele-Refresh" class="mr5" />重置
+			</el-button>
+		</el-form-item>
+	</el-form>
+	<!--	<vxe-toolbar
+		ref="toolbarRef"
+		:loading="state.loading"
+		custom
+		:refresh="{
+			queryMethod: handleQuery,
+		}"
+	>
+	</vxe-toolbar>-->
+	<vxe-table
+		border
+		:loading="state.loading"
+		:data="state.tableData"
+		:column-config="{ resizable: true }"
+		:row-config="{ isCurrent: true, isHover: true, height: 30, useKey: true }"
+		ref="tableRef"
+		show-overflow
+		:scrollY="{ enabled: true, gt: 100 }"
+		:max-height="500"
+	>
+		<vxe-column field="no" title="工单编码" width="140"></vxe-column>
+		<vxe-column field="currentStepName" title="当前节点" width="100"></vxe-column>
+		<vxe-column field="isScreen" title="甄别状态" width="100">
+			<template #default="{ row }">
+				<el-text :type="row.isScreen ? 'danger' : 'info'">{{ row.isScreen ? '已甄别' : '-' }}</el-text>
+			</template>
+		</vxe-column>
+		<vxe-column field="title" title="工单标题" min-width="150">
+			<template #default="{ row }">
+				<order-detail :order="row" @updateList="searchHistory">{{ row.title }}</order-detail>
+			</template>
+		</vxe-column>
+		<vxe-column field="statusText" title="状态" width="100"></vxe-column>
+		<vxe-column field="actualHandleOrgName" title="接办部门" width="140"></vxe-column>
+	</vxe-table>
+	<pagination
+		@pagination="searchHistory"
+		:total="state.total"
+		v-model:current-page="state.queryParams.PageIndex"
+		v-model:page-size="state.queryParams.PageSize"
+	/>
+</template>
+<script setup lang="ts" name="orderDetailHistory">
+import { reactive, ref, defineAsyncComponent, onMounted } from 'vue';
+import { FormInstance } from 'element-plus';
+import { throttle } from '@/utils/tools';
+import { historyOrder } from '@/api/business/order';
+import { useRoute } from 'vue-router';
+
+const pagination = defineAsyncComponent(() => import('@/components/ProTable/components/Pagination.vue')); // 分页
+const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
+
+const props = defineProps({
+	orderId: {
+		type: String,
+		default: '',
+	},
+	ruleForm: {
+		// 表单填写的数据
+		type: Object,
+		default: () => {
+			return {};
+		},
+	},
+	readonly: {
+		//只读  不允许操作
+		type: Boolean,
+		default: false,
+	},
+});
+const state = reactive<any>({
+	tableData: [], // 历史工单
+	total: 0, // 历史工单总条数
+	queryParams: {
+		PageIndex: 1, // 当前页
+		PageSize: 10, // 每页条数
+		Keyword: null, // 关键字
+	},
+	loading: false,
+});
+const queryParamsRef = ref<RefType>(); // 历史工单查询参数
+const multipleSelection = ref<any[]>([]); // 重复件表格选中项
+/** 搜索按钮操作 */
+const handleQuery = throttle(() => {
+	state.queryParams.PageIndex = 1;
+	searchHistory();
+}, 500);
+/** 重置按钮操作 */
+const resetQuery = throttle((formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	handleQuery();
+}, 300);
+/** 获取历史工单 */
+const searchHistory = throttle(async () => {
+	if (!props.ruleForm.contact) return;
+	state.loading = true;
+	let request = {
+		...state.queryParams,
+		PhoneNo: props.ruleForm.contact,
+		OrderId: props.orderId, //传入id 排除重复工单选择自己
+	};
+	try {
+		const response = await historyOrder(request);
+		state.tableData = response?.result.items ?? [];
+		state.total = response?.result.total;
+		state.loading = false;
+	} catch (error) {
+		state.loading = false;
+	}
+}, 300);
+/*const toolbarRef = ref<RefType>();
+const tableRef = ref<RefType>();
+onMounted(() => {
+	if (tableRef.value && toolbarRef.value) {
+		tableRef.value.connect(toolbarRef.value);
+	}
+});*/
+const route = useRoute();
+onMounted(() => {
+	if (route.query.createBy || route.query.createBy === 'tel' || route.query.createBy === 'transfer') {
+		searchHistory();
+	}
+});
+defineExpose({
+	multipleSelection,
+	searchHistory,
+});
+</script>

+ 31 - 2
src/components/OrderDetail/index.vue

@@ -230,6 +230,13 @@
 									<annex-list name="附件列表" readonly :businessId="state.ruleForm.id" classify="查看附件" v-model="state.ruleForm.files" />
 								</el-form-item>
 							</el-col>
+							<template v-if="state.ruleForm.knowledgeQuote && state.ruleForm.knowledgeQuote.length">
+								<el-col v-for="item in state.ruleForm.knowledgeQuote" :key="item.id">
+									<el-form-item label="引用知识">
+										<el-button link type="primary" @click="showKnowledge(item)">{{ item.value }}</el-button>
+									</el-form-item>
+								</el-col>
+							</template>
 						</el-row>
 					</el-form>
 				</div>
@@ -306,6 +313,15 @@
 							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-if="state.ruleForm.provinceRevokeString">
 								<el-form-item label="省件撤单" class="formatted-text color-danger"> {{ state.ruleForm.provinceRevokeString }} </el-form-item>
 							</el-col>
+							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-if="state.ruleForm.provinceReTransactNum > 1">
+								<el-form-item label="省件重办" class="formatted-text color-danger"> {{ state.ruleForm.caseProcessTypeText }} </el-form-item>
+							</el-col>
+							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-if="state.ruleForm.provinceScreenString">
+								<el-form-item label="省件甄别" class="formatted-text color-danger"> {{ state.ruleForm.provinceScreenString }} </el-form-item>
+							</el-col>
+							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-if="state.ruleForm.provinceDelayString">
+								<el-form-item label="省件延期" class="formatted-text color-danger"> {{ state.ruleForm.provinceDelayString }} </el-form-item>
+							</el-col>
 							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-if="state.ruleForm.sendBackOpinion">
 								<el-form-item label="退回意见" class="formatted-text"> {{ state.ruleForm.sendBackOpinion }} </el-form-item>
 							</el-col>
@@ -409,7 +425,7 @@
 		</el-collapse>
 		<!-- 历史工单 -->
 		<div v-show="state.activeName === '1'">
-			<history-order :ruleForm="state.ruleForm" :orderId="state.orderId" ref="historyOrderRef" readonly :maxHeight="500" />
+			<history-order :ruleForm="state.ruleForm" :orderId="state.orderId" ref="historyOrderRef" />
 		</div>
 		<!-- 回访详情 -->
 		<div v-show="state.activeName === '2'">
@@ -708,6 +724,7 @@ import { callCenterOutbound } from '@/utils/callCenter';
 import { useUserInfo } from '@/stores/userInfo';
 import { storeToRefs } from 'pinia';
 import { useThemeConfig } from '@/stores/themeConfig';
+import { useRouter } from 'vue-router';
 
 // 引入组件
 const OrderExpandDetail = defineAsyncComponent(() => import('@/views/business/order/components/Order-expand-detail.vue')); // 扩展信息
@@ -718,7 +735,7 @@ const OrderRepeat = defineAsyncComponent(() => import('@/views/business/order/co
 const AuditRecord = defineAsyncComponent(() => import('@/components/AuditRecord/index.vue')); // 流程明细
 const AnnexList = defineAsyncComponent(() => import('@/components/AnnexList/index.vue')); // 附件列表
 const ProcessAudit = defineAsyncComponent(() => import('@/components/ProcessAudit/index.vue')); // 流程审批
-const HistoryOrder = defineAsyncComponent(() => import('@/views/todo/seats/accept/History.vue')); // 历史工单
+const HistoryOrder = defineAsyncComponent(() => import('@/components/OrderDetail/History.vue')); // 历史工单
 const CitizenPortrait = defineAsyncComponent(() => import('@/views/todo/seats/accept/Citizen-portrait.vue')); // 市民画像
 const SpecialHandleOrder = defineAsyncComponent(() => import('@/views/business/special/components/Special-apply-order.vue')); // 特提申请
 const PlayRecord = defineAsyncComponent(() => import('@/components/PlayRecord/index.vue')); // 播放录音
@@ -1199,6 +1216,18 @@ const onOrderDetail = () => {
 const isTelSource = computed(() => {
 	return state.ruleForm?.sourceChannelCode === 'RGDH';
 });
+// 查看引用知识
+const router = useRouter();
+const showKnowledge = (row: any) => {
+	closeDialog();
+	router.push({
+		name: 'knowledgePreview',
+		params: {
+			id: row.key,
+			tagsViewName: row.value,
+		},
+	});
+};
 // 暴露变量
 defineExpose({
 	openDialog,

+ 1 - 1
src/components/PlayRecord/index.vue

@@ -127,7 +127,7 @@ const playRecordPath = async (path: string) => {
 		popup.document.write(`
 			<html>
 				<head>
-					<title>智能回访录音</title>
+					<title>播放录音</title>
 					<style>
 						body,html {
 						 margin: 0;

+ 1 - 1
src/views/business/delay/audit.vue

@@ -44,7 +44,7 @@
 					}"
 					showHeaderOverflow
 				>
-					<vxe-column field="order.expiredStatusText" title="超期状态" width="90" align="center">
+					<vxe-column field="order.expiredStatusText" title="状态" width="60" align="center">
 						<template #default="{ row }">
 							<span :class="'overdue-status-' + row.order?.expiredStatus" :title="row.order?.expiredStatusText"></span>
 						</template>

+ 2 - 2
src/views/business/delay/index.vue

@@ -56,14 +56,14 @@
 					auto-resize
 					show-overflow
 					:print-config="{}"
-					:scrollY="{ enabled: true, gt: 100  }"
+					:scrollY="{ enabled: true, gt: 100 }"
 					id="orderDelay"
 					:custom-config="{
 						storage: true,
 					}"
 					showHeaderOverflow
 				>
-					<vxe-column field="order.expiredStatusText" title="超期状态" width="90" align="center">
+					<vxe-column field="order.expiredStatusText" title="状态" width="60" align="center">
 						<template #default="{ row }">
 							<span :class="'overdue-status-' + row.order?.expiredStatus" :title="row.order?.expiredStatusText"></span>
 						</template>

+ 5 - 0
src/views/business/discern/YBApply.vue

@@ -57,6 +57,11 @@
 					:params="{ exportMethod: screenApplyListExport, exportParams: requestParams }"
 				>
 					<vxe-column type="checkbox" width="50" align="center"></vxe-column>
+					<vxe-column field="order.expiredStatusText" title="状态" width="60" align="center">
+						<template #default="{ row }">
+							<span :class="'overdue-status-' + row.order?.expiredStatus" :title="row.order?.expiredStatusText"></span>
+						</template>
+					</vxe-column>
 					<vxe-column field="screenSendBackText" title="甄别退回" width="90"></vxe-column>
 					<vxe-column field="order.no" title="工单编码" width="140"></vxe-column>
 					<vxe-column field="order.isProvinceText" title="省/市工单" width="90"></vxe-column>

+ 5 - 0
src/views/business/discern/ZGApply.vue

@@ -61,6 +61,11 @@
 					:params="{ exportMethod: screenApplyListExport, exportParams: requestParams }"
 				>
 					<vxe-column type="checkbox" width="50" align="center"></vxe-column>
+					<vxe-column field="order.expiredStatusText" title="状态" width="60" align="center">
+						<template #default="{ row }">
+							<span :class="'overdue-status-' + row.order?.expiredStatus" :title="row.order?.expiredStatusText"></span>
+						</template>
+					</vxe-column>
 					<vxe-column field="screenByEndTime" title="截止申请日期" width="160" sortable>
 						<template #default="{ row }">
 							{{ formatDate(row.screenByEndTime, 'YYYY-mm-dd HH:MM:SS') }}

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

@@ -85,6 +85,11 @@
 					:params="{ exportMethod: screenListExport, exportParams: requestParams }"
 				>
 					<vxe-column type="checkbox" width="50" align="center"></vxe-column>
+					<vxe-column field="order.expiredStatusText" title="状态" width="90" align="center">
+						<template #default="{ row }">
+							<span :class="'overdue-status-' + row.order?.expiredStatus" :title="row.order?.expiredStatusText"></span>
+						</template>
+					</vxe-column>
 					<vxe-column field="statusText" title="甄别状态" width="100"></vxe-column>
 					<vxe-column field="workflow.actualHandleStepName" title="当前审核节点" width="120"></vxe-column>
 					<vxe-column field="order.no" title="工单编码" width="140"></vxe-column>

+ 5 - 0
src/views/business/discern/todo.vue

@@ -75,6 +75,11 @@
 					:params="{ exportMethod: screenListExport, exportParams: requestParams }"
 				>
 					<vxe-column type="checkbox" width="50" align="center"></vxe-column>
+					<vxe-column field="order.expiredStatusText" title="状态" width="60" align="center">
+						<template #default="{ row }">
+							<span :class="'overdue-status-' + row.order?.expiredStatus" :title="row.order?.expiredStatusText"></span>
+						</template>
+					</vxe-column>
 					<vxe-column field="statusText" title="甄别状态" width="100"></vxe-column>
 					<vxe-column field="screenSendBackApply" title="重提甄别" width="90" v-if="state.queryParams.TabStatus === 0"></vxe-column>
 					<vxe-column field="order.no" title="工单编码" width="140"></vxe-column>

+ 1 - 0
src/views/knowledge/browse/index.vue

@@ -91,6 +91,7 @@
 						>
 							<vxe-column field="knowledgeTitle" title="标题" min-width="200"></vxe-column>
 							<vxe-column field="creatorName" title="浏览人" min-width="120"></vxe-column>
+							<vxe-column field="browseTime" title="浏览时长(分)" min-width="150"></vxe-column>
 							<vxe-column field="creationTime" title="浏览时间" width="160">
 								<template #default="{ row }">
 									{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}

+ 200 - 0
src/views/statistics/call/detailSeatsMoth.vue

@@ -0,0 +1,200 @@
+<template>
+	<div class="statistics-call-seats-moth-detail-container layout-padding">
+		<div class="layout-padding-auto layout-padding-view pd20">
+			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
+				<el-form-item label="坐席" prop="Role">
+					<el-select-v2
+						v-model="state.queryParams.Role"
+						filterable
+						:options="state.roleOptions"
+						:props="{
+							label: 'displayName',
+							value: 'id',
+						}"
+						placeholder="请选择坐席"
+						clearable
+						@change="handleQuery"
+					/>
+				</el-form-item>
+				<el-form-item label="主叫号码" prop="AcceptorName">
+					<el-input v-model.trim="state.queryParams.AcceptorName" placeholder="主叫号码" clearable @keyup.enter="handleQuery" class="keyword-input" />
+				</el-form-item>
+				<el-form-item label="被叫号码" prop="AcceptorName">
+					<el-input v-model.trim="state.queryParams.AcceptorName" placeholder="被叫号码" clearable @keyup.enter="handleQuery" class="keyword-input" />
+				</el-form-item>
+				<el-form-item>
+					<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+					<!--					<el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
+						<SvgIcon name="ele-Refresh" class="mr5" />重置
+					</el-button>-->
+					<el-button @click="drawer = true" class="default-button"> <SvgIcon name="ele-Search" class="mr5" />更多查询</el-button>
+				</el-form-item>
+			</el-form>
+			<vxe-toolbar
+				ref="toolbarRef"
+				:loading="state.loading"
+				custom
+				:refresh="{
+					queryMethod: handleQuery,
+				}"
+				:tools="[{ toolRender: { name: 'exportAll' } }]"
+			>
+			</vxe-toolbar>
+			<div style="overflow: hidden; width: 100%; height: 100%; flex: 1">
+				<vxe-table
+					border
+					:loading="state.loading"
+					:data="state.tableData"
+					:column-config="{ resizable: true }"
+					:row-config="{ isCurrent: true, isHover: true, height: 30, useKey: true }"
+					ref="tableRef"
+					height="auto"
+					auto-resize
+					:scrollY="{ enabled: true, gt: 100 }"
+					show-overflow
+					id="statisticsOrderCenter"
+					:custom-config="{ storage: true }"
+					show-footer
+					:footer-method="footerMethod"
+					:params="{ exportMethod: centerListExport, exportParams: requestParams }"
+					:sort-config="{ remote: true }"
+					@sort-change="sortChange"
+				>
+					<vxe-column field="userName" title="主叫号码"></vxe-column>
+					<vxe-column field="invalid" title="被叫号码"> </vxe-column>
+					<vxe-column field="repeat" title="振铃开始时间"></vxe-column>
+					<vxe-column field="subtotal" title="接通时间"></vxe-column>
+					<vxe-column field="subtotal" title="响应分机"></vxe-column>
+					<vxe-column field="subtotal" title="坐席"></vxe-column>
+				</vxe-table>
+			</div>
+		</div>
+		<!--	更多查询	-->
+		<el-drawer v-model="drawer" title="更多查询" size="500px">
+			<el-form :model="state.queryParams" ref="drawerRuleFormRef" @submit.native.prevent label-width="100px">
+				<el-form-item label="响应分机" prop="AcceptorName">
+					<el-input v-model.trim="state.queryParams.AcceptorName" placeholder="响应分机" clearable @keyup.enter="handleQuery" />
+				</el-form-item>
+				<el-form-item label="接通时间" prop="jtTime">
+					<el-date-picker
+						v-model="state.queryParams.jtTime"
+						type="datetimerange"
+						unlink-panels
+						range-separator="至"
+						start-placeholder="开始时间"
+						end-placeholder="结束时间"
+						:shortcuts="shortcuts"
+						@change="handleQuery"
+						value-format="YYYY-MM-DD[T]HH:mm:ss"
+						:default-time="defaultTimeStartEnd"
+					/>
+				</el-form-item>
+				<el-form-item label="振铃开始时间" prop="zlTime">
+					<el-date-picker
+						v-model="state.queryParams.zlTime"
+						type="datetimerange"
+						unlink-panels
+						range-separator="至"
+						start-placeholder="开始时间"
+						end-placeholder="结束时间"
+						:shortcuts="shortcuts"
+						@change="handleQuery"
+						value-format="YYYY-MM-DD[T]HH:mm:ss"
+						:default-time="defaultTimeStartEnd"
+					/>
+				</el-form-item>
+			</el-form>
+			<template #footer>
+				<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+				<el-button @click="resetQuery(drawerRuleFormRef)" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+			</template>
+		</el-drawer>
+	</div>
+</template>
+<script setup lang="tsx" name="statisticsCallSeatsMothDetail">
+import { onMounted, reactive, ref } from 'vue';
+import { FormInstance } from 'element-plus';
+import { centerList, centerListExport } from '@/api/statistics/order';
+import { defaultDate, defaultTimeStartEnd, shortcuts } from '@/utils/constants';
+import Other from '@/utils/other';
+import XEUtils from 'xe-utils';
+
+// 定义变量内容
+const state = reactive<any>({
+	queryParams: {
+		// 查询条件
+		Keyword: null, // 关键词
+		crTime: defaultDate,
+		SortField: null,
+		SortRule: null,
+		jtTime: [],
+		zlTime: [],
+	},
+	tableData: [], //表单
+	loading: false, // 加载
+	total: 0, // 总数
+	roleOptions: [],
+});
+/** 搜索按钮操作 */
+const handleQuery = () => {
+	// state.queryParams.PageIndex = 1;
+	queryList();
+};
+/** 获取列表 */
+const requestParams = ref<EmptyObjectType>({});
+const queryList = () => {
+	state.loading = true;
+	requestParams.value = Other.deepClone(state.queryParams);
+	requestParams.value.StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
+	requestParams.value.EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+	Reflect.deleteProperty(requestParams.value, 'crTime');
+	centerList(requestParams.value)
+		.then((res: any) => {
+			state.tableData = res.result;
+			state.loading = false;
+		})
+		.catch(() => {
+			state.loading = false;
+		});
+};
+// 排序
+const sortChange = (val: any) => {
+	state.queryParams.SortField = val.order ? val.field : null;
+	// 0 升序 1 降序
+	state.queryParams.SortRule = val.order ? (val.order == 'desc' ? 1 : 0) : null;
+	queryList();
+};
+/** 重置按钮操作 */
+const drawerRuleFormRef = ref();
+const ruleFormRef = ref<RefType>(); // 表单ref
+const drawer = ref(false);
+const statisticalTimeRef = ref<RefType>();
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	statisticalTimeRef.value.reset();
+	ruleFormRef.value?.resetFields();
+	queryList();
+};
+// 计算合计
+const footerMethod = ({ columns, data }) => {
+	return [
+		columns.map((column: any, columnIndex: number) => {
+			if (columnIndex === 0) {
+				return '合计';
+			}
+			if (['centreArchive', 'centreCareOf', 'noCentreCareOf', 'invalid', 'repeat', 'subtotal'].includes(column.property)) {
+				return XEUtils.sum(data, column.property);
+			}
+		}),
+	];
+};
+const toolbarRef = ref<RefType>();
+const tableRef = ref<RefType>();
+onMounted(() => {
+	queryList();
+	if (tableRef.value && toolbarRef.value) {
+		tableRef.value.connect(toolbarRef.value);
+	}
+});
+</script>

+ 168 - 0
src/views/statistics/call/seatsMoth.vue

@@ -0,0 +1,168 @@
+<template>
+	<div class="statistics-call-seats-moth-container layout-padding">
+		<div class="layout-padding-auto layout-padding-view pd20">
+			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
+				<el-form-item label="坐席" prop="Role">
+					<el-select-v2
+						v-model="state.queryParams.Role"
+						filterable
+						:options="state.roleOptions"
+						:props="{
+							label: 'displayName',
+							value: 'id',
+						}"
+						placeholder="请选择坐席"
+						clearable
+						@change="handleQuery"
+					/>
+				</el-form-item>
+				<el-form-item prop="crTime">
+					<statistical-time v-model="state.queryParams.crTime" @change="handleQuery" ref="statisticalTimeRef" :disabled="state.loading" />
+				</el-form-item>
+				<el-form-item>
+					<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+					<el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
+						<SvgIcon name="ele-Refresh" class="mr5" />重置
+					</el-button>
+				</el-form-item>
+			</el-form>
+			<vxe-toolbar
+				ref="toolbarRef"
+				:loading="state.loading"
+				custom
+				:refresh="{
+					queryMethod: handleQuery,
+				}"
+				:tools="[{ toolRender: { name: 'exportAll' } }]"
+			>
+				<template #buttons>
+					<el-button type="primary" @click="onLink">通话时段明细</el-button>
+				</template>
+			</vxe-toolbar>
+			<div style="overflow: hidden; width: 100%; height: 100%; flex: 1">
+				<vxe-table
+					border
+					:loading="state.loading"
+					:data="state.tableData"
+					:column-config="{ resizable: true }"
+					:row-config="{ isCurrent: true, isHover: true, height: 30, useKey: true }"
+					ref="tableRef"
+					height="auto"
+					auto-resize
+					:scrollY="{ enabled: true, gt: 100 }"
+					show-overflow
+					id="statisticsOrderCenter"
+					:custom-config="{ storage: true }"
+					show-footer
+					:footer-method="footerMethod"
+					:params="{ exportMethod: centerListExport, exportParams: requestParams }"
+					:sort-config="{ remote: true }"
+					@sort-change="sortChange"
+				>
+					<vxe-column field="userName" title="坐席"></vxe-column>
+					<vxe-column title="呼入总量" field="centreArchive" sortable></vxe-column>
+					<vxe-column title="呼入总量" field="centreCareOf" sortable></vxe-column>
+					<vxe-column title="有效接通量" field="noCentreCareOf" sortable></vxe-column>
+					<vxe-column title="接通秒挂量" field="noCentreCareOf" sortable></vxe-column>
+					<vxe-column title="超时接通量" field="noCentreCareOf" sortable></vxe-column>
+					<vxe-column title="按时接通量" field="noCentreCareOf" sortable></vxe-column>
+					<vxe-column title="呼入未接通总量" field="noCentreCareOf" sortable></vxe-column>
+					<vxe-column title="未接通秒挂量" field="noCentreCareOf" sortable></vxe-column>
+					<vxe-column title="超时未接通量" field="noCentreCareOf" sortable></vxe-column>
+					<vxe-column title="接通率" field="noCentreCareOf" sortable></vxe-column>
+				</vxe-table>
+			</div>
+		</div>
+	</div>
+</template>
+<script setup lang="tsx" name="statisticsCallSeatsMoth">
+import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
+import { FormInstance } from 'element-plus';
+import { centerList, centerListExport } from '@/api/statistics/order';
+import { defaultDate } from '@/utils/constants';
+import Other from '@/utils/other';
+import XEUtils from 'xe-utils';
+import { useRouter } from 'vue-router';
+
+const StatisticalTime = defineAsyncComponent(() => import('@/components/StatisticalTime/index.vue')); // 日期类型选择组件
+// 定义变量内容
+const ruleFormRef = ref<RefType>(); // 表单ref
+const state = reactive<any>({
+	queryParams: {
+		// 查询条件
+		Keyword: null, // 关键词
+		crTime: defaultDate,
+		SortField: null,
+		SortRule: null,
+	},
+	tableData: [], //表单
+	loading: false, // 加载
+	total: 0, // 总数
+	roleOptions: [],
+});
+/** 搜索按钮操作 */
+const handleQuery = () => {
+	// state.queryParams.PageIndex = 1;
+	queryList();
+};
+/** 获取列表 */
+const requestParams = ref<EmptyObjectType>({});
+const queryList = () => {
+	state.loading = true;
+	requestParams.value = Other.deepClone(state.queryParams);
+	requestParams.value.StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
+	requestParams.value.EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+	Reflect.deleteProperty(requestParams.value, 'crTime');
+	centerList(requestParams.value)
+		.then((res: any) => {
+			state.tableData = res.result;
+			state.loading = false;
+		})
+		.catch(() => {
+			state.loading = false;
+		});
+};
+// 排序
+const sortChange = (val: any) => {
+	state.queryParams.SortField = val.order ? val.field : null;
+	// 0 升序 1 降序
+	state.queryParams.SortRule = val.order ? (val.order == 'desc' ? 1 : 0) : null;
+	queryList();
+};
+/** 重置按钮操作 */
+const statisticalTimeRef = ref<RefType>();
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	statisticalTimeRef.value.reset();
+	queryList();
+};
+// 计算合计
+const footerMethod = ({ columns, data }) => {
+	return [
+		columns.map((column: any, columnIndex: number) => {
+			if (columnIndex === 0) {
+				return '合计';
+			}
+			if (['centreArchive', 'centreCareOf', 'noCentreCareOf', 'invalid', 'repeat', 'subtotal'].includes(column.property)) {
+				return XEUtils.sum(data, column.property);
+			}
+		}),
+	];
+};
+const router = useRouter();
+// 跳转明细
+const onLink = () => {
+	router.push({
+		path: '/statistics/call/detailSeatsMoth',
+	});
+};
+const toolbarRef = ref<RefType>();
+const tableRef = ref<RefType>();
+onMounted(() => {
+	queryList();
+	if (tableRef.value && toolbarRef.value) {
+		tableRef.value.connect(toolbarRef.value);
+	}
+});
+</script>

+ 202 - 0
src/views/statistics/center/hotWord.vue

@@ -0,0 +1,202 @@
+<template>
+	<div class="statistics-center-hot-word-container layout-padding">
+		<div class="layout-padding-auto layout-padding-view pd20">
+			<vxe-grid v-bind="gridOptions" v-on="gridEvents" ref="gridRef">
+				<template #form>
+					<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
+						<el-form-item prop="crTime">
+							<statistical-time v-model="state.queryParams.crTime" @change="handleQuery" ref="statisticalTimeRef" :disabled="state.loading" />
+						</el-form-item>
+						<el-form-item label="热词" prop="Keyword">
+							<el-input v-model="state.queryParams.Keyword" placeholder="热词" clearable @keyup.enter="handleQuery" class="keyword-input" />
+						</el-form-item>
+						<el-form-item>
+							<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+							<el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
+								<SvgIcon name="ele-Refresh" class="mr5" />重置
+							</el-button>
+						</el-form-item>
+					</el-form>
+				</template>
+				<template #pager>
+					<pagination
+						@pagination="queryList"
+						:total="state.total"
+						v-model:current-page="state.queryParams.PageIndex"
+						v-model:page-size="state.queryParams.PageSize"
+						:disabled="state.loading"
+					/>
+				</template>
+			</vxe-grid>
+		</div>
+		<el-dialog v-model="state.dialogVisible" width="40%" draggable title="关联工单" append-to-body destroy-on-close>
+			<vxe-table
+				border
+				:loading="state.loading"
+				:data="state.tableData"
+				:column-config="{ resizable: true }"
+				:row-config="{ isCurrent: true, isHover: true, height: 30, useKey: true }"
+				ref="tableRef"
+				max-height="500px"
+				show-overflow
+				:scrollY="{ enabled: true, gt: 100 }"
+				showHeaderOverflow
+			>
+				<vxe-column field="no" title="工单编码" width="140"></vxe-column>
+				<vxe-column field="title" title="工单标题">
+					<template #default="{ row }">
+						<order-detail :order="{ id: row.orderId }" @updateList="queryList">{{ row.title }}</order-detail>
+					</template>
+				</vxe-column>
+			</vxe-table>
+		</el-dialog>
+	</div>
+</template>
+<script setup lang="tsx" name="statisticsCenterHotWord">
+import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
+import { FormInstance } from 'element-plus';
+import { defaultDate } from '@/utils/constants';
+import Other from '@/utils/other';
+import { centerHotWord, centerHotWordExport, centerHotWordQuery } from '@/api/statistics/center';
+
+const StatisticalTime = defineAsyncComponent(() => import('@/components/StatisticalTime/index.vue')); // 日期类型选择组件
+const pagination = defineAsyncComponent(() => import('@/components/ProTable/components/Pagination.vue')); // 分页
+const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
+// 定义变量内容
+const state = reactive<any>({
+	queryParams: {
+		// 查询条件
+		PageIndex: 1,
+		PageSize: 20,
+		Keyword: null, // 关键词
+		crTime: defaultDate, // 时间默认今天开始到今天结束
+		SortField: null,
+		SortRule: 0,
+	},
+	tableData: [], //表单
+	loading: false, // 加载
+	total: 0, // 总数
+	dialogVisible: false,
+});
+
+const requestParams = ref<EmptyObjectType>({});
+const gridOptions = reactive<any>({
+	loading: false,
+	border: true,
+	showOverflow: true,
+	columnConfig: {
+		resizable: true,
+	},
+	scrollY: {
+		enabled: true,
+		gt: 100,
+	},
+	sortConfig: {
+		remote: true,
+	},
+	toolbarConfig: {
+		zoom: true,
+		custom: true,
+		refresh: {
+			queryMethod: () => {
+				handleQuery();
+			},
+		},
+		tools: [{ toolRender: { name: 'exportCurrent' } }, { toolRender: { name: 'exportAll' } }],
+	},
+	customConfig: {
+		storage: true,
+	},
+	id: 'statisticsCenterHotWord',
+	rowConfig: { isHover: true, height: 30, isCurrent: true, useKey: true },
+	height: 'auto',
+	columns: [
+		{
+			field: 'name',
+			title: '热词',
+		},
+		{
+			field: 'countNum',
+			title: '关联工单',
+			slots: {
+				default({ row }) {
+					return (
+						<el-button type="primary" onClick={() => linkDetail(row)} link>
+							{row.countNum}
+						</el-button>
+					);
+				},
+			},
+		},
+	],
+	data: [],
+	params: {
+		exportMethod: centerHotWordExport,
+		exportParams: requestParams,
+	},
+});
+const gridEvents = {
+	sortChange(val: any) {
+		state.queryParams.SortField = val.order ? val.field : null;
+		// 0 升序 1 降序
+		state.queryParams.SortRule = val.order ? (val.order == 'desc' ? 1 : 0) : null;
+		handleQuery();
+	},
+};
+/** 搜索按钮操作 */
+const ruleFormRef = ref<RefType>(); // 表单ref
+const handleQuery = () => {
+	state.queryParams.PageIndex = 1;
+	queryList();
+};
+/** 获取列表 */
+const queryList = () => {
+	state.loading = true;
+	gridOptions.loading = true;
+	requestParams.value = Other.deepClone(state.queryParams);
+	requestParams.value.StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
+	requestParams.value.EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+	Reflect.deleteProperty(requestParams.value, 'crTime');
+	centerHotWord(requestParams.value)
+		.then((res: any) => {
+			state.tableData = res.result?.items ?? [];
+			gridOptions.data = res.result?.items ?? [];
+			state.total = res.result?.total ?? 0;
+			state.loading = false;
+			gridOptions.loading = false;
+		})
+		.catch(() => {
+			state.loading = false;
+			gridOptions.loading = false;
+		});
+};
+/** 重置按钮操作 */
+const statisticalTimeRef = ref<RefType>();
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	statisticalTimeRef.value.reset();
+	queryList();
+};
+// 查看详情
+const linkDetail = async (row: any) => {
+	state.dialogVisible = true;
+	state.loading = true;
+	try {
+		const { result } = await centerHotWordQuery({ KeyWord: row.name });
+		state.tableData = result;
+		state.loading = false;
+	} catch (e) {
+		console.log(e);
+		state.loading = false;
+	}
+};
+const toolbarRef = ref<RefType>();
+const tableRef = ref<RefType>();
+onMounted(() => {
+	queryList();
+	if (tableRef.value && toolbarRef.value) {
+		tableRef.value.connect(toolbarRef.value);
+	}
+});
+</script>

+ 28 - 0
src/views/statistics/department/detailSatisfiedOrg.vue

@@ -100,6 +100,18 @@
 						</template>
 					</vxe-column>
 					<vxe-column field="satisfiedRateText" title="满意率" min-width="120"> </vxe-column>
+					<!--	自贡字段		-->
+					<template v-if="['ZiGong'].includes(themeConfig.appScope)">
+						<vxe-column field="normalCount" title="一般"  min-width="100">
+							<template #default="scope">
+								<el-button type="primary" link @click="linkDetail(scope.row.normalKey, scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
+									{{ scope.row.normalCount }}
+								</el-button>
+								<span v-else>{{ scope.row.normalCount }}</span>
+							</template>
+						</vxe-column>
+						<vxe-column field="normalRateText" title="一般率" min-width="120"> </vxe-column>
+					</template>
 					<vxe-column field="regardedAsSatisfiedCount" title="视为满意"  min-width="100">
 						<template #default="scope">
 							<el-button type="primary" link @click="linkDetail(scope.row.regardedAsSatisfiedKey, scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
@@ -127,6 +139,18 @@
 						</template>
 					</vxe-column>
 					<vxe-column field="noSatisfiedRateText" title="不满意率" min-width="120"> </vxe-column>
+					<!--	自贡字段		-->
+					<template v-if="['ZiGong'].includes(themeConfig.appScope)">
+						<vxe-column field="veryNoSatisfiedCount" title="非常不满意"  min-width="100">
+							<template #default="scope">
+								<el-button type="primary" link @click="linkDetail(scope.row.veryNoSatisfiedKey, scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
+									{{ scope.row.veryNoSatisfiedCount }}
+								</el-button>
+								<span v-else>{{ scope.row.veryNoSatisfiedCount }}</span>
+							</template>
+						</vxe-column>
+						<vxe-column field="veryNoSatisfiedRateText" title="非常不满意率" min-width="120"> </vxe-column>
+					</template>
 					<vxe-column field="noEvaluateCount" title="未作评价"  min-width="100">
 						<template #default="scope">
 							<el-button type="primary" link @click="linkDetail(scope.row.noEvaluateKey, scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
@@ -156,6 +180,8 @@ import { FormInstance } from 'element-plus';
 import { departmentSatisfactionBase, departmentSatisfactionOrg, departmentSatisfactionOrgExport } from '@/api/statistics/department';
 import { useRoute, useRouter } from 'vue-router';
 import XEUtils from 'xe-utils';
+import { useThemeConfig } from '@/stores/themeConfig';
+import { storeToRefs } from 'pinia';
 
 // 定义变量内容
 const ruleFormRef = ref<RefType>(); // 表单ref
@@ -179,6 +205,8 @@ const handleQuery = () => {
 	state.queryParams.PageIndex = 1;
 	queryList();
 };
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
 /** 获取列表 */
 const route = useRoute();
 const routeQueryParams = route.query;

+ 23 - 14
src/views/statistics/department/dpSatisfied.vue

@@ -123,11 +123,6 @@
 		<!--	更多查询	-->
 		<el-drawer v-model="drawer" title="更多查询" size="500px">
 			<el-form :model="state.queryParams" ref="drawerRuleFormRef" @submit.native.prevent label-width="100px">
-				<el-form-item label="办件态度" prop="AttitudeType" v-if="['ZiGong'].includes(themeConfig.appScope)">
-					<el-select v-model="state.queryParams.AttitudeType" placeholder="办件态度" @change="handleQuery">
-						<el-option :value="item.key" v-for="item in state.attitudeType" :key="item.key" :label="item.value"></el-option>
-					</el-select>
-				</el-form-item>
 				<el-form-item label="受理时间" prop="crTime">
 					<el-date-picker
 						v-model="state.queryParams.crTime"
@@ -156,11 +151,22 @@
 				<el-form-item label="回访人姓名" prop="VisitUser">
 					<el-input v-model="state.queryParams.VisitUser" placeholder="回访人姓名" clearable @keyup.enter="handleQuery" />
 				</el-form-item>
-				<el-form-item label="办件结果" prop="OrgProcessingResults">
-					<el-select v-model="state.queryParams.OrgProcessingResults" placeholder="请选择来办件结果" clearable class="w100" @change="handleQuery">
-						<el-option v-for="item in state.visitSatisfaction" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+				<el-form-item label="查询类型" prop="AttitudeType">
+					<el-select v-model="state.queryParams.AttitudeType" placeholder="请选择查询类型" @change="selectType">
+						<el-option v-for="item in state.attitudeType" :value="item.key" :key="item.key" :label="item.value" />
+					</el-select>
+				</el-form-item>
+				<el-form-item label="办件结果" prop="OrgProcessingResults" v-if="state.queryParams.AttitudeType === 1">
+					<el-select v-model="state.queryParams.OrgProcessingResults" placeholder="请选择办件结果" multiple clearable>
+						<el-option  v-for="item in state.visitSatisfaction" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName"></el-option>
 					</el-select>
 				</el-form-item>
+				<el-form-item label="办件态度" prop="OrgProcessingResults" v-if="state.queryParams.AttitudeType === 2">
+					<el-select v-model="state.queryParams.OrgProcessingResults" placeholder="请选择办件态度" multiple clearable>
+						<el-option  v-for="item in state.visitMananer" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName"></el-option>
+					</el-select>
+				</el-form-item>
+
 				<el-form-item label="热点分类" prop="Hotspot">
 					<el-input v-model="state.queryParams.Hotspot" placeholder="热点分类名称" clearable @keyup.enter="handleQuery" />
 				</el-form-item>
@@ -215,8 +221,6 @@ import { formatDate } from '@/utils/formatTime';
 import { defaultDate, defaultTimeStartEnd, shortcuts } from '@/utils/constants';
 import Other from '@/utils/other';
 import {  exportAssignment } from '@/utils/tools';
-import { useThemeConfig } from '@/stores/themeConfig';
-import { storeToRefs } from 'pinia';
 
 // 引入组件
 const VisitDetailCom = defineAsyncComponent(() => import('@/views/business/visit/components/Visit-detail.vue')); // 回访
@@ -224,8 +228,6 @@ const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/
 const StatisticalTime = defineAsyncComponent(() => import('@/components/StatisticalTime/index.vue')); // 日期类型选择组件
 const pagination = defineAsyncComponent(() => import('@/components/ProTable/components/Pagination.vue')); // 分页
 
-const storesThemeConfig = useThemeConfig();
-const { themeConfig } = storeToRefs(storesThemeConfig);
 // 定义变量内容
 const state = reactive<any>({
 	queryParams: {
@@ -233,6 +235,7 @@ const state = reactive<any>({
 		PageIndex: 1,
 		PageSize: 20,
 		hfTime: defaultDate, // 回访事件
+		AttitudeType:1, // 默认办件结果
 		VisitTimeStart: null,
 		VisitTimeEnd: null,
 		crTime: [],
@@ -244,7 +247,6 @@ const state = reactive<any>({
 		VisitUser: null,
 		OrgProcessingResults: null,
 		OrgId: null,
-		AttitudeType: 1,
 		TypeCode: 0,
 		SortField:null,
 		SortRule:null,
@@ -256,6 +258,8 @@ const state = reactive<any>({
 	total: 0, // 总数
 	attitudeType:[],
 	channelOptions:[],
+	visitSatisfaction:[], // 办件结果
+	visitMananer:[], // 办件态度
 });
 // 排序
 const sortChange = (val: any) => {
@@ -264,6 +268,10 @@ const sortChange = (val: any) => {
 	state.queryParams.SortRule = val.order ? (val.order == 'desc' ? 1 : 0) : null;
 	queryList();
 };
+// 选择查询类型
+const selectType = ()=>{
+	drawerRuleFormRef.value.resetFields('OrgProcessingResults');
+}
 /** 搜索按钮操作 */
 const handleQuery = () => {
 	state.queryParams.PageIndex = 1;
@@ -318,7 +326,8 @@ const getBaseData = async () => {
 			visitSatisfaction: 'visitSatisfaction',
 			orgsOptions: 'orgsOptions',
 			attitudeType: 'attitudeType',
-			channelOptions:'channelOptions'
+			channelOptions:'channelOptions',
+			visitMananer:'visitMananer',
 		};
 		for (const key in mappings) {
 			state[key] = res.result?.[mappings[key]] ?? [];

+ 24 - 0
src/views/statistics/department/satisfied.vue

@@ -101,6 +101,18 @@
 						</template>
 					</vxe-column>
 					<vxe-column field="satisfiedRateText" title="满意率" min-width="120"> </vxe-column>
+					<!--	自贡字段		-->
+					<template v-if="['ZiGong'].includes(themeConfig.appScope)">
+						<vxe-column field="normalCount" title="一般"  min-width="100">
+							<template #default="scope">
+								<el-button type="primary" link @click="linkDetail(scope.row.normalKey, scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
+									{{ scope.row.normalCount }}
+								</el-button>
+								<span v-else>{{ scope.row.normalCount }}</span>
+							</template>
+						</vxe-column>
+						<vxe-column field="normalRateText" title="一般率" min-width="120"> </vxe-column>
+					</template>
 					<vxe-column field="regardedAsSatisfiedCount" title="视为满意"  min-width="100">
 						<template #default="scope">
 							<el-button type="primary" link @click="linkDetail(scope.row.regardedAsSatisfiedKey, scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
@@ -128,6 +140,18 @@
 						</template>
 					</vxe-column>
 					<vxe-column field="noSatisfiedRateText" title="不满意率" min-width="120"> </vxe-column>
+					<!--	自贡字段		-->
+					<template v-if="['ZiGong'].includes(themeConfig.appScope)">
+						<vxe-column field="veryNoSatisfiedCount" title="非常不满意"  min-width="100">
+							<template #default="scope">
+								<el-button type="primary" link @click="linkDetail(scope.row.veryNoSatisfiedKey, scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
+									{{ scope.row.veryNoSatisfiedCount }}
+								</el-button>
+								<span v-else>{{ scope.row.veryNoSatisfiedCount }}</span>
+							</template>
+						</vxe-column>
+						<vxe-column field="veryNoSatisfiedRateText" title="非常不满意率" min-width="120"> </vxe-column>
+					</template>
 					<vxe-column field="noEvaluateCount" title="未作评价"  min-width="100">
 						<template #default="scope">
 							<el-button type="primary" link @click="linkDetail(scope.row.noEvaluateKey, scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">

+ 100 - 25
src/views/statistics/department/shSatisfied.vue

@@ -1,9 +1,9 @@
 <template>
 	<div class="statistics-department-sh-satisfied-container layout-padding">
-    <div class="layout-padding-auto layout-padding-view pd20">
+		<div class="layout-padding-auto layout-padding-view pd20">
 			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
 				<el-form-item prop="crTime">
-					<statistical-time v-model="state.queryParams.crTime" @change="handleQuery" ref="statisticalTimeRef" :disabled="state.loading"/>
+					<statistical-time v-model="state.queryParams.crTime" @change="handleQuery" ref="statisticalTimeRef" :disabled="state.loading" />
 				</el-form-item>
 				<el-form-item label="部门名称" prop="OrgName">
 					<el-input v-model="state.queryParams.OrgName" placeholder="部门名称" clearable @keyup.enter="handleQuery" class="keyword-input" />
@@ -26,13 +26,17 @@
 					</el-button>
 					<el-popover :width="500" trigger="click">
 						<template #reference>
-							<el-button type="primary" title="口径说明"><SvgIcon name="ele-QuestionFilled" class="mr5"/>口径说明</el-button>
+							<el-button type="primary" title="口径说明"><SvgIcon name="ele-QuestionFilled" class="mr5" />口径说明</el-button>
 						</template>
 						<el-descriptions title="" :column="1" border style="max-height: 400px; overflow: auto">
 							<el-descriptions-item label="部门名称">办理工单的部门名称</el-descriptions-item>
 							<el-descriptions-item label="部门类别">部门类型</el-descriptions-item>
-							<el-descriptions-item label="小计">(非常满意+满意+默认满意+视为满意)/(非常满意+满意+视为满意+不满意+默认满意+非常不满意)</el-descriptions-item>
-							<el-descriptions-item label="总满意率">(非常满意+满意+视为满意+默认满意)/(非常满意+满意+视为满意+默认满意+不满意)</el-descriptions-item>
+							<el-descriptions-item label="小计"
+								>(非常满意+满意+默认满意+视为满意)/(非常满意+满意+视为满意+不满意+默认满意+非常不满意)</el-descriptions-item
+							>
+							<el-descriptions-item label="总满意率"
+								>(非常满意+满意+视为满意+默认满意)/(非常满意+满意+视为满意+默认满意+不满意)</el-descriptions-item
+							>
 							<el-descriptions-item label="非常满意">已回访-部门评价-办件结果为非常满意</el-descriptions-item>
 							<el-descriptions-item label="非常满意率">非常满意/小计</el-descriptions-item>
 							<el-descriptions-item label="满意">已回访-部门评价-办件结果为满意</el-descriptions-item>
@@ -82,68 +86,136 @@
 					showHeaderOverflow
 					:params="{ exportMethod: departmentSatisfactionExport, exportParams: requestParams }"
 				>
-					<vxe-column field="orgName" title="部门名称" min-width="200" fixed="left">
-					</vxe-column>
+					<vxe-column field="orgName" title="部门名称" min-width="200" fixed="left"> </vxe-column>
 					<vxe-column field="orgTypeText" title="部门类别" min-width="100" fixed="left"> </vxe-column>
 					<vxe-column field="totalSumCount" title="小计" min-width="90" fixed="left"> </vxe-column>
 					<vxe-column field="totalSumRateText" title="总满意率" min-width="120"> </vxe-column>
-					<vxe-column field="verySatisfiedCount" title="非常满意"  min-width="100">
+					<vxe-column field="verySatisfiedCount" title="非常满意" min-width="100">
 						<template #default="scope">
-							<el-button type="primary" link @click="linkDetail('verySatisfiedCount', scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
+							<el-button
+								type="primary"
+								link
+								@click="linkDetail('verySatisfiedCount', scope.row)"
+								v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)"
+							>
 								{{ scope.row.verySatisfiedCount }}
 							</el-button>
 							<span v-else>{{ scope.row.verySatisfiedCount }}</span>
 						</template>
 					</vxe-column>
 					<vxe-column field="verySatisfiedRateText" title="非常满意率" min-width="120"> </vxe-column>
-					<vxe-column field="satisfiedCount" title="满意"  min-width="100">
+					<vxe-column field="satisfiedCount" title="满意" min-width="100">
 						<template #default="scope">
-							<el-button type="primary" link @click="linkDetail('satisfiedCount', scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
+							<el-button
+								type="primary"
+								link
+								@click="linkDetail('satisfiedCount', scope.row)"
+								v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)"
+							>
 								{{ scope.row.satisfiedCount }}
 							</el-button>
 							<span v-else>{{ scope.row.satisfiedCount }}</span>
 						</template>
 					</vxe-column>
 					<vxe-column field="satisfiedRateText" title="满意率" min-width="120"> </vxe-column>
-					<vxe-column field="regardedAsSatisfiedCount" title="视为满意"  min-width="100">
+					<!--	自贡字段		-->
+					<template v-if="['ZiGong'].includes(themeConfig.appScope)">
+						<vxe-column field="normalCount" title="一般" min-width="100">
+							<template #default="scope">
+								<el-button
+									type="primary"
+									link
+									@click="linkDetail('normalCount', scope.row)"
+									v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)"
+								>
+									{{ scope.row.normalCount }}
+								</el-button>
+								<span v-else>{{ scope.row.normalCount }}</span>
+							</template>
+						</vxe-column>
+						<vxe-column field="normalRateText" title="一般率" min-width="120"> </vxe-column>
+					</template>
+					<vxe-column field="regardedAsSatisfiedCount" title="视为满意" min-width="100">
 						<template #default="scope">
-							<el-button type="primary" link @click="linkDetail('regardedAsSatisfiedCount', scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
+							<el-button
+								type="primary"
+								link
+								@click="linkDetail('regardedAsSatisfiedCount', scope.row)"
+								v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)"
+							>
 								{{ scope.row.regardedAsSatisfiedCount }}
 							</el-button>
 							<span v-else>{{ scope.row.regardedAsSatisfiedCount }}</span>
 						</template>
 					</vxe-column>
 					<vxe-column field="regardedAsSatisfiedRateText" title="视为满意率" min-width="120"> </vxe-column>
-					<vxe-column field="defaultSatisfiedCount" title="默认满意"  min-width="100">
+					<vxe-column field="defaultSatisfiedCount" title="默认满意" min-width="100">
 						<template #default="scope">
-							<el-button type="primary" link @click="linkDetail('defaultSatisfiedCount', scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
+							<el-button
+								type="primary"
+								link
+								@click="linkDetail('defaultSatisfiedCount', scope.row)"
+								v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)"
+							>
 								{{ scope.row.defaultSatisfiedCount }}
 							</el-button>
 							<span v-else>{{ scope.row.defaultSatisfiedCount }}</span>
 						</template>
 					</vxe-column>
 					<vxe-column field="defaultSatisfiedRateText" title="默认满意率" min-width="120"> </vxe-column>
-					<vxe-column field="noSatisfiedCount" title="不满意"  min-width="100">
+					<vxe-column field="noSatisfiedCount" title="不满意" min-width="100">
 						<template #default="scope">
-							<el-button type="primary" link @click="linkDetail('noSatisfiedCount', scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
+							<el-button
+								type="primary"
+								link
+								@click="linkDetail('noSatisfiedCount', scope.row)"
+								v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)"
+							>
 								{{ scope.row.noSatisfiedCount }}
 							</el-button>
 							<span v-else>{{ scope.row.defaultSatisfiedCount }}</span>
 						</template>
 					</vxe-column>
 					<vxe-column field="noSatisfiedRateText" title="不满意率" min-width="120"> </vxe-column>
-					<vxe-column field="noEvaluateCount" title="未作评价"  min-width="100">
+					<!--	自贡字段		-->
+					<template v-if="['ZiGong'].includes(themeConfig.appScope)">
+						<vxe-column field="veryNoSatisfiedCount" title="非常不满意" min-width="100">
+							<template #default="scope">
+								<el-button
+									type="primary"
+									link
+									@click="linkDetail('veryNoSatisfiedCount', scope.row)"
+									v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)"
+								>
+									{{ scope.row.veryNoSatisfiedCount }}
+								</el-button>
+								<span v-else>{{ scope.row.veryNoSatisfiedCount }}</span>
+							</template>
+						</vxe-column>
+						<vxe-column field="veryNoSatisfiedRateText" title="非常不满意率" min-width="120"> </vxe-column>
+					</template>
+					<vxe-column field="noEvaluateCount" title="未作评价" min-width="100">
 						<template #default="scope">
-							<el-button type="primary" link @click="linkDetail('noEvaluateCount', scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
+							<el-button
+								type="primary"
+								link
+								@click="linkDetail('noEvaluateCount', scope.row)"
+								v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)"
+							>
 								{{ scope.row.noEvaluateCount }}
 							</el-button>
 							<span v-else>{{ scope.row.noEvaluateCount }}</span>
 						</template>
 					</vxe-column>
 					<vxe-column field="noEvaluateRateText" title="未作评价率" min-width="120"> </vxe-column>
-					<vxe-column field="noPutThroughCount" title="未接通"  min-width="100">
+					<vxe-column field="noPutThroughCount" title="未接通" min-width="100">
 						<template #default="scope">
-							<el-button type="primary" link @click="linkDetail('noPutThroughCount', scope.row)" v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)">
+							<el-button
+								type="primary"
+								link
+								@click="linkDetail('noPutThroughCount', scope.row)"
+								v-if="!['市直合计', '区县合计'].includes(scope.row.orgName)"
+							>
 								{{ scope.row.noPutThroughCount }}
 							</el-button>
 							<span v-else>{{ scope.row.noPutThroughCount }}</span>
@@ -163,7 +235,8 @@ import { defaultDate } from '@/utils/constants';
 import { useRouter } from 'vue-router';
 import { callPeriodBase } from '@/api/statistics/call';
 import Other from '@/utils/other';
-
+import { useThemeConfig } from '@/stores/themeConfig';
+import { storeToRefs } from 'pinia';
 
 const StatisticalTime = defineAsyncComponent(() => import('@/components/StatisticalTime/index.vue')); // 日期类型选择组件
 // 定义变量内容
@@ -174,7 +247,7 @@ const state = reactive<any>({
 		PageIndex: 1,
 		PageSize: 10,
 		OrgName: null,
-    VisitTypeId: '1', //
+		VisitTypeId: '1', //
 		CDPN: null,
 		crTime: defaultDate, // 时间默认今天开始到今天结束
 	},
@@ -184,6 +257,8 @@ const state = reactive<any>({
 	totalCount: {},
 	callForwardingSource: [],
 });
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
 /** 搜索按钮操作 */
 const handleQuery = () => {
 	// state.queryParams.PageIndex = 1;
@@ -216,7 +291,7 @@ const resetQuery = (formEl: FormInstance | undefined) => {
 };
 const router = useRouter();
 // 点击数字
-const linkDetail = (key: string, row:any) => {
+const linkDetail = (key: string, row: any) => {
 	const StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
 	const EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
 	router.push({
@@ -226,7 +301,7 @@ const linkDetail = (key: string, row:any) => {
 			EndTime,
 			OrgId: row.orgId,
 			OrgName: state.queryParams.OrgName,
-      VisitTypeId: state.queryParams.VisitTypeId,
+			VisitTypeId: state.queryParams.VisitTypeId,
 			CDPN: state.queryParams.CDPN,
 			Header: key,
 		},

+ 117 - 92
src/views/statistics/knowledge/data.vue

@@ -1,67 +1,33 @@
 <template>
 	<div class="statistics-knowledge-data-container layout-padding">
 		<div class="layout-padding-auto layout-padding-view pd20">
-			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
-				<el-form-item prop="crTime">
-					<statistical-time v-model="state.queryParams.crTime" @change="handleQuery" ref="statisticalTimeRef" :disabled="state.loading" />
-				</el-form-item>
-				<el-form-item label="部门名称" prop="Keyword">
-					<el-input v-model="state.queryParams.Keyword" placeholder="部门名称" clearable @keyup.enter="handleQuery" class="keyword-input" />
-				</el-form-item>
-				<el-form-item>
-					<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
-					<el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
-						<SvgIcon name="ele-Refresh" class="mr5" />重置
-					</el-button>
-				</el-form-item>
-			</el-form>
-			<vxe-toolbar
-				ref="toolbarRef"
-				:loading="state.loading"
-				custom
-				:refresh="{
-					queryMethod: handleQuery,
-				}"
-				:tools="[{ toolRender: { name: 'exportCurrent' } }, { toolRender: { name: 'exportAll' } }]"
-			>
-			</vxe-toolbar>
-			<div style="overflow: hidden; width: 100%; height: 100%; flex: 1">
-				<vxe-table
-					border
-					:loading="state.loading"
-					:data="state.tableData"
-					:column-config="{ resizable: true }"
-					:row-config="{ isCurrent: true, isHover: true, height: 30, useKey: true }"
-					ref="tableRef"
-					height="auto"
-					auto-resize
-					show-overflow
-					:scrollY="{ enabled: true, gt: 100 }"
-					id="statisticsKnowledgeData"
-					:custom-config="{ storage: true }"
-					showHeaderOverflow
-					:params="{ exportMethod: knowledgeExport, exportParams: requestParams }"
-					:sort-config="{ remote: true }"
-					@sort-change="sortChange"
-				>
-					<vxe-column field="orgName" title="部门名称"></vxe-column>
-					<vxe-column field="orgTypeText" title="部门类型"></vxe-column>
-					<vxe-column field="addNum" title="新增数量" sortable></vxe-column>
-					<vxe-column field="deleteNum" title="删除数量" sortable></vxe-column>
-					<vxe-column field="publicNum" title="公开数量" sortable></vxe-column>
-					<vxe-colgroup title="修改">
-						<vxe-column title="退回数量" field="sendBackNum" sortable></vxe-column>
-						<vxe-column title="通过数量" field="passNum" sortable></vxe-column>
-					</vxe-colgroup>
-				</vxe-table>
-			</div>
-			<pagination
-				@pagination="queryList"
-				:total="state.total"
-				v-model:current-page="state.queryParams.PageIndex"
-				v-model:page-size="state.queryParams.PageSize"
-				:disabled="state.loading"
-			/>
+			<vxe-grid v-bind="gridOptions" v-on="gridEvents" ref="gridRef">
+				<template #form>
+					<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
+						<el-form-item prop="crTime">
+							<statistical-time v-model="state.queryParams.crTime" @change="handleQuery" ref="statisticalTimeRef" :disabled="state.loading" />
+						</el-form-item>
+						<el-form-item label="部门名称" prop="Keyword">
+							<el-input v-model="state.queryParams.Keyword" placeholder="部门名称" clearable @keyup.enter="handleQuery" class="keyword-input" />
+						</el-form-item>
+						<el-form-item>
+							<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+							<el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
+								<SvgIcon name="ele-Refresh" class="mr5" />重置
+							</el-button>
+						</el-form-item>
+					</el-form>
+				</template>
+				<template #pager>
+					<pagination
+						@pagination="queryList"
+						:total="state.total"
+						v-model:current-page="state.queryParams.PageIndex"
+						v-model:page-size="state.queryParams.PageSize"
+						:disabled="state.loading"
+					/>
+				</template>
+			</vxe-grid>
 		</div>
 	</div>
 </template>
@@ -74,23 +40,6 @@ import Other from '@/utils/other';
 
 const StatisticalTime = defineAsyncComponent(() => import('@/components/StatisticalTime/index.vue')); // 日期类型选择组件
 const pagination = defineAsyncComponent(() => import('@/components/ProTable/components/Pagination.vue')); // 分页
-// 表格配置项
-const columns = ref<any[]>([
-	{ prop: 'orgName', label: '部门名称', align: 'center' },
-	{ prop: 'orgTypeText', label: '部门类型', align: 'center' },
-	{ prop: 'addNum', label: '新增数量', align: 'center', sortable: 'custom' },
-	{ prop: 'deleteNum', label: '删除数量', align: 'center', sortable: 'custom' },
-	{ prop: 'publicNum', label: '公开数量', align: 'center' },
-	{
-		label: '修改',
-		align: 'center',
-		prop: 'modify',
-		_children: [
-			{ prop: 'sendBackNum', label: '退回数量', align: 'center', sortable: 'custom' },
-			{ prop: 'passNum', label: '通过数量', align: 'center', sortable: 'custom' },
-		],
-	},
-]);
 // 定义变量内容
 const ruleFormRef = ref<RefType>(); // 表单ref
 const state = reactive<any>({
@@ -107,36 +56,117 @@ const state = reactive<any>({
 	loading: false, // 加载
 	total: 0, // 总数
 });
+
+const requestParams = ref<EmptyObjectType>({});
+const gridOptions = reactive<any>({
+	loading: false,
+	border: true,
+	showOverflow: true,
+	columnConfig: {
+		resizable: true,
+	},
+	scrollY: {
+		enabled: true,
+		gt: 100,
+	},
+	sortConfig: {
+		remote: true,
+	},
+	toolbarConfig: {
+		zoom: true,
+		custom: true,
+		refresh: {
+			queryMethod: () => {
+				handleQuery();
+			},
+		},
+		tools: [{ toolRender: { name: 'exportCurrent' } }, { toolRender: { name: 'exportAll' } }],
+	},
+	customConfig: {
+		storage: true,
+	},
+	id: 'statisticsKnowledgeData',
+	rowConfig: { isHover: true, height: 30, isCurrent: true, useKey: true },
+	height: 'auto',
+	columns: [
+		{
+			field: 'orgName',
+			title: '部门名称',
+		},
+		{
+			field: 'orgTypeText',
+			title: '部门类型',
+		},
+		{
+			field: 'addNum',
+			title: '新增数量',
+			sortable: true,
+		},
+		{
+			field: 'deleteNum',
+			title: '删除数量',
+			sortable: true,
+		},
+		{
+			field: 'publicNum',
+			title: '公开数量',
+			sortable: true,
+		},
+		{
+			title: '公开数量',
+			children: [
+				{
+					field: 'sendBackNum',
+					title: '退回数量',
+					sortable: true,
+				},
+				{
+					field: 'passNum',
+					title: '通过数量',
+					sortable: true,
+				},
+			],
+		},
+	],
+	data: [],
+	params: {
+		exportMethod: knowledgeExport,
+		exportParams: requestParams,
+	},
+});
+const gridEvents = {
+	sortChange(val: any) {
+		state.queryParams.SortField = val.order ? val.field : null;
+		// 0 升序 1 降序
+		state.queryParams.SortRule = val.order ? (val.order == 'desc' ? 1 : 0) : null;
+		handleQuery();
+	},
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
 	state.queryParams.PageIndex = 1;
 	queryList();
 };
 /** 获取列表 */
-const requestParams = ref<EmptyObjectType>({});
 const queryList = () => {
 	state.loading = true;
+	gridOptions.loading = true;
 	requestParams.value = Other.deepClone(state.queryParams);
 	requestParams.value.CreationTimeStart = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
 	requestParams.value.CreationTimeEnd = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
 	Reflect.deleteProperty(requestParams.value, 'crTime');
 	knowledgeList(requestParams.value)
 		.then((res: any) => {
-			state.tableData = res.result?.items ?? [];
+			gridOptions.data = res.result?.items ?? [];
 			state.total = res.result?.total ?? 0;
 			state.loading = false;
+			gridOptions.loading = false;
 		})
 		.catch(() => {
 			state.loading = false;
+			gridOptions.loading = false;
 		});
 };
-// 排序
-const sortChange = (val: any) => {
-	state.queryParams.SortField = val.order ? val.field : null;
-	// 0 升序 1 降序
-	state.queryParams.SortRule = val.order ? (val.order == 'desc' ? 1 : 0) : null;
-	handleQuery();
-};
 /** 重置按钮操作 */
 const statisticalTimeRef = ref<RefType>();
 const resetQuery = (formEl: FormInstance | undefined) => {
@@ -145,12 +175,7 @@ const resetQuery = (formEl: FormInstance | undefined) => {
 	statisticalTimeRef.value.reset();
 	queryList();
 };
-const toolbarRef = ref<RefType>();
-const tableRef = ref<RefType>();
 onMounted(() => {
 	queryList();
-	if (tableRef.value && toolbarRef.value) {
-		tableRef.value.connect(toolbarRef.value);
-	}
 });
 </script>

+ 203 - 0
src/views/statistics/knowledge/quote.vue

@@ -0,0 +1,203 @@
+<template>
+	<div class="statistics-knowledge-quote-container layout-padding">
+		<div class="layout-padding-auto layout-padding-view pd20">
+			<vxe-grid v-bind="gridOptions" v-on="gridEvents" ref="gridRef">
+				<template #form>
+					<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
+						<el-form-item prop="crTime">
+							<statistical-time v-model="state.queryParams.crTime" @change="handleQuery" ref="statisticalTimeRef" :disabled="state.loading" />
+						</el-form-item>
+						<el-form-item label="知识标题" prop="Keyword">
+							<el-input v-model="state.queryParams.Keyword" placeholder="知识标题" clearable @keyup.enter="handleQuery" class="keyword-input" />
+						</el-form-item>
+						<el-form-item>
+							<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+							<el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
+								<SvgIcon name="ele-Refresh" class="mr5" />重置
+							</el-button>
+						</el-form-item>
+					</el-form>
+				</template>
+				<template #pager>
+					<pagination
+						@pagination="queryList"
+						:total="state.total"
+						v-model:current-page="state.queryParams.PageIndex"
+						v-model:page-size="state.queryParams.PageSize"
+						:disabled="state.loading"
+					/>
+				</template>
+			</vxe-grid>
+		</div>
+		<el-dialog v-model="state.dialogVisible" width="40%" draggable title="关联工单" append-to-body destroy-on-close>
+			<vxe-table
+				border
+				:loading="state.loading"
+				:data="state.tableData"
+				:column-config="{ resizable: true }"
+				:row-config="{ isCurrent: true, isHover: true, height: 30, useKey: true }"
+				ref="tableRef"
+				max-height="500px"
+				show-overflow
+				:scrollY="{ enabled: true, gt: 100 }"
+				showHeaderOverflow
+			>
+				<vxe-column field="no" title="工单编码" width="140"></vxe-column>
+				<vxe-column field="title" title="工单标题">
+					<template #default="{ row }">
+						<order-detail :order="{ id: row.orderId }" @updateList="queryList">{{ row.title }}</order-detail>
+					</template>
+				</vxe-column>
+			</vxe-table>
+		</el-dialog>
+	</div>
+</template>
+<script setup lang="tsx" name="statisticsKnowledgeQuote">
+import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
+import { FormInstance } from 'element-plus';
+import { centerKnowledgeType, centerKnowledgeTypeExport, centerKnowledgeTypeQuery } from '@/api/statistics/knowledge';
+import { defaultDate } from '@/utils/constants';
+import Other from '@/utils/other';
+import { centerHotWordQuery } from '@/api/statistics/center';
+
+const StatisticalTime = defineAsyncComponent(() => import('@/components/StatisticalTime/index.vue')); // 日期类型选择组件
+const pagination = defineAsyncComponent(() => import('@/components/ProTable/components/Pagination.vue')); // 分页
+const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
+// 定义变量内容
+const state = reactive<any>({
+	queryParams: {
+		// 查询条件
+		PageIndex: 1,
+		PageSize: 20,
+		Keyword: null, // 关键词
+		crTime: defaultDate, // 时间默认今天开始到今天结束
+		SortField: null,
+		SortRule: 0,
+	},
+	tableData: [], //表单
+	loading: false, // 加载
+	total: 0, // 总数
+});
+
+const requestParams = ref<EmptyObjectType>({});
+const gridOptions = reactive<any>({
+	loading: false,
+	border: true,
+	showOverflow: true,
+	columnConfig: {
+		resizable: true,
+	},
+	scrollY: {
+		enabled: true,
+		gt: 100,
+	},
+	sortConfig: {
+		remote: true,
+	},
+	toolbarConfig: {
+		zoom: true,
+		custom: true,
+		refresh: {
+			queryMethod: () => {
+				handleQuery();
+			},
+		},
+		tools: [{ toolRender: { name: 'exportCurrent' } }, { toolRender: { name: 'exportAll' } }],
+	},
+	customConfig: {
+		storage: true,
+	},
+	id: 'statisticsKnowledgeQuote',
+	rowConfig: { isHover: true, height: 30, isCurrent: true, useKey: true },
+	height: 'auto',
+	columns: [
+		{
+			field: 'name',
+			title: '知识标题',
+		},
+		{
+			field: 'countNum',
+			title: '引用次数',
+			slots: {
+				default({ row }) {
+					return (
+						<el-button type="primary" onClick={() => linkDetail(row)} link>
+							{row.countNum}
+						</el-button>
+					);
+				},
+			},
+		},
+	/*	{
+			field: 'inConnectionRate',
+			title: '引用时间',
+			sortable: true,
+			formatter: 'formatDate',
+		},*/
+	],
+	data: [],
+	params: {
+		exportMethod: centerKnowledgeTypeExport,
+		exportParams: requestParams,
+	},
+});
+const gridEvents = {
+	sortChange(val: any) {
+		state.queryParams.SortField = val.order ? val.field : null;
+		// 0 升序 1 降序
+		state.queryParams.SortRule = val.order ? (val.order == 'desc' ? 1 : 0) : null;
+		handleQuery();
+	},
+};
+/** 搜索按钮操作 */
+const ruleFormRef = ref<RefType>(); // 表单ref
+const handleQuery = () => {
+	state.queryParams.PageIndex = 1;
+	queryList();
+};
+/** 获取列表 */
+const queryList = () => {
+	state.loading = true;
+	gridOptions.loading = true;
+	requestParams.value = Other.deepClone(state.queryParams);
+	requestParams.value.StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
+	requestParams.value.EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+	Reflect.deleteProperty(requestParams.value, 'crTime');
+	centerKnowledgeType(requestParams.value)
+		.then((res: any) => {
+			state.tableData = res.result?.items ?? [];
+			gridOptions.data = res.result?.items ?? [];
+			state.total = res.result?.total ?? 0;
+			state.loading = false;
+			gridOptions.loading = false;
+		})
+		.catch(() => {
+			state.loading = false;
+			gridOptions.loading = false;
+		});
+};
+/** 重置按钮操作 */
+const statisticalTimeRef = ref<RefType>();
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	statisticalTimeRef.value.reset();
+	queryList();
+};
+// 查看详情
+const linkDetail = async (row: any) => {
+	state.dialogVisible = true;
+	state.loading = true;
+	try {
+		const { result } = await centerKnowledgeTypeQuery({ KeyWord: row.name });
+		state.tableData = result;
+		state.loading = false;
+	} catch (e) {
+		console.log(e);
+		state.loading = false;
+	}
+};
+onMounted(() => {
+	queryList();
+});
+</script>

+ 200 - 0
src/views/tels/recordUpload/components/Upload.vue

@@ -0,0 +1,200 @@
+<template>
+	<el-dialog v-model="state.dialogVisible" width="50%" draggable title="录音上传">
+		<el-upload
+			class="upload-demo"
+			v-model:file-list="fileList"
+			:action="action"
+			:multiple="true"
+			:accept="fileTypeAccept"
+			:on-exceed="handleExceed"
+			ref="uploadListRef"
+			name="fileData"
+			:on-change="handleChangeFile"
+			:on-success="updateSuccess"
+			:disabled="uploadingDisabled"
+			:on-error="onUploadError"
+			:limit="fileLimit"
+			:on-remove="handRemove"
+			:before-upload="beforeUpload"
+			drag
+		>
+			<SvgIcon name="ele-UploadFilled" size="42px" />
+			<div class="el-upload__text">点击或将文件拖拽到这里上传</div>
+			<template #tip>
+				<div class="el-upload__tip">大小限制:20M</div>
+			</template>
+		</el-upload>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="closeDialog" class="default-button">取 消</el-button>
+				<el-button type="primary" @click="onSave" :loading="loading">保 存</el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script setup lang="ts" name="parameterAdd">
+import { computed, reactive, ref } from 'vue';
+import { useAppConfig } from '@/stores/appConfig';
+import { storeToRefs } from 'pinia';
+import { ElMessage, UploadFile, UploadFiles, UploadUserFile } from 'element-plus';
+import Other from '@/utils/other';
+import { uploadRecordSave } from '@/api/tels/uploadRecord';
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+// 定义变量内容
+const state = reactive<any>({
+	dialogVisible: false,
+	ruleForm: {
+		settingName: '', // 参数名称
+		code: '', // 参数
+		settingValue: '', // 参数值
+		sort: 1, // 排序
+		remark: '', // 参数说明
+	},
+});
+
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
+const fileTypeAccept = AppConfigInfo.value?.fileExt;
+const action = computed(() => {
+	return import.meta.env.VITE_API_UPLOAD_URL + '/file/upload?source=hotline';
+	// return 'http://171.94.154.2:50105/hlfs/file/upload?source=hotline';
+});
+
+const fileList = ref<EmptyArrayType>([]);
+const uploadListRef = ref<RefType>(); // 上传组件ref
+
+// 格式化数据
+const formatData = (data: any) => {
+	return data.map((v: any) => {
+		return {
+			name: v.name,
+			fileName: v.name,
+			additions: v?.response?.result.id,
+			path: v?.response?.result?.path,
+			publicity: v?.publicity ? 1 : 0,
+			classify: '录音上传',
+			url: import.meta.env.VITE_API_UPLOAD_URL + v?.response?.result?.path,
+			allPath: import.meta.env.VITE_API_UPLOAD_URL + v?.response?.result?.path,
+		};
+	});
+};
+// 更新数据
+const transformData = ref<EmptyArrayType>([]);
+const updateData = () => {
+	transformData.value = formatData(Other.deepClone(fileList.value));
+};
+
+//文件限制
+const fileLimit = ref(10);
+const handleExceed = (files: any, uploadFiles: UploadUserFile[]) => {
+	ElMessage.warning(`当前限制最多上传 ${fileLimit.value} 个文件,已经上传了${uploadFiles.length}个文件,本次选择了 ${files.length} 个文件。`);
+	setTimeout(() => {
+		uploadLoading.value = false; // 模拟上传过程
+		uploadingDisabled.value = false;
+	}, 100);
+};
+
+//限制文件大小
+const handleChangeFile = (file: any, fileList: any) => {
+	//限制上传文件大小
+	setTimeout(() => {
+		updateData();
+	}, 100);
+	if (!file) return;
+	const isLt2M = file.size / 1024 / 1024 < 20;
+	if (!isLt2M) {
+		const currIdx = fileList.indexOf(file);
+		fileList.splice(currIdx, 1);
+		ElMessage.warning(`文件超过了最大限度 20MB!`);
+		setTimeout(() => {
+			uploadLoading.value = false; // 模拟上传过程
+			uploadingDisabled.value = false;
+		}, 100);
+		return false;
+	}
+};
+// 删除文件
+const handRemove = () => {
+	setTimeout(() => {
+		updateData();
+	}, 100);
+};
+// 上传失败
+const onUploadError = (error: Error, uploadFile: UploadFile) => {
+	try {
+		const errMessage = JSON.parse(error.message)?.message ?? `文件 ${uploadFile.name} 上传失败`;
+		// 从文件列表中移除失败的文件
+		fileList.value = fileList.value.filter((item) => item.response);
+		console.error(`文件 ${uploadFile.name} 上传失败`);
+		console.log(fileList.value, '111');
+		ElMessage.error(errMessage);
+	} catch (e) {
+		ElMessage.error(`文件 ${uploadFile.name} 上传失败`);
+	}
+	setTimeout(() => {
+		updateData();
+		uploadLoading.value = false; // 模拟上传过程
+		uploadingDisabled.value = false;
+	}, 100);
+};
+
+const uploadLoading = ref(false);
+const uploadingDisabled = ref(false);
+const beforeUpload = () => {
+	uploadLoading.value = true; // 模拟上传过程
+	uploadingDisabled.value = true;
+};
+
+// 上传成功
+const updateSuccess = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+	if (response.result.path) {
+		fileList.value = uploadFiles;
+		setTimeout(() => {
+			updateData();
+			uploadLoading.value = false;
+			uploadingDisabled.value = false;
+		}, 100);
+	} else {
+		uploadListRef.value.handleRemove(uploadFile);
+		ElMessage.error('上传失败');
+	}
+};
+
+let loading = ref<boolean>(false); // 加载状态
+// 打开弹窗
+const ruleFormRef = ref<RefType>();
+const openDialog = async () => {
+	ruleFormRef.value?.resetFields();
+	try {
+		state.dialogVisible = true;
+	} catch (error) {
+		console.log(error);
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+// 保存
+const onSave = () => {
+	console.log(transformData.value);
+	uploadRecordSave(transformData.value)
+		.then(() => {
+			ElMessage.success('保存成功');
+			closeDialog();
+			emit('updateList');
+		})
+		.catch((err: any) => {
+			console.log(err, 'err');
+			closeDialog();
+		});
+};
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>

+ 262 - 0
src/views/tels/recordUpload/index.vue

@@ -0,0 +1,262 @@
+<template>
+	<div class="tels-record-upload-container layout-padding">
+		<div class="layout-padding-auto layout-padding-view pd20">
+			<vxe-grid v-bind="gridOptions" v-on="gridEvents" ref="gridRef">
+				<template #form>
+					<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
+						<el-form-item label="录音名称" prop="Keyword">
+							<el-input v-model="state.queryParams.Keyword" placeholder="录音名称" clearable @keyup.enter="handleQuery" class="keyword-input" />
+						</el-form-item>
+						<el-form-item prop="crTime" label="上传时间">
+							<el-date-picker
+								v-model="state.queryParams.crTime"
+								type="datetimerange"
+								unlink-panels
+								range-separator="至"
+								start-placeholder="开始时间"
+								end-placeholder="结束时间"
+								:shortcuts="shortcuts"
+								@change="handleQuery"
+								value-format="YYYY-MM-DD[T]HH:mm:ss"
+								:default-time="defaultTimeStartEnd"
+								:clearable="false"
+							/>
+						</el-form-item>
+						<el-form-item>
+							<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+							<el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
+								<SvgIcon name="ele-Refresh" class="mr5" />重置
+							</el-button>
+						</el-form-item>
+					</el-form>
+				</template>
+				<template #toolbar_buttons>
+					<el-button type="primary" @click="onUpload" v-auth="'tels:recordUpload:add'" :loading="state.loading">
+						<SvgIcon name="ele-Upload" class="mr5" />上传录音
+					</el-button>
+				</template>
+				<template #action="{ row }">
+					<el-button link type="primary" @click="onPlay(row)" v-auth="'tels:recordUpload:play'"> 播放 </el-button>
+					<el-button link type="primary" @click="onDownload(row)" v-auth="'tels:recordUpload:download'"> 下载 </el-button>
+					<el-button link type="danger" @click="onDelete(row)" v-auth="'tels:recordUpload:delete'"> 删除 </el-button>
+				</template>
+				<template #pager>
+					<pagination
+						@pagination="queryList"
+						:total="state.total"
+						v-model:current-page="state.queryParams.PageIndex"
+						v-model:page-size="state.queryParams.PageSize"
+						:disabled="state.loading"
+					/>
+				</template>
+			</vxe-grid>
+		</div>
+		<el-dialog v-model="state.dialogVisible" width="500px" draggable title="关联工单" append-to-body destroy-on-close>
+			<vxe-table
+				border
+				:loading="state.loading"
+				:data="state.tableData"
+				:column-config="{ resizable: true }"
+				:row-config="{ isCurrent: true, isHover: true, height: 30, useKey: true }"
+				ref="tableRef"
+				max-height="500px"
+				show-overflow
+				:scrollY="{ enabled: true, gt: 100 }"
+				showHeaderOverflow
+			>
+				<vxe-column field="no" title="工单编码" width="140"></vxe-column>
+				<vxe-column field="title" title="工单标题">
+					<template #default="{ row }">
+						<order-detail :order="row" @updateList="queryList">{{ row.title }}</order-detail>
+					</template>
+				</vxe-column>
+			</vxe-table> </el-dialog
+		>‘
+		<!--	录音上传	-->
+		<RecordUpload ref="uploadRef" @updateList="queryList" />
+		<!-- 播放录音 -->
+		<play-record ref="playRecordRef" />
+	</div>
+</template>
+<script setup lang="tsx" name="telsRecordUpload">
+import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
+import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+import { defaultDate, defaultTimeStartEnd, shortcuts } from '@/utils/constants';
+import Other from '@/utils/other';
+import { uploadRecordDelete, uploadRecordExport, uploadRecordList } from '@/api/tels/uploadRecord';
+import { fileDownloadByUrl } from '@/api/public/file';
+
+const pagination = defineAsyncComponent(() => import('@/components/ProTable/components/Pagination.vue')); // 分页
+const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
+const RecordUpload = defineAsyncComponent(() => import('@/views/tels/recordUpload/components/Upload.vue')); // 录音上传
+const PlayRecord = defineAsyncComponent(() => import('@/components/PlayRecord/index.vue')); // 播放录音
+// 定义变量内容
+const state = reactive<any>({
+	queryParams: {
+		// 查询条件
+		PageIndex: 1,
+		PageSize: 20,
+		Keyword: null, // 关键词
+		crTime: defaultDate, // 时间默认今天开始到今天结束
+		SortField: null,
+		SortRule: 0,
+	},
+	tableData: [], //表单
+	loading: false, // 加载
+	total: 0, // 总数
+});
+
+const requestParams = ref<EmptyObjectType>({});
+const gridOptions = reactive<any>({
+	loading: false,
+	border: true,
+	showOverflow: true,
+	columnConfig: {
+		resizable: true,
+	},
+	scrollY: {
+		enabled: true,
+		gt: 100,
+	},
+	sortConfig: {
+		remote: true,
+	},
+	toolbarConfig: {
+		zoom: true,
+		custom: true,
+		refresh: {
+			queryMethod: () => {
+				handleQuery();
+			},
+		},
+		tools: [{ toolRender: { name: 'exportCurrent' } }, { toolRender: { name: 'exportAll' } }],
+		slots: {
+			buttons: 'toolbar_buttons',
+		},
+	},
+	customConfig: {
+		storage: true,
+	},
+	id: 'statisticsKnowledgeQuote',
+	rowConfig: { isHover: true, height: 30, isCurrent: true, useKey: true },
+	height: 'auto',
+	columns: [
+		{
+			field: 'fileName',
+			title: '录音名称',
+		},
+		{
+			field: 'creationTime',
+			title: '上传时间',
+			sortable: true,
+			formatter: 'formatDate',
+		},
+
+		{ title: '操作', width: 180, fixed: 'right', align: 'center', slots: { default: 'action' } },
+	],
+	data: [],
+	params: {
+		exportMethod: uploadRecordExport,
+		exportParams: requestParams,
+	},
+});
+const gridEvents = {
+	sortChange(val: any) {
+		state.queryParams.SortField = val.order ? val.field : null;
+		// 0 升序 1 降序
+		state.queryParams.SortRule = val.order ? (val.order == 'desc' ? 1 : 0) : null;
+		handleQuery();
+	},
+};
+/** 搜索按钮操作 */
+const ruleFormRef = ref<RefType>(); // 表单ref
+const handleQuery = () => {
+	state.queryParams.PageIndex = 1;
+	queryList();
+};
+/** 获取列表 */
+const queryList = () => {
+	state.loading = true;
+	gridOptions.loading = true;
+	requestParams.value = Other.deepClone(state.queryParams);
+	requestParams.value.StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
+	requestParams.value.EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+	Reflect.deleteProperty(requestParams.value, 'crTime');
+	uploadRecordList(requestParams.value)
+		.then((res: any) => {
+			state.tableData = res.result?.items ?? [];
+			gridOptions.data = res.result?.items ?? [];
+			state.total = res.result?.total ?? 0;
+			state.loading = false;
+			gridOptions.loading = false;
+		})
+		.catch(() => {
+			state.loading = false;
+			gridOptions.loading = false;
+		});
+};
+/** 重置按钮操作 */
+const statisticalTimeRef = ref<RefType>();
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	statisticalTimeRef.value.reset();
+	queryList();
+};
+// 上传录音
+const uploadRef = ref<RefType>();
+const onUpload = () => {
+	uploadRef.value.openDialog();
+};
+// 播放
+const onPlay = (row: any) => {
+	window.open(row.allPath)
+};
+// 下载
+const onDownload = (row: any) => {
+	ElMessageBox.confirm(`确定要下载 ${row.name} 吗?`, '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		cancelButtonClass: 'default-button',
+	})
+		.then(() => {
+			fileDownloadByUrl({
+				Source: 'hotline',
+				Id: row.fileId,
+			}).then((res: any) => {
+				let blob: Blob = new Blob([res.data], { type: res.data.type }); // 创建blob 设置blob文件类型 data 设置为后端返回的文件(例如mp3,jpeg) type:这里设置后端返回的类型 为 mp3
+				let down: HTMLAnchorElement = document.createElement('a'); // 创建A标签
+				let href: string = window.URL.createObjectURL(blob); // 创建下载的链接
+				down.href = href; // 下载地址
+				down.download = row.fileName; // 下载文件名
+				document.body.appendChild(down);
+				down.click(); // 模拟点击A标签
+				document.body.removeChild(down); // 下载完成移除元素
+				window.URL.revokeObjectURL(href); // 释放blob对象
+			});
+		})
+		.catch(() => {});
+};
+// 删除
+const onDelete = (row: any) => {
+	ElMessageBox.confirm(`确定要删除 ${row.name} 吗?`, '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		cancelButtonClass: 'default-button',
+	})
+		.then(() => {
+			uploadRecordDelete({ ids: [row.fileId] }).then(() => {
+				queryList();
+				ElMessage.success('删除成功');
+			});
+		})
+		.catch(() => {});
+};
+onMounted(() => {
+	queryList();
+});
+</script>

+ 41 - 1
src/views/todo/seats/accept/Knowledge.vue

@@ -42,7 +42,12 @@
 			</el-empty>
 			<el-scrollbar>
 				<div v-for="(v, i) in state.knowledgeList" :key="i" class="retrieval-content-item" @click="onPreview(v)">
-					<h4 class="mb10 text-no-wrap">{{ v.title }}</h4>
+					<div class="mb10" style="display: flex">
+						<p class="text-no-wrap" style="flex: 1">{{ v.title }}</p>
+						<el-button type="primary" size="small" @click.stop="changeYYType(v)" v-if="['ZiGong'].includes(themeConfig.appScope)">{{
+							v.isChoose ? '取消引用' : '引用'
+						}}</el-button>
+					</div>
 					<!--					<div class="text-ellipsis2">{{ v.summary }}</div>-->
 					<div class="flex-center-between mt10 color-info">
 						<div>
@@ -75,6 +80,8 @@ import { useRoute, useRouter } from 'vue-router';
 import { formatDate } from '@/utils/formatTime';
 import { knowledgeRetrieval, knowledgeRetrievalAccept } from '@/api/knowledge/retrieval';
 import { throttle } from '@/utils/tools';
+import { useThemeConfig } from '@/stores/themeConfig';
+import { storeToRefs } from 'pinia';
 
 const pagination = defineAsyncComponent(() => import('@/components/ProTable/components/Pagination.vue')); // 分页
 
@@ -93,6 +100,8 @@ const props = defineProps({
 	},
 });
 
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
 const state = reactive<any>({
 	loading: false, // 知识检索加载状态
 	knowledgeList: [],
@@ -137,6 +146,15 @@ const knowledgeRetrievalPaged = throttle(async () => {
 		const { result } = await knowledgeRetrievalAccept(request);
 		state.knowledgeList = result?.items ?? [];
 		state.knowledgeTotal = result?.total ?? 0;
+		if (props.formData.knowledgeQuote) {
+			for (let i of state.knowledgeList) {
+				for (let j of props.formData.knowledgeQuote) {
+					if (i.id === j.key) {
+						i.isChoose = true;
+					}
+				}
+			}
+		}
 		state.loading = false;
 	} catch (error) {
 		state.loading = false;
@@ -168,6 +186,15 @@ const querySearch = async (name: string) => {
 		const res: any = await knowledgeRetrieval(request);
 		state.knowledgeList = res.result?.items ?? [];
 		state.knowledgeTotal = res.result?.total ?? 0;
+		if (props.formData.knowledgeQuote) {
+			for (let i of state.knowledgeList) {
+				for (let j of props.formData.knowledgeQuote) {
+					if (i.id === j.key) {
+						i.isChoose = true;
+					}
+				}
+			}
+		}
 		state.loading = false;
 	} catch (error) {
 		state.loading = false;
@@ -177,6 +204,19 @@ const querySearch = async (name: string) => {
 const changeRecommendType = () => {
 	knowledgeRetrievalPaged();
 };
+const emit = defineEmits(['changeYYType']);
+const changeYYType = (row: any) => {
+	row.isChoose = !row.isChoose;
+	// 获取选中的数据
+	const data = state.knowledgeList.filter((v: any) => v.isChoose);
+	const reData = data.map((v: any) => {
+		return {
+			key: v.id,
+			value: v.title,
+		};
+	});
+	emit('changeYYType', reData);
+};
 watch(
 	() => props.formData.hotspotId,
 	(val: any) => {