Browse Source

feat: 0428bug,需求处理提交

master
AaronWu 1 month ago
parent
commit
9bbb08c681
  1. 2
      .env.development
  2. 1
      src/assets/icons/close.svg
  3. 2
      src/enums/dictEnum.ts
  4. 5
      src/views/client/issue/formSchemas.tsx
  5. 50
      src/views/client/issue/index.vue
  6. 17
      src/views/question/issue/columns.tsx
  7. 8
      src/views/question/issue/data.ts
  8. 6
      src/views/question/issue/detail.vue
  9. 123
      src/views/question/issue/formSchemas.tsx
  10. 242
      src/views/question/issue/index.vue
  11. 2
      src/views/question/knowledge/columns.tsx
  12. 4
      src/views/question/knowledge/formSchemas.tsx
  13. 2
      src/views/question/knowledge/index.vue

2
.env.development

@ -9,7 +9,7 @@
# 只在开发模式中被载入
# 网站前缀
VITE_BASE_API_URL = http://192.168.2.92:8089/server/
VITE_BASE_API_URL = http://192.168.2.217:8089/server/
# VITE_BASE_API_URL = http://43.137.2.78:8085/server/
# base api

1
src/assets/icons/close.svg

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1745894579270" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7446" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M872.802928 755.99406 872.864326 755.99406 872.864326 755.624646Z" fill="#d81e06" p-id="7447"></path><path d="M927.846568 511.997953c0-229.315756-186.567139-415.839917-415.838893-415.839917-229.329059 0-415.85322 186.524161-415.85322 415.839917 0 229.300406 186.524161 415.84094 415.85322 415.84094C741.278405 927.838893 927.846568 741.29836 927.846568 511.997953M512.007675 868.171955c-196.375529 0-356.172979-159.827125-356.172979-356.174002 0-196.374506 159.797449-356.157629 356.172979-356.157629 196.34483 0 356.144326 159.783123 356.144326 356.157629C868.152001 708.34483 708.352505 868.171955 512.007675 868.171955" fill="#d81e06" p-id="7448"></path><path d="M682.378947 642.227993 553.797453 513.264806 682.261267 386.229528c11.661597-11.514241 11.749602-30.332842 0.234337-41.995463-11.514241-11.676947-30.362518-11.765975-42.026162-0.222057L511.888971 471.195665 385.223107 344.130711c-11.602246-11.603269-30.393217-11.661597-42.025139-0.059352-11.603269 11.618619-11.603269 30.407544-0.059352 42.011836l126.518508 126.887922L342.137823 639.104863c-11.662621 11.543917-11.780301 30.305213-0.23536 41.96988 5.830799 5.89015 13.429871 8.833179 21.086248 8.833179 7.53972 0 15.136745-2.8847 20.910239-8.569166l127.695311-126.311801L640.293433 684.195827c5.802146 5.8001 13.428847 8.717546 21.056572 8.717546 7.599072 0 15.165398-2.917446 20.968567-8.659217C693.922864 672.681586 693.950494 653.889591 682.378947 642.227993" fill="#d81e06" p-id="7449"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

2
src/enums/dictEnum.ts

@ -1,4 +1,4 @@
export enum DictEnum {
QUESTION_TYPE = '问题属性',
TAG_TYPE = '标签',
TAG_TYPE = '功能模块',
}

5
src/views/client/issue/formSchemas.tsx

@ -22,6 +22,9 @@ export const getEditFormSchema: (
field: 'billcode',
component: 'Input',
label: '问题号',
componentProps: {
placeholder: '自动生成',
},
dynamicDisabled: true,
colProps: {
span: 24,
@ -32,7 +35,7 @@ export const getEditFormSchema: (
component: 'Input',
componentProps: {
showCount: true,
maxlength: 150,
maxlength: 50,
},
label: '问题标题',
colProps: {

50
src/views/client/issue/index.vue

@ -14,29 +14,31 @@
<template #title>
<span class="card-title"> <folder-outlined /> 问题工单目录 </span>
</template>
<a-tree
v-if="expandAll"
v-model:selectedKeys="selectedKeys"
:tree-data="treeData"
:defaultExpandAll="expandAll"
@select="onSelect"
>
<template #switcherIcon="{ switcherCls }"
><down-outlined :class="switcherCls"
/></template>
<template #title="item">
<div class="flex items-center">
<span class="mr-3 w-[100px] truncate" :title="item.title">{{ item.title }}</span>
<a-tag v-if="item.isLeaf" :color="item.color">{{ item.stateText }}</a-tag></div
>
</template>
<a-spin :spinning="loading">
<a-tree
v-if="expandAll"
v-model:selectedKeys="selectedKeys"
:tree-data="treeData"
:defaultExpandAll="expandAll"
@select="onSelect"
>
<template #switcherIcon="{ switcherCls }"
><down-outlined :class="switcherCls"
/></template>
<template #title="item">
<div class="flex items-center">
<span class="mr-3 w-[100px] truncate" :title="item.title">{{ item.title }}</span>
<a-tag v-if="item.isLeaf" :color="item.color">{{ item.stateText }}</a-tag></div
>
</template>
<!-- <template #icon="item">
<!-- <template #icon="item">
<template v-if="item.isLeaf">
<a-tag :color="item.color">{{ item.stateText }}</a-tag>
</template>
</template> -->
</a-tree>
</a-tree>
</a-spin>
</a-card>
</a-col>
@ -77,9 +79,10 @@
</div>
<DraggableModal
v-model:visible="visible"
:width="700"
:width="1000"
:bodyStyle="{
height: '70vh',
height: '55vh',
overflow: 'auto',
}"
:force-render="true"
:title="`${curRow.id ? '编辑' : '新增'}问题工单`"
@ -132,7 +135,7 @@
import Detail from '@/views/question/issue/detail.vue';
import { DraggableModal } from '@/components/core/draggable-modal';
import { useForm } from '@/components/core/schema-form';
import { getEditFormSchema } from './formSchemas.tsx';
import { getEditFormSchema } from '@/views/question/issue/formSchemas';
import { QuillEditor } from '@vueup/vue-quill';
import '@vueup/vue-quill/dist/vue-quill.snow.css';
import { type TableListItem } from '@/views/question/issue/columns';
@ -142,7 +145,7 @@
//
const treeData = ref<any[]>([]);
const expandAll = ref(false);
const loading = ref(false);
//
const selectedKeys = ref<string[]>([]);
const quillEditor = ref<InstanceType<typeof QuillEditor> | null>(null);
@ -372,6 +375,7 @@
const initTreeData = async () => {
let tree: any[] = [];
loading.value = true;
//
const res = await fetchProdList({});
console.log('res: ', res);
@ -435,6 +439,8 @@
}
treeData.value = tree;
expandAll.value = true;
loading.value = false;
console.log('treeData.value: ', treeData.value);
};
initTreeData();

17
src/views/question/issue/columns.tsx

@ -22,6 +22,9 @@ export const baseColumns: TableColumnItem[] = [
formItemProps: {
defaultValue: '',
required: false,
colProps: {
span: 6,
},
},
},
{
@ -34,10 +37,13 @@ export const baseColumns: TableColumnItem[] = [
formItemProps: {
defaultValue: '',
required: false,
colProps: {
span: 6,
},
},
},
{
title: '标签',
title: '功能模块',
align: 'center',
dataIndex: 'tags',
width: 200,
@ -70,6 +76,9 @@ export const baseColumns: TableColumnItem[] = [
formItemProps: {
defaultValue: '',
required: false,
colProps: {
span: 6,
},
},
},
{
@ -139,6 +148,9 @@ export const baseColumns: TableColumnItem[] = [
componentProps: {
valueFormat: 'YYYY-MM-DD',
},
colProps: {
span: 6,
},
},
},
// state 问题状态
@ -155,6 +167,9 @@ export const baseColumns: TableColumnItem[] = [
componentProps: {
options: stateTypeList,
},
colProps: {
span: 6,
},
},
customRender: ({ record }) => {
const { label, color } = stateTypeList.find((e) => e.value === record.state);

8
src/views/question/issue/data.ts

@ -27,6 +27,12 @@ export const stateTypeList: any = [
{
label: '已解决',
value: 4,
color: '#f50',
color: '#87d068',
},
{
label: '关闭',
value: 5,
// 灰色
color: '#d9d9d9',
},
];

6
src/views/question/issue/detail.vue

@ -9,9 +9,9 @@
修改时间
-->
<template>
<div class="bg-[#fff] p-5">
<div class="bg-[#fff] p-5 w-full">
<a-spin :spinning="loading">
<div class="my-3">
<!-- <div class="my-3">
<a-steps :current="current" size="small">
<a-step title="待处理">
<template #icon>
@ -40,7 +40,7 @@
</template>
</a-step>
</a-steps>
</div>
</div> -->
<a-tabs default-active-key="1">
<a-tab-pane key="1" tab="基础信息">

123
src/views/question/issue/formSchemas.tsx

@ -8,6 +8,7 @@ import { stateTypeList } from './data';
import { DictEnum } from '@/enums/dictEnum';
import { getDictionaryByTypeName } from '@/utils/dict';
import { fetchProdList, fetchVersionPageList } from '@/api/prodVersion';
import component from '@/locales/lang/en-US/component';
const questionTypeList = await getDictionaryByTypeName(DictEnum.QUESTION_TYPE);
// 编辑页字段
export const getEditFormSchema: (
@ -21,23 +22,25 @@ export const getEditFormSchema: (
field: 'billcode',
component: 'Input',
label: '问题号',
componentProps: {
placeholder: '自动生成',
},
dynamicDisabled: true,
colProps: {
span: 24,
span: 8,
},
},
{
field: 'title',
component: 'Input',
label: '问题属性',
field: 'arrtibute',
component: 'Select',
componentProps: {
showCount: true,
maxlength: 150,
options: questionTypeList,
},
label: '问题标题',
colProps: {
span: 12,
span: 8,
},
rules: [{ required: true }],
rules: [{ required: true, type: 'string' }],
},
{
field: 'tags',
@ -48,35 +51,23 @@ export const getEditFormSchema: (
return data;
},
multiple: true,
placeholder: '请选择标签',
placeholder: '请选择功能模块',
mode: 'tags',
allowClear: true,
},
label: '标签',
label: '功能模块',
colProps: {
span: 12,
span: 8,
},
rules: [{ required: true, type: 'array' }],
},
// {
// label: '问题属性',
// field: 'arrtibute',
// component: 'Select',
// componentProps: {
// options: questionTypeList,
// },
// colProps: {
// span: 12,
// },
// rules: [{ required: true, type: 'string' }],
// },
{
field: 'customer',
component: 'Input',
label: '客户',
colProps: {
span: 12,
span: 6,
},
},
{
@ -121,7 +112,7 @@ export const getEditFormSchema: (
},
label: '产品',
colProps: {
span: 12,
span: 6,
},
rules: [{ required: true, type: 'number' }],
},
@ -133,50 +124,34 @@ export const getEditFormSchema: (
},
label: '版本',
colProps: {
span: 12,
span: 6,
},
rules: [{ required: true, type: 'number' }],
},
{
field: 'agent',
field: 'appVersion',
component: 'Input',
label: '代理商',
label: 'APP版本',
colProps: {
span: 12,
span: 6,
},
},
{
field: 'serviceNumber',
component: 'Input',
label: '服务号',
colProps: {
span: 12,
},
},
{
field: 'zentaoNos',
component: 'Input',
label: '禅道号',
colProps: {
span: 12,
},
},
{
field: 'contacts',
component: 'Input',
label: '联系人',
colProps: {
span: 12,
span: 8,
},
rules: [{ required: true, type: 'string' }],
},
{
field: 'contactsEmail',
component: 'Input',
label: '联系人邮箱',
label: '邮箱',
colProps: {
span: 12,
span: 8,
},
rules: [
{
@ -189,9 +164,9 @@ export const getEditFormSchema: (
{
field: 'contactsMobile',
component: 'Input',
label: '联系人手机号',
label: '手机号',
colProps: {
span: 12,
span: 8,
},
rules: [
{
@ -202,13 +177,40 @@ export const getEditFormSchema: (
},
],
},
{
field: 'agent',
component: 'Input',
label: '代理商',
colProps: {
span: 6,
},
},
{
field: 'serviceNumber',
component: 'Input',
label: '服务号',
colProps: {
span: 6,
},
},
{
field: 'zentaoNos',
component: 'Input',
label: '禅道号',
colProps: {
span: 6,
},
},
{
field: 'state',
component: 'Select',
defaultValue: 0,
label: '状态',
colProps: {
span: 12,
span: 6,
},
componentProps: {
options: stateTypeList,
@ -216,6 +218,21 @@ export const getEditFormSchema: (
},
rules: [{ required: true, type: 'number' }],
},
{
field: 'title',
component: 'Input',
componentProps: {
showCount: true,
maxlength: 50,
},
label: '问题标题',
colProps: {
span: 24,
},
rules: [{ required: true }],
},
{
field: 'description',
component: 'InputTextArea',
@ -231,7 +248,6 @@ export const getEditFormSchema: (
},
rules: [{ required: true }],
},
{
label: '描述附件',
field: 'files',
@ -275,7 +291,7 @@ export const getEditFormSchema: (
),
},
colProps: {
span: 24,
span: 8,
},
rules: [{ required: false }],
},
@ -287,6 +303,7 @@ export const getEditFormSchema: (
},
// rules: [{ required: true, type: 'array' }],
slot: 'solution',
vIf: ({ formModel }) => formModel.state === 4,
},
] as any;
};

242
src/views/question/issue/index.vue

@ -9,71 +9,84 @@
修改时间
-->
<template>
<div class="issue-container" ref="issueContainerRef">
<DynamicTable
size="small"
showIndex
headerTitle="问题工单列表"
titleTooltip=""
:data-request="loadData"
:columns="columns"
row-key="id"
@resize-column="handleResizeColumn"
:row-selection="rowSelection"
:scroll="{ x: '100vw' }"
>
<template v-if="isCheckRows" #title>
<Alert class="w-full" type="info" show-icon>
<template #message>
已选 {{ isCheckRows }}
<a-button type="link" @click="rowSelection.selectedRowKeys = []">取消选择</a-button>
<div class="h-[100%]">
<div class="issue-container h-[55%] overflow-auto" ref="issueContainerRef">
<DynamicTable
size="small"
showIndex
headerTitle="问题工单列表"
titleTooltip=""
:data-request="loadData"
:columns="columns"
row-key="id"
@resize-column="handleResizeColumn"
:row-class-name="getRowClassName"
:customRow="customRow"
:row-selection="rowSelection"
:scroll="{ x: '100vw' }"
>
<template v-if="isCheckRows" #title>
<Alert class="w-full" type="info" show-icon>
<template #message>
已选 {{ isCheckRows }}
<a-button type="link" @click="rowSelection.selectedRowKeys = []">取消选择</a-button>
</template>
</Alert>
</template>
<template #toolbar>
<a-button type="primary" @click="handleAdd">新增</a-button>
<a-button
type="danger"
:disabled="!isCheckRows"
@click="delRowConfirm(rowSelection.selectedRowKeys)"
>
<DeleteOutlined /> 删除
</a-button>
</template>
</DynamicTable>
<Modal
v-model:visible="visible"
:width="1000"
:bodyStyle="{
height: '55vh',
overflow: 'auto',
}"
:title="`${curRecord.id ? '编辑' : '新增'}问题工单`"
@ok="handleOk"
@cancel="handleCancel"
:mask-closable="false"
:destroyOnClose="true"
:getContainer="() => issueContainerRef"
>
<SchemaForm>
<template #solution="{ formModel, field }">
<div class="ql-box">
<QuillEditor
ref="quillEditor"
theme="snow"
v-model:content="formModel[field]"
:options="editorOptions"
contentType="html"
/>
</div>
</template>
</Alert>
</template>
<template #toolbar>
<a-button type="primary" @click="handleAdd">新增</a-button>
<a-button
type="danger"
:disabled="!isCheckRows"
@click="delRowConfirm(rowSelection.selectedRowKeys)"
>
<DeleteOutlined /> 删除
</a-button>
</template>
</DynamicTable>
<Modal
v-model:visible="visible"
:width="700"
:bodyStyle="{
height: '70vh',
overflow: 'auto',
}"
:title="`${curRecord.id ? '编辑' : '新增'}问题工单`"
@ok="handleOk"
@cancel="handleCancel"
:mask-closable="false"
:destroyOnClose="true"
:getContainer="() => issueContainerRef"
>
<SchemaForm>
<template #solution="{ formModel, field }">
<div class="ql-box">
<QuillEditor
ref="quillEditor"
theme="snow"
v-model:content="formModel[field]"
:options="editorOptions"
contentType="html"
/>
</div>
</SchemaForm>
</Modal>
</div>
<div class="detail-container bg-white flex justify-center items-center min-h-[200px]">
<Detail :id="curRowId" v-if="curRowId"></Detail>
<a-empty v-else>
<template #description>
<span> 请选择问题工单查看 </span>
</template>
</SchemaForm>
</Modal>
</a-empty>
</div>
</div>
</template>
<script lang="tsx" setup>
import { QuillEditor } from '@vueup/vue-quill';
import Detail from './detail.vue';
import '@vueup/vue-quill/dist/vue-quill.snow.css';
import { type TableListItem, baseColumns } from './columns';
import { useTable, type OnChangeCallbackParams } from '@/components/core/dynamic-table';
@ -88,7 +101,7 @@
addToknowledge,
} from '@/api/issue';
import { computed, nextTick, ref, watch, onMounted } from 'vue';
import { message, Alert } from 'ant-design-vue';
import { message, Alert, Modal } from 'ant-design-vue';
import { useRouter } from 'vue-router';
import { useFormModal } from '@/hooks/useModal/index';
import { getEditFormSchema, getFlowFormSchema } from './formSchemas';
@ -107,6 +120,7 @@
const issueContainerRef = ref<HTMLElement | null>(null);
const curRecord = ref<Partial<TableListItem>>({});
const curRowId = ref<any>('');
const visible = ref(false);
const quillEditor = ref<InstanceType<typeof QuillEditor> | null>(null);
const editorOptions = ref({
@ -121,6 +135,24 @@
},
});
//
const getRowClassName = (record) => {
return curRowId.value === record.id ? 'highlight-row' : '';
};
const customRow = (record: TableListItem) => {
return {
style: {
cursor: 'pointer',
},
onClick: () => {
// handleView(record);
curRowId.value = record.id;
curRecord.value = record;
},
};
};
const [showModal] = useFormModal();
const [showFlowModal] = useFormModal();
@ -141,7 +173,8 @@
// watch(
// () => curRecord.value,
// (newVal) => {
// formRef?.setFieldsValue(newVal);
// console.log('newVal: ', newVal);
// formRef?.updateSchema(getEditFormSchema(newVal));
// },
// {
// immediate: true,
@ -220,27 +253,33 @@
const { state } = record;
const stateText = stateTypeList.find((item) => item.value === state)?.label;
return [
{
icon: 'searchoutlined',
color: '#3b82f6',
label: '查看',
onClick: () => handleView(record),
},
// {
// icon: 'searchoutlined',
// color: '#3b82f6',
// label: '',
// onClick: () => handleView(record),
// },
{
icon: 'edit',
color: '#3b82f6',
size: '15',
label: '修改',
// ifShow: stateText !== '',
onClick: () => handleEdit(record),
ifShow: stateText !== '关闭',
onClick: (e) => {
e.stopPropagation();
handleEdit(record);
},
},
{
icon: 'init',
size: '15',
title: '初始化',
label: '初始化',
title: '处理',
label: '处理',
ifShow: stateText === '退回',
onClick: () => changeState(record, 0),
onClick: (e) => {
e.stopPropagation();
changeState(record, 0);
},
},
{
icon: 'dev',
@ -248,15 +287,21 @@
title: '开发',
label: '开发',
ifShow: stateText === '待处理',
onClick: () => changeState(record, 2),
onClick: (e) => {
e.stopPropagation();
changeState(record, 2);
},
},
{
icon: 'back',
size: '20',
title: '退回',
label: '退回',
ifShow: stateText === '待处理',
onClick: () => changeState(record, 1),
ifShow: stateText === '开发中' || stateText === '测试中',
onClick: (e) => {
e.stopPropagation();
changeState(record, 1);
},
},
{
icon: 'test',
@ -264,7 +309,10 @@
title: '测试',
label: '测试',
ifShow: stateText === '开发中',
onClick: () => changeState(record, 3),
onClick: (e) => {
e.stopPropagation();
changeState(record, 3);
},
},
{
icon: 'end',
@ -272,7 +320,10 @@
title: '结束',
label: '结束',
ifShow: stateText === '测试中',
onClick: () => changeState(record, 4),
onClick: (e) => {
e.stopPropagation();
changeState(record, 4);
},
},
{
icon: 'knowledge',
@ -280,13 +331,31 @@
title: '添加到知识库',
label: '添加到知识库',
ifShow: stateText === '已解决',
onClick: () => handleAddToKnowledge(record),
onClick: (e) => {
e.stopPropagation();
handleAddToKnowledge(record);
},
},
{
icon: 'close',
size: '16',
title: '关闭',
label: '关闭',
ifShow: stateText !== '关闭',
onClick: (e) => {
e.stopPropagation();
changeState(record, 5);
},
},
{
icon: 'delete',
color: '#ec6f6f',
label: '删除',
onClick: () => handleDelete(record.id),
ifShow: stateText !== '关闭',
onClick: (e) => {
e.stopPropagation();
handleDelete(record.id);
},
// popConfirm: {
// title: '',
// onConfirm: () => handleDelete(record.id),
@ -382,7 +451,7 @@
state: state,
...values,
});
message.success(`${flowTitle}成功`);
message.success(`操作成功`);
dynamicTableInstance?.reload();
},
},
@ -497,24 +566,19 @@
};
const handleDelete = (id: string) => {
delRowConfirm(id);
delRowConfirm([id]);
};
/**
* @description 表格删除行
*/
const delRowConfirm = async (id: string | string[]) => {
const delRowConfirm = async (id: string[]) => {
Modal.confirm({
title: '确定要删除所选的问题工单吗?',
icon: <ExclamationCircleOutlined />,
centered: true,
onOk: async () => {
if (Array.isArray(id)) {
//
await deleteBatchIssueById(id).finally(dynamicTableInstance?.reload);
} else {
await deleteIssueById({ id }).finally(dynamicTableInstance?.reload);
}
await deleteBatchIssueById(id).finally(dynamicTableInstance?.reload);
},
});
};
@ -620,6 +684,10 @@
</script>
<style lang="less">
/* 定义高亮行的样式 */
.highlight-row {
background-color: #e6f7ff !important; /* 设置高亮背景色 */
}
.action-divider {
margin: 0 5px;
}

2
src/views/question/knowledge/columns.tsx

@ -31,7 +31,7 @@ export const baseColumns: TableColumnItem[] = [
},
},
{
title: '标签',
title: '功能模块',
align: 'center',
dataIndex: 'tags',
width: 200,

4
src/views/question/knowledge/formSchemas.tsx

@ -52,11 +52,11 @@ export const getEditFormSchema: (
return data;
},
multiple: true,
placeholder: '请选择标签',
placeholder: '请选择功能模块',
mode: 'tags',
allowClear: true,
},
label: '标签',
label: '功能模块',
colProps: {
span: 12,
},

2
src/views/question/knowledge/index.vue

@ -86,7 +86,7 @@
findOneById,
} from '@/api/knowledgeBase';
import { computed, nextTick, ref, watch, onMounted, h } from 'vue';
import { message, Alert } from 'ant-design-vue';
import { message, Alert, Modal } from 'ant-design-vue';
import { useRouter } from 'vue-router';
import { useFormModal } from '@/hooks/useModal/index';
import { getEditFormSchema } from './formSchemas';

Loading…
Cancel
Save