Forráskód Böngészése

reactor:排班管理对接;

zhangchong 1 éve
szülő
commit
47d7265579

+ 12 - 1
src/api/system/workforce.ts

@@ -105,7 +105,7 @@ export const deleteWorkforceClass = (data: object) => {
  */
 export const getWorkforceClassUserList = (params: object) => {
 	return request({
-		url: '/api/v1/Scheduling/list',
+		url: '/api/v1/Scheduling/data',
 		method: 'get',
 		params,
 	});
@@ -133,4 +133,15 @@ export const updateScheduling = (data: object) => {
 		method: 'put',
 		data,
 	});
+}
+/**
+ * @description 排班详情
+ * @return {*}
+ * @param id
+ */
+export const getSchedulingDetail = (id: string) => {
+	return request({
+		url: `/api/v1/Scheduling/${id}`,
+		method: 'get',
+	});
 }

+ 87 - 14
src/views/statistics/call/telephonist.vue

@@ -54,31 +54,82 @@ import { throttle } from '@/utils/tools';
 import { callAgent } from '@/api/statistics/call';
 import { shortcuts } from '@/utils/constants';
 import dayjs from 'dayjs';
+import { formatDuration } from '@/utils/formatTime';
 
 const proTableRef = ref<RefType>(); // 表格ref
 // 表格配置项
 const columns = ref<any[]>([
 	{ type: 'index', fixed: 'left', width: 55, label: '序号', align: 'center' },
-	{ prop: 'name', label: '坐席工号', align: 'center' },
-	{ prop: 'inTotal', label: '呼入总量', align: 'center', sortable: 'custom' },
-	{ prop: 'inAnswered', label: '接通总量', align: 'center', sortable: 'custom' },
-	{ prop: 'inHangupImmediate', label: '呼入秒挂', align: 'center', sortable: 'custom' },
-	{ prop: 'inHanguped', label: '呼入超时未接', align: 'center', sortable: 'custom' },
+	{
+		prop: 'name',
+		label: '坐席工号',
+		align: 'center',
+		minWidth: 120,
+		render: (scope) => (
+			<span>
+				{scope.row.name} {scope.row.staffNo ? <span>({scope.row.telNo})</span> : ''}{' '}
+			</span>
+		),
+	},
+	{ prop: 'inTotal', label: '呼入总量', align: 'center', sortable: 'custom', minWidth: 120 },
+	{ prop: 'inAnswered', label: '接通总量', align: 'center', sortable: 'custom', minWidth: 120 },
+	{ prop: 'inHangupImmediate', label: '呼入秒挂', align: 'center', sortable: 'custom', minWidth: 120 },
+	{ prop: 'inHanguped', label: '呼入超时未接', align: 'center', sortable: 'custom', minWidth: 140 },
 	{
 		prop: 'inAnsweredRate',
 		label: '接通率',
 		align: 'center',
 		sortable: 'custom',
-		render: (scope) => <span>{scope.row.inAnsweredRate}%</span>
+		render: (scope) => <span>{scope.row.inAnsweredRate}%</span>,
+		minWidth: 120,
+	},
+	{ prop: 'outDurationAvg', label: '呼入平均时长', align: 'center', sortable: 'custom', minWidth: 140 },
+	{ prop: 'inAvailableAnswer', label: '有效接通量', align: 'center', sortable: 'custom', minWidth: 120 },
+	{ prop: 'inHangupImmediateWhenAnswered', label: '接通秒挂', align: 'center', sortable: 'custom', minWidth: 120 },
+	{
+		prop: 'inAnsweredRate',
+		label: '有效接通率',
+		align: 'center',
+		sortable: 'custom',
+		render: (scope) => <span>{scope.row.inAnsweredRate}%</span>,
+		minWidth: 120,
+	},
+	{ prop: 'outTotal', label: '呼出总量', align: 'center', sortable: 'custom', minWidth: 120 },
+	{ prop: 'outAnswered', label: '呼出接通量', align: 'center', sortable: 'custom', minWidth: 120 },
+	{
+		prop: 'outAnsweredRate',
+		label: '呼出接通率',
+		align: 'center',
+		sortable: 'custom',
+		render: (scope) => <span>{scope.row.outAnsweredRate}%</span>,
+		minWidth: 120,
+	},
+	{
+		prop: 'outDurationAvg',
+		label: '呼出平均时长',
+		align: 'center',
+		sortable: 'custom',
+		minWidth: 140,
+		render: (scope) => <span>{formatDuration(scope.row.outDurationAvg)}</span>,
+	},
+	{
+		prop: 'loginDuration',
+		label: '登录时长',
+		align: 'center',
+		sortable: 'custom',
+		minWidth: 120,
+		render: (scope) => <span>{formatDuration(scope.row.loginDuration)}</span>,
+	},
+	{
+		prop: 'restDuration',
+		label: '小休+摘机时长',
+		align: 'center',
+		sortable: 'custom',
+		minWidth: 150,
+		render: (scope) => <span>{formatDuration(scope.row.restDuration)}</span>,
 	},
-	{ prop: 'outDurationAvg', label: '呼入平均时长', align: 'center', sortable: 'custom' },
-	{ prop: 'inAvailableAnswer', label: '有效接通率', align: 'center', sortable: 'custom',render: (scope) => <span>{scope.row.inAvailableAnswer}%</span> },
-	{ prop: 'inHangupImmediateWhenAnswered', label: '接通秒挂', align: 'center', sortable: 'custom' },
-	{ prop: 'inAnsweredRate', label: '有效接通率', align: 'center', sortable: 'custom',render: (scope) => <span>{scope.row.inAnsweredRate}%</span> },
-	{ prop: 'outTotal', label: '呼出总量', align: 'center', sortable: 'custom' },
-	{ prop: 'outAnswered', label: '呼出接通量', align: 'center', sortable: 'custom' },
-	{ prop: 'outAnsweredRate', label: '呼出接通率', align: 'center', sortable: 'custom',render: (scope) => <span>{scope.row.outAnsweredRate}%</span> },
-	{ prop: 'outDurationAvg', label: '呼出平均时长', align: 'center', sortable: 'custom' },
+	{ prop: 'outDurationAvg', label: '摘机次数', align: 'center', sortable: 'custom', minWidth: 120 },
+	{ prop: 'workRate', label: '工作效率', align: 'center', minWidth: 120, render: (scope) => <span>{scope.row.workRate}%</span> },
 ]);
 // 定义变量内容
 const ruleFormRef = ref<RefType>(); // 表单ref
@@ -159,6 +210,28 @@ const getSummaries = (param: any) => {
 		}
 	});
 	return sums;
+  /*const { columns } = param;
+  const sums: string[] = [];
+  columns.forEach((column: { property: string }, index: number) => {
+    switch (column.property) {
+      case 'name':
+        sums[index] = state.totalCount?.name;
+        break;
+      case 'num':
+        sums[index] = state.totalCount?.num;
+        break;
+      case 'chainNum':
+        sums[index] = state.totalCount?.chainNum;
+        break;
+      case 'chainRate':
+        sums[index] = state.totalCount?.chainRate;
+        break;
+      default:
+        sums[index] = '';
+        break;
+    }
+  });
+  return sums;*/
 };
 onMounted(() => {
 	queryList();

+ 1 - 0
src/views/statistics/call/transferOut.vue

@@ -40,6 +40,7 @@
 				:total="state.total"
 				v-model:page-index="state.queryParams.PageIndex"
 				v-model:page-size="state.queryParams.PageSize"
+        border
 			>
 			</ProTable>
 		</el-card>

+ 2 - 2
src/views/statistics/knowledge/data.vue

@@ -9,14 +9,14 @@
 				<el-form-item label="时间段" prop="crTime">
 					<el-date-picker
 						v-model="state.queryParams.crTime"
-						type="datetimerange"
+						type="daterange"
 						unlink-panels
 						range-separator="至"
 						start-placeholder="开始时间"
 						end-placeholder="结束时间"
 						:shortcuts="shortcuts"
 						@change="queryList"
-						value-format="YYYY-MM-DD[T]HH:mm:ss"
+						value-format="YYYY-MM-DD"
 					/>
 				</el-form-item>
 				<el-form-item>

+ 11 - 9
src/views/system/workforce/components/Select-number.vue

@@ -28,7 +28,7 @@
 import { reactive, ref } from 'vue';
 import { ElMessage, FormInstance } from 'element-plus';
 import { throttle } from '@/utils/tools';
-import { getWorkforceClassList, updateScheduling } from '@/api/system/workforce';
+import { getSchedulingDetail, getWorkforceClassList, updateScheduling } from '@/api/system/workforce';
 
 // 定义子组件向父组件传值/事件
 const emit = defineEmits(['updateList']);
@@ -39,21 +39,24 @@ const state = reactive<any>({
 	ruleForm: {
 		shiftId: null,
 	},
-	currentRow: {},
 });
 let loading = ref<boolean>(false); // 加载状态
 const dialogTitle = ref('选择班次');
 // 打开弹窗
 const ruleFormRef = ref<RefType>();
 const numberOptions = ref<any[]>([]); // 班次列表
+const schedulingId = ref(''); // 排班ID
+const schedulingDate = ref(''); // 排班日期
 const openDialog = async (row: any) => {
 	if (!row) return;
+	schedulingId.value = row.row[row.column.property]['id'];
+	schedulingDate.value = row.column.property;
 	try {
-		const number = await getWorkforceClassList({ PageSize: 999999, PageIndex: 1 });
-		numberOptions.value = number.result?.items ?? [];
-		state.currentRow = row.row;
+		const numberRes = await getWorkforceClassList({ PageSize: 999999, PageIndex: 1 });
+		numberOptions.value = numberRes.result?.items ?? [];
 		dialogTitle.value = `选择 ${row.row?.schedulingUserName}【${row.column?.property}】排班`;
-		state.ruleForm.shiftId = row.row?.shiftId;
+		const schedulingRes = await getSchedulingDetail(schedulingId.value);
+		state.ruleForm.shiftId = schedulingRes.result?.shiftId;
 		state.dialogVisible = true;
 	} catch (error) {
 		console.log(error);
@@ -74,10 +77,9 @@ const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
 		if (!valid) return;
 		loading.value = true;
 		const request = {
-			userIds: [state.currentRow?.schedulingUserId],
 			shiftId: state.ruleForm.shiftId,
-			schedulingTime: state.currentRow?.schedulingTime,
-			id: state.currentRow?.id,
+			schedulingTime: schedulingDate.value,
+			id: schedulingId.value,
 		};
 		state.loading = true;
 		updateScheduling(request)

+ 6 - 52
src/views/system/workforce/scheduling.vue

@@ -12,9 +12,7 @@
 				:data="state.tableData"
 				@updateTable="queryList"
 				:loading="state.loading"
-				:total="state.total"
-				v-model:page-index="state.queryParams.PageIndex"
-				v-model:page-size="state.queryParams.PageSize"
+				:pagination="false"
 				:key="Math.random()"
 				border
 			>
@@ -51,13 +49,12 @@ const state = reactive({
 });
 const proTableRef = ref<RefType>(); // 表格ref
 // 表格配置项
-const columns = ref<any[]>([{ prop: 'schedulingUserName', label: '姓名', width: 120, fixed: 'left', align: 'center' }]);
-const numberList = ref<any[]>([]); // 班次列表
+const columns = ref<any[]>([{ prop: 'SchedulingUserName', label: '姓名', width: 120, fixed: 'left', align: 'center' }]);
 /** 通话记录列表 */
 const queryList = async () => {
 	state.loading = true;
 	try {
-		columns.value = [{ prop: 'schedulingUserName', label: '姓名', width: 120, fixed: 'left', align: 'center' }];
+		columns.value = [{ prop: 'SchedulingUserName', label: '姓名', width: 120, fixed: 'left', align: 'center' }];
 		const days = dayjs(month.value).daysInMonth(); // 获取当月有多少天
 		for (let i = 1; i <= days; i++) {
 			const num = i < 10 ? `0${i}` : i;
@@ -66,11 +63,7 @@ const queryList = async () => {
 				label: `${num}日`,
 				align: 'center',
 				render: (scope) => {
-					/*		{scope.row?.schedulingTime === `${dayjs(month.value).format('YYYY-MM')}-${num}`
-            ? `${scope.row[dayjs(month.value).format(`YYYY-MM-${num}`)]}`
-            : ''}*/
 					const value = `${scope.row[dayjs(month.value).format(`YYYY-MM-${num}`)]}`;
-					console.log(value);
 					return (
 						<>
 							{value !== 'undefined' && value ? (
@@ -90,39 +83,11 @@ const queryList = async () => {
 				},
 			});
 		}
-		/*const request = {
-			...state.queryParams,
-			StartTime: `${month.value}-01`,
-			EndTime: `${month.value}-${days}`,
+		const request = {
+			Time: month.value,
 		};
 		const response = await getWorkforceClassUserList(request);
-		state.tableData = response.result?.items ?? [];
-		state.tableData = state.tableData.map((item: any) => {
-			return {
-				...item,
-				schedulingTime: dayjs(item.schedulingTime).format('YYYY-MM-DD'),
-				[`${dayjs(item.schedulingTime).format('YYYY-MM-DD')}`]: item.schedulingShift?.name,
-			};
-		});
-		state.total = response.result?.total ?? 0;*/
-		console.log(columns.value);
-		state.tableData = [
-			{
-				schedulingUserName: '张冲',
-				'2024-04-01': {
-					name: '班次1',
-					id: 1,
-				},
-				'2024-04-02': {
-					name: '班次2',
-					id: 2,
-				},
-				'2024-04-03': {
-					name: '班次3',
-					id: 3,
-				},
-			},
-		];
+		state.tableData = response.result ?? [];
 		state.loading = false;
 	} catch (e) {
 		state.loading = false;
@@ -137,20 +102,9 @@ const scheduler = () => {
 // 单个排班
 const schedulingRef = ref<RefType>(); // 单个排班
 const changeScheduling = (row) => {
-  console.log(row)
 	schedulingRef.value.openDialog(row);
 };
-// 获取班次列表
-const getNumberList = async () => {
-	try {
-		const response = await getWorkforceClassList({ PageSize: 999999, PageIndex: 1 });
-		numberList.value = response.result?.items ?? [];
-	} catch (e) {
-		console.log(e);
-	}
-};
 onMounted(() => {
-	getNumberList();
 	queryList();
 });
 </script>