34 changed files with 1677 additions and 127 deletions
@ -0,0 +1,104 @@ |
|||
/* |
|||
* @Author: AaronWu 2463371514@qq.com |
|||
* @Date: 2025-04-01 09:09:04 |
|||
* @LastEditors: AaronWu 2463371514@qq.com |
|||
* @LastEditTime: 2025-04-01 11:34:26 |
|||
* @FilePath: /KnowledgeBaseSupportManage/src/api/user/index.ts |
|||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
|||
*/ |
|||
import type { BaseResponse } from '@/utils/request'; |
|||
import { request } from '@/utils/request'; |
|||
/** |
|||
* @description 查询列表 |
|||
* @param {SearchListParams} data |
|||
* @returns |
|||
*/ |
|||
export function fetchKnowledgeBaseList(data: API.SearchListParams) { |
|||
return request<BaseResponse<API.SearchListResult>>( |
|||
{ |
|||
url: 'question/list', |
|||
method: 'post', |
|||
data, |
|||
}, |
|||
{ |
|||
isGetDataDirectly: false, |
|||
}, |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* @description 查询分页列表 |
|||
* @param {SearchPageListParams} data |
|||
* @returns |
|||
*/ |
|||
export function fetchKnowledgeBasePageList(data: API.SearchPageListParams) { |
|||
return request<BaseResponse<API.SearchPageListResult>>( |
|||
{ |
|||
url: 'question/list', |
|||
method: 'post', |
|||
data, |
|||
}, |
|||
{ |
|||
isGetDataDirectly: false, |
|||
}, |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* @description 新增单条 |
|||
* @param {KnowledgeBaseType} data |
|||
* @returns |
|||
*/ |
|||
export function createKnowledgeBase(data: API.KnowledgeBaseType) { |
|||
return request({ |
|||
url: 'question/create', |
|||
method: 'post', |
|||
data, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @description 修改单条 |
|||
* @param {KnowledgeBaseType} data |
|||
* @returns |
|||
*/ |
|||
export function updateKnowledgeBase(data: API.KnowledgeBaseType) { |
|||
return request({ |
|||
url: 'question/update', |
|||
method: 'post', |
|||
data, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @description 查询单条 |
|||
*/ |
|||
export function findOneById(params: { id: string }) { |
|||
return request({ |
|||
url: `question/getById`, |
|||
method: 'get', |
|||
params, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @description 删除单条 ?id=${data.id} |
|||
*/ |
|||
export function deleteKnowledgeBaseById(params: API.DeleteKnowledgeBaseParams) { |
|||
return request({ |
|||
url: `question/delById`, |
|||
method: 'post', |
|||
params, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @description 删除多条 |
|||
*/ |
|||
export function deleteBatchKnowledgeBaseById(data: API.DeleteBatchKnowledgeBaseParams) { |
|||
return request({ |
|||
url: `question/delete`, |
|||
method: 'delete', |
|||
data, |
|||
}); |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
declare namespace API { |
|||
/** 问题工单类型 */ |
|||
type KnowledgeBaseType = { |
|||
id?: string; |
|||
agent?: string; // 代理商
|
|||
attribute?: string; // 问题属性
|
|||
billcode?: string; // 问题号
|
|||
contacts?: string; // 联系人
|
|||
contactsEmail?: string; // 联系人邮箱
|
|||
contactsMobile?: string; // 联系人手机号
|
|||
createTime?: string; // 创建时间
|
|||
createUserid?: number; // 创建人ID
|
|||
customer?: string; // 客户
|
|||
description?: string; // 问题描述
|
|||
dr?: number; // 删除标记
|
|||
product?: string; // 产品
|
|||
productId?: string; // 产品ID
|
|||
version?: string; // 版本
|
|||
versionId?: string; // 版本ID
|
|||
serviceNumber?: string; // 服务号
|
|||
state?: number; // 状态
|
|||
title?: string; // 问题标题
|
|||
updateTime?: string; // 更新时间
|
|||
updateUserid?: number; // 更新人ID
|
|||
version?: string; // 版本
|
|||
fileList?: any[]; // 附件列表
|
|||
}; |
|||
|
|||
type CreateKnowledgeBaseParams = { |
|||
id?: string; |
|||
agent?: string; // 代理商
|
|||
attribute?: string; // 问题属性
|
|||
billcode?: string; // 问题号
|
|||
contacts?: string; // 联系人
|
|||
contactsEmail?: string; // 联系人邮箱
|
|||
contactsMobile?: string; // 联系人手机号
|
|||
createTime?: string; // 创建时间
|
|||
createUserid?: number; // 创建人ID
|
|||
customer?: string; // 客户
|
|||
description?: string; // 问题描述
|
|||
dr?: number; // 删除标记
|
|||
product?: string; // 产品
|
|||
serviceNumber?: string; // 服务号
|
|||
state?: number; // 状态
|
|||
title?: string; // 问题标题
|
|||
updateTime?: string; // 更新时间
|
|||
updateUserid?: number; // 更新人ID
|
|||
version?: string; // 版本
|
|||
fileList?: any[]; // 附件列表
|
|||
}; |
|||
|
|||
type DeleteKnowledgeBaseParams = { |
|||
id: string; |
|||
}; |
|||
|
|||
type DeleteBatchKnowledgeBaseParams = string[]; |
|||
} |
|||
@ -0,0 +1,106 @@ |
|||
import type { BaseResponse } from '@/utils/request'; |
|||
import { request } from '@/utils/request'; |
|||
|
|||
/** |
|||
* @description 查询类别列表 |
|||
* @param {SearchPageListParams} data |
|||
* @returns |
|||
*/ |
|||
export function fetchProdList(data) { |
|||
return request<BaseResponse<API.SearchPageListResult>>({ |
|||
url: `/product/list`, |
|||
method: 'post', |
|||
data, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @description 新增单条 |
|||
* @param {ProdType} data |
|||
* @returns |
|||
*/ |
|||
export function createProd(data: API.ProdType) { |
|||
return request({ |
|||
url: `/product/create`, |
|||
method: 'post', |
|||
data, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @description 修改单条 |
|||
* @param {ProdType} data |
|||
* @returns |
|||
*/ |
|||
export function updateProd(data: API.ProdType) { |
|||
return request({ |
|||
url: `/product/update`, |
|||
method: 'post', |
|||
data, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @description 删除 |
|||
*/ |
|||
export function deleteProd(data: API.DeleteProdParams) { |
|||
return request({ |
|||
url: `/product/delete?id=${data.id}`, |
|||
method: 'delete', |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @description 根据字典类型查询字典值分页列表 |
|||
* @param {SearchPageListParams} params |
|||
* @returns |
|||
*/ |
|||
export function fetchVersionPageList(params: API.SearchPageListParams) { |
|||
return request<BaseResponse<API.SearchPageListResult>>( |
|||
{ |
|||
url: `/productVersion/list`, |
|||
method: 'get', |
|||
params, |
|||
}, |
|||
{ |
|||
isGetDataDirectly: false, |
|||
}, |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* @description 新增单条 |
|||
* @param {VersionType} data |
|||
* @returns |
|||
*/ |
|||
export function createVersion(data: API.VersionType) { |
|||
return request({ |
|||
url: `/productVersion/create`, |
|||
method: 'post', |
|||
data, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @description 修改单条 |
|||
* @param {VersionType} data |
|||
* @returns |
|||
*/ |
|||
export function updateVersion(data: API.VersionType) { |
|||
return request({ |
|||
url: `/productVersion/update`, |
|||
method: 'post', |
|||
data, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @description 删除多条 |
|||
*/ |
|||
export function deleteBatchVersionById(data: API.DeleteBatchVersionParams) { |
|||
return request({ |
|||
url: `/productVersion/delete`, |
|||
method: 'delete', |
|||
data, |
|||
}); |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
declare namespace API { |
|||
type ProdType = { |
|||
id?: string; |
|||
name: string; |
|||
}; |
|||
|
|||
type DeleteProdParams = { |
|||
id: string; |
|||
}; |
|||
|
|||
type VersionType = { |
|||
id?: string; |
|||
productId: string; |
|||
name: string; |
|||
remark?: string; |
|||
}; |
|||
|
|||
type DeleteVersionParams = { |
|||
id: string; |
|||
}; |
|||
|
|||
type DeleteBatchVersionParams = string[]; |
|||
} |
|||
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 646 B |
|
After Width: | Height: | Size: 897 B |
|
After Width: | Height: | Size: 721 B |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 476 B |
@ -0,0 +1,3 @@ |
|||
export enum DictEnum { |
|||
QUESTION_TYPE = '问题属性', |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
import { fetchDictValueListByType } from '@/api/dict'; |
|||
|
|||
export const getDictionaryByTypeName = async (name: string) => { |
|||
const res = await fetchDictValueListByType({ typeName: name }); |
|||
if (res && Array.isArray(res) && res.length) { |
|||
return res |
|||
.filter((e) => e.enable === 1) |
|||
.map((e) => { |
|||
return { |
|||
label: e.dictValue, |
|||
value: e.dictValue, |
|||
}; |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
export const getLabelByDictId = ( |
|||
options: Array<{ label: string; value: string }>, |
|||
id: string, |
|||
) => {}; |
|||
@ -0,0 +1,150 @@ |
|||
<!-- |
|||
功能:功能描述 |
|||
作者:Aaron |
|||
时间:2023年07月31日 11:51:23 |
|||
版本:v1.0 |
|||
修改记录: |
|||
修改内容: |
|||
修改人员: |
|||
修改时间: |
|||
--> |
|||
<template> |
|||
<div class="bg-[#fff] p-5"> |
|||
<a-spin :spinning="loading"> |
|||
<div class="my-3"> |
|||
<a-steps :current="current" size="small"> |
|||
<a-step title="初始化"> |
|||
<template #icon> |
|||
<SvgIcon :size="22" name="init" /> |
|||
</template> |
|||
</a-step> |
|||
|
|||
<a-step title="退回"> |
|||
<template #icon> |
|||
<SvgIcon :size="24" name="back" /> |
|||
</template> |
|||
</a-step> |
|||
<a-step title="开发"> |
|||
<template #icon> |
|||
<SvgIcon :size="24" name="dev" /> |
|||
</template> |
|||
</a-step> |
|||
<a-step title="测试"> |
|||
<template #icon> |
|||
<SvgIcon :size="24" name="test" /> |
|||
</template> |
|||
</a-step> |
|||
<a-step title="结束"> |
|||
<template #icon> |
|||
<SvgIcon :size="24" name="end" /> |
|||
</template> |
|||
</a-step> |
|||
</a-steps> |
|||
</div> |
|||
|
|||
<a-tabs default-active-key="1"> |
|||
<a-tab-pane key="1" tab="基础信息"> |
|||
<SchemaForm> </SchemaForm> |
|||
</a-tab-pane> |
|||
<a-tab-pane key="2" tab="处理历史"> |
|||
<a-steps progress-dot :current="historyList.length - 1" direction="vertical"> |
|||
<a-step |
|||
v-for="(item, index) in historyList" |
|||
:key="index" |
|||
:title="item.title" |
|||
:description="item.message" |
|||
/> |
|||
</a-steps> |
|||
</a-tab-pane> |
|||
</a-tabs> |
|||
</a-spin> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { useForm } from '@/components/core/schema-form'; |
|||
import { getEditFormSchema } from './formSchemas'; |
|||
import { useRoute } from 'vue-router'; |
|||
import { onMounted, ref } from 'vue'; |
|||
import { findOneById } from '@/api/issue'; |
|||
import { SvgIcon } from '@/components/basic/svg-icon'; |
|||
import { stateTypeList } from './data'; |
|||
const route = useRoute(); |
|||
|
|||
const loading = ref(false); |
|||
|
|||
const historyList = ref< |
|||
Array<{ |
|||
status: number; |
|||
message: string; |
|||
title?: string; |
|||
}> |
|||
>([ |
|||
{ |
|||
status: 0, |
|||
message: '初始化', |
|||
}, |
|||
{ |
|||
status: 1, |
|||
message: '退回', |
|||
}, |
|||
{ |
|||
status: 2, |
|||
message: '开发', |
|||
}, |
|||
{ |
|||
status: 3, |
|||
message: '测试', |
|||
}, |
|||
{ |
|||
status: 4, |
|||
message: '结束', |
|||
}, |
|||
]); |
|||
|
|||
historyList.value = historyList.value.map((item) => { |
|||
return { |
|||
...item, |
|||
title: stateTypeList.find((e) => e.value === item.status)?.label, |
|||
}; |
|||
}); |
|||
|
|||
const current = ref(0); |
|||
|
|||
const { id } = route.query; |
|||
|
|||
const [SchemaForm, formRef] = useForm({ |
|||
labelWidth: 150, |
|||
schemas: getEditFormSchema({}, true), |
|||
showActionButtonGroup: false, |
|||
actionColOptions: { |
|||
span: 24, |
|||
}, |
|||
submitButtonOptions: { |
|||
text: '保存', |
|||
}, |
|||
disabled: true, |
|||
}); |
|||
|
|||
onMounted(async () => { |
|||
loading.value = true; |
|||
const res = await findOneById({ id: id as string }); |
|||
loading.value = false; |
|||
|
|||
if (res?.files && Array.isArray(res.files) && res.files.length) { |
|||
res.files = res.files.map((e) => { |
|||
return { |
|||
name: e.originalFilename, |
|||
url: e.url, |
|||
id: e.id, |
|||
}; |
|||
}); |
|||
} |
|||
|
|||
current.value = res?.state; |
|||
|
|||
formRef?.setFieldsValue(res); |
|||
formRef?.clearValidate(); |
|||
}); |
|||
</script> |
|||
<style lang="less" scoped></style> |
|||
@ -0,0 +1,325 @@ |
|||
<template> |
|||
<div class="bg-white m-4 mr-2 overflow-hidden h-full"> |
|||
<BasicTree |
|||
ref="treeRef" |
|||
:actionList="actionList" |
|||
:beforeRightClick="getRightMenuList" |
|||
:checkable="false" |
|||
:clickRowToExpand="false" |
|||
:treeData="treeData" |
|||
checkStrictly |
|||
:defaultExpandAll="true" |
|||
search |
|||
toolbar |
|||
:highlight="true" |
|||
@select="handleSelect" |
|||
:toolbarStrictly="false" |
|||
> |
|||
<!-- <template #titleBefore="item"> </template> --> |
|||
</BasicTree> |
|||
<div v-if="query" class="m-4 flex justify-center"> |
|||
<a-button class="w-[80%]" type="primary" @click="handleReset()">重置</a-button> |
|||
<!-- <Checkbox v-model:checked="recursion" @change="handleQuery()">本级及子级</Checkbox> --> |
|||
</div> |
|||
<div v-else class="m-4 flex justify-center"> |
|||
<a-button type="primary" class="w-[80%]" @click="openTypeModal({})"> |
|||
{{ '新增产品' }} |
|||
</a-button> |
|||
<!-- <a-button |
|||
v-permission="{ action: RoleEnum.DICT_DELETE, effect: 'disabled' }" |
|||
class="mr-2" |
|||
@click="handleBatchDelete()" |
|||
> |
|||
{{ '删除' }} |
|||
</a-button> --> |
|||
</div> |
|||
<!-- <OrgRole @register="registerModal" @success="handleSuccess" /> --> |
|||
</div> |
|||
</template> |
|||
<script lang="tsx"> |
|||
import { defineComponent, h, onMounted, ref, unref } from 'vue'; |
|||
import { Checkbox, message, Tag } from 'ant-design-vue'; // antd组件 |
|||
import { useI18n } from '@/hooks/useI18n'; |
|||
import { |
|||
BasicTree, |
|||
ContextMenuItem, |
|||
TreeActionItem, |
|||
TreeActionType, |
|||
TreeItem, |
|||
} from '@/components/core/Tree'; |
|||
import { eachTree, findChildrenByParentId, findNodeByKey } from '@/utils/helper/treeHelper'; |
|||
import { RoleEnum } from '@/enums/roleEnum'; |
|||
import { OrgTypeEnum } from '@/enums/biz/base'; |
|||
import { useFormModal } from '@/hooks/useModal/index'; |
|||
|
|||
import { createProd, deleteProd, fetchProdList, updateProd } from '@/api/prodVersion'; |
|||
// import { useModal } from '@/components/Modal'; |
|||
// import OrgRole from './orgRole/index.vue'; |
|||
import { useMessage } from '@/hooks/useMessage'; |
|||
import { mockTree } from './mockData'; |
|||
import { Nullable } from '@/utils/types'; |
|||
import { prodFormSchema } from './formSchemas'; |
|||
import { TableListItem } from './columns'; |
|||
import { omit } from 'lodash-es'; |
|||
import { isArray } from '@/utils/is'; |
|||
|
|||
export default defineComponent({ |
|||
name: 'BaseProdValueManagement', |
|||
components: { |
|||
BasicTree, |
|||
// OrgRole, |
|||
Checkbox, |
|||
Tag, |
|||
}, |
|||
props: { |
|||
query: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
}, |
|||
emits: ['select', 'add', 'edit', 'change', 'reset'], |
|||
setup(props, { emit }) { |
|||
const { t } = useI18n(); |
|||
const { createMessage, createConfirm } = useMessage(); |
|||
|
|||
const treeRef = ref<Nullable<TreeActionType>>(null); |
|||
const treeData = ref<TreeItem[]>([]); |
|||
const recursion = ref<boolean>(false); |
|||
// 绑定角色 |
|||
// const [registerModal, { openModal }] = useModal(); |
|||
|
|||
const [showModal] = useFormModal(); |
|||
|
|||
/** |
|||
* @description 打开弹窗 |
|||
*/ |
|||
const openTypeModal = async (record: Partial<TableListItem> = {}, isReadOnly = false) => { |
|||
const [formRef] = await showModal<any>({ |
|||
modalProps: { |
|||
title: `${isReadOnly ? '查看' : record.id ? '编辑' : '新增'}产品`, |
|||
width: 500, |
|||
onFinish: async (values) => { |
|||
values.id = record.id; |
|||
await (record.id ? updateProd : createProd)(values); |
|||
message.success(`${record.id ? '编辑' : '新增'}成功`); |
|||
fetch(); |
|||
}, |
|||
}, |
|||
formProps: { |
|||
labelWidth: 100, |
|||
schemas: prodFormSchema, |
|||
autoSubmitOnEnter: true, |
|||
}, |
|||
}); |
|||
formRef?.setFieldsValue(record); |
|||
}; |
|||
|
|||
function getTree() { |
|||
const tree = unref(treeRef); |
|||
if (!tree) { |
|||
throw new Error('树结构加载失败,请刷新页面'); |
|||
} |
|||
return tree; |
|||
} |
|||
|
|||
onMounted(() => { |
|||
fetch(); |
|||
}); |
|||
|
|||
// 加载数据 |
|||
async function fetch() { |
|||
const types = (await fetchProdList({})) as unknown as TreeItem[]; |
|||
// const types = mockTree; |
|||
console.log('types: ', types); |
|||
treeData.value = types.map((e) => { |
|||
return { |
|||
...e, |
|||
name: e.name, |
|||
editable: true, |
|||
}; |
|||
}) as unknown as TreeItem[]; |
|||
eachTree(treeData.value, (item) => { |
|||
item.key = item.id; |
|||
item.title = item.name; |
|||
item.slots = { titleBefore: 'titleBefore' }; |
|||
return item; |
|||
}); |
|||
console.log('treeData.value: ', treeData.value); |
|||
console.log('[treeData.value[0].id]: ', [treeData.value[0].id]); |
|||
|
|||
if (isArray(treeData.value) && treeData.value.length > 0) { |
|||
getTree().setSelectedKeys([treeData.value[0].id]); |
|||
handleSelect([treeData.value[0].id]); |
|||
} |
|||
// setTimeout(() => { |
|||
// getTree().filterByLevel(2); |
|||
// }, 0); |
|||
} |
|||
|
|||
// 选择节点 |
|||
function handleSelect(keys: string[]) { |
|||
console.log('keys: ', keys); |
|||
if (keys[0]) { |
|||
const node = findNodeByKey(keys[0], treeData.value); |
|||
const parent = findNodeByKey(node?.parentId, treeData.value); |
|||
let childrenIds: string[] = []; |
|||
if (recursion.value) { |
|||
childrenIds = findChildrenByParentId(keys[0], treeData.value); |
|||
} else { |
|||
childrenIds = [node.id]; |
|||
} |
|||
emit('select', parent, node, childrenIds); |
|||
} else { |
|||
emit('select', {}, {}); |
|||
} |
|||
} |
|||
|
|||
let actionList: TreeActionItem[] = []; |
|||
let getRightMenuList = (_: any): ContextMenuItem[] => { |
|||
return []; |
|||
}; |
|||
if (!props.query) { |
|||
// 悬停图标 |
|||
actionList = [ |
|||
{ |
|||
render: (node) => { |
|||
if (node.editable) { |
|||
return h( |
|||
'a', |
|||
{ |
|||
class: 'ml-2', |
|||
onClick: (e: Event) => { |
|||
e?.stopPropagation(); |
|||
e?.preventDefault(); |
|||
const current = findNodeByKey(node?.id, treeData.value); |
|||
// const parent = findNodeByKey(node?.parentId, treeData.value); |
|||
// emit('edit', parent, current); |
|||
openTypeModal(current); |
|||
}, |
|||
}, |
|||
'编辑', |
|||
); |
|||
} |
|||
}, |
|||
}, |
|||
|
|||
{ |
|||
render: (node) => { |
|||
if (node.editable) { |
|||
return h( |
|||
'a', |
|||
{ |
|||
class: 'ml-2', |
|||
onClick: (e: Event) => { |
|||
e?.stopPropagation(); |
|||
e?.preventDefault(); |
|||
batchDelete(node.id); |
|||
}, |
|||
}, |
|||
'删除', |
|||
); |
|||
} |
|||
}, |
|||
}, |
|||
]; |
|||
|
|||
// 右键菜单 |
|||
// getRightMenuList = (node: any): ContextMenuItem[] => { |
|||
// return [ |
|||
// { |
|||
// label: '编辑', |
|||
// auth: RoleEnum.DICT_EDIT, |
|||
// handler: () => { |
|||
// const current = findNodeByKey(unref(node)?.id, treeData.value); |
|||
// const parent = findNodeByKey(unref(node)?.parentId, treeData.value); |
|||
// emit('edit', parent, current); |
|||
// }, |
|||
// }, |
|||
// { |
|||
// label: '删除', |
|||
// auth: RoleEnum.DICT_DELETE, |
|||
// handler: () => { |
|||
// batchDelete([unref(node).id]); |
|||
// }, |
|||
// }, |
|||
// ]; |
|||
// }; |
|||
} |
|||
|
|||
// 执行批量删除 |
|||
async function batchDelete(id: string) { |
|||
createConfirm({ |
|||
iconType: 'warning', |
|||
content: '选中节点及其子结点将被永久删除, 是否确定删除?', |
|||
onOk: async () => { |
|||
try { |
|||
await deleteProd({ id }); |
|||
createMessage.success(t('common.tips.deleteSuccess')); |
|||
fetch(); |
|||
} catch (e) {} |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
// 点击树外面的 新增 |
|||
function handleAdd() { |
|||
emit('add', findNodeByKey('0', treeData.value)); |
|||
} |
|||
|
|||
// 点击树外面的 批量删除 |
|||
// function handleBatchDelete() { |
|||
// const { checked } = getTree().getCheckedKeys() as { |
|||
// checked: string[]; |
|||
// halfChecked: string[]; |
|||
// }; |
|||
// if (!checked || checked.length <= 0) { |
|||
// createMessage.warning(t('common.tips.pleaseSelectTheData')); |
|||
// return; |
|||
// } |
|||
// batchDelete(checked); |
|||
// } |
|||
|
|||
// 切换显示方式 |
|||
function changeDisplay() { |
|||
emit('change', '2'); |
|||
} |
|||
|
|||
// 重置 |
|||
function handleReset() { |
|||
getTree().setSelectedKeys([]); |
|||
emit('reset'); |
|||
} |
|||
|
|||
// 选择 本级及子级 |
|||
function handleQuery() { |
|||
handleSelect(getTree().getSelectedKeys() as string[]); |
|||
} |
|||
|
|||
// 新增或编辑成功回调 |
|||
function handleSuccess() { |
|||
fetch(); |
|||
} |
|||
|
|||
return { |
|||
t, |
|||
treeRef, |
|||
treeData, |
|||
fetch, |
|||
handleAdd, |
|||
// handleBatchDelete, |
|||
getRightMenuList, |
|||
actionList, |
|||
handleSelect, |
|||
changeDisplay, |
|||
handleReset, |
|||
handleQuery, |
|||
RoleEnum, |
|||
// registerModal, |
|||
handleSuccess, |
|||
recursion, |
|||
OrgTypeEnum, |
|||
openTypeModal, |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
@ -0,0 +1,30 @@ |
|||
/* |
|||
* @Author: AaronWu 2463371514@qq.com |
|||
* @Date: 2025-04-01 13:43:34 |
|||
* @LastEditors: AaronWu 2463371514@qq.com |
|||
* @LastEditTime: 2025-04-01 13:52:02 |
|||
* @FilePath: /IssueSupportManage/src/views/system/dictionary/columns.tsx |
|||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
|||
*/ |
|||
import type { TableColumn } from '@/components/core/dynamic-table'; |
|||
|
|||
export type TableListItem = API.VersionType; |
|||
export type TableColumnItem = TableColumn<TableListItem>; |
|||
|
|||
// 数据项类型
|
|||
// export type ListItemType = typeof tableData[number];
|
|||
// 使用TableColumn<ListItemType> 将会限制dataIndex的类型,但换来的是dataIndex有类型提示
|
|||
export const baseColumns: TableColumnItem[] = [ |
|||
{ |
|||
title: '版本名称', |
|||
align: 'center', |
|||
dataIndex: 'name', |
|||
width: 150, |
|||
ellipsis: true, |
|||
resizable: true, |
|||
formItemProps: { |
|||
defaultValue: '', |
|||
required: false, |
|||
}, |
|||
}, |
|||
]; |
|||
@ -0,0 +1,48 @@ |
|||
import type { FormSchema } from '@/components/core/schema-form/'; |
|||
|
|||
// 列表编辑页字段
|
|||
export const editFormSchema: FormSchema[] = [ |
|||
{ |
|||
field: 'id', |
|||
label: 'ID', |
|||
component: 'Input', |
|||
vShow: false, |
|||
}, |
|||
{ |
|||
label: '版本名称', |
|||
field: 'name', |
|||
component: 'Input', |
|||
colProps: { |
|||
span: 24, |
|||
}, |
|||
rules: [{ required: true }], |
|||
}, |
|||
{ |
|||
label:'备注', |
|||
field: 'remark', |
|||
component: 'InputTextArea', |
|||
colProps: { |
|||
span: 24, |
|||
}, |
|||
rules: [{ required: false }], |
|||
} |
|||
]; |
|||
|
|||
// 新增产品表单
|
|||
export const prodFormSchema: FormSchema[] = [ |
|||
{ |
|||
field: 'id', |
|||
label: 'ID', |
|||
component: 'Input', |
|||
vShow: false, |
|||
}, |
|||
{ |
|||
label: '名称', |
|||
field: 'name', |
|||
component: 'Input', |
|||
colProps: { |
|||
span: 24, |
|||
}, |
|||
rules: [{ required: true }], |
|||
}, |
|||
]; |
|||
@ -0,0 +1,241 @@ |
|||
<!-- |
|||
* @Author: AaronWu 2463371514@qq.com |
|||
* @Date: 2025-04-01 13:17:38 |
|||
* @LastEditors: AaronWu 2463371514@qq.com |
|||
* @LastEditTime: 2025-04-01 14:43:11 |
|||
* @FilePath: /IssueSupportManage/src/views/system/dictionary/index.vue |
|||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE |
|||
--> |
|||
<template> |
|||
<SplitPanel> |
|||
<template #left-content> |
|||
<BaseTypeTree ref="treeRef" class="" @reset="handleReset" @select="handleTypeSelect" /> |
|||
</template> |
|||
<template #right-content> |
|||
<DynamicTable |
|||
search-type="drawer" |
|||
size="small" |
|||
showIndex |
|||
headerTitle="版本列表" |
|||
titleTooltip="" |
|||
:data-request="loadData" |
|||
:columns="columns" |
|||
row-key="id" |
|||
@resize-column="handleResizeColumn" |
|||
:row-selection="rowSelection" |
|||
> |
|||
<template v-if="isCheckRows" #[`title`]> |
|||
<Alert class="w-full" type="info" show-icon> |
|||
<template #message> |
|||
已选 {{ rowSelection.selectedRowKeys.length }} 项 |
|||
<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" |
|||
v-if="isCheckRows" |
|||
@click="delRowConfirm(rowSelection.selectedRowKeys)" |
|||
> |
|||
<DeleteOutlined /> 删除 |
|||
</a-button> |
|||
</template> |
|||
</DynamicTable> |
|||
</template> |
|||
</SplitPanel> |
|||
</template> |
|||
|
|||
<script lang="tsx" setup> |
|||
import { computed, h, ref } from 'vue'; |
|||
import { SplitPanel } from '@/components/basic/split-panel'; |
|||
import BaseTypeTree from './Tree.vue'; |
|||
import { OnChangeCallbackParams, useTable } from '@/components/core/dynamic-table'; |
|||
import { baseColumns } from './columns'; |
|||
import { message, Modal, Alert } from 'ant-design-vue'; |
|||
import { ExclamationCircleOutlined, DeleteOutlined } from '@ant-design/icons-vue'; |
|||
import { useFormModal } from '@/hooks/useModal'; |
|||
import { editFormSchema } from './formSchemas'; |
|||
import { |
|||
createVersion, |
|||
deleteBatchVersionById, |
|||
fetchVersionPageList, |
|||
updateVersion, |
|||
} from '@/api/prodVersion'; |
|||
const columns: any = [ |
|||
...baseColumns, |
|||
{ |
|||
title: '操作', |
|||
width: 50, |
|||
dataIndex: 'ACTION', |
|||
hideInSearch: true, |
|||
align: 'center', |
|||
fixed: 'right', |
|||
actions: ({ record }) => [ |
|||
{ |
|||
color: '#3b82f6', |
|||
size: '15', |
|||
label: '编辑', |
|||
onClick: () => handleEdit(record), |
|||
}, |
|||
{ |
|||
color: '#ec6f6f', |
|||
label: '删除', |
|||
onClick: () => handleDelete(record.id), |
|||
}, |
|||
], |
|||
}, |
|||
]; |
|||
const treeRef = ref<InstanceType<typeof BaseTypeTree>>(); |
|||
const [showModal] = useFormModal(); |
|||
|
|||
const currentType = ref<API.DictType>({ |
|||
id: '', |
|||
name: '', |
|||
}); |
|||
|
|||
const [DynamicTable, dynamicTableInstance] = useTable(); |
|||
|
|||
function handleTypeSelect(_parent = {}, record: API.DictType, childrenIds = []) { |
|||
console.log('record: ', record); |
|||
currentType.value = record; |
|||
dynamicTableInstance?.reload(); |
|||
} |
|||
|
|||
function handleReset() { |
|||
currentType.value = { |
|||
id: '', |
|||
name: '', |
|||
}; |
|||
dynamicTableInstance?.reload(); |
|||
} |
|||
|
|||
/** |
|||
* @description 表格删除行 |
|||
*/ |
|||
const delRowConfirm = async (ids: string[]) => { |
|||
Modal.confirm({ |
|||
title: '确定要删除所选的版本吗?', |
|||
icon: <ExclamationCircleOutlined />, |
|||
centered: true, |
|||
onOk: async () => { |
|||
await deleteBatchVersionById(ids).finally(dynamicTableInstance?.reload); |
|||
}, |
|||
}); |
|||
}; |
|||
|
|||
const handleAdd = () => { |
|||
// openDrawer(true, { type: ActionEnum.ADD, record: {} }); |
|||
|
|||
// modal方式 |
|||
openModal({}); |
|||
}; |
|||
|
|||
const handleEdit = (record: API.VersionType) => { |
|||
if (record.enable === 1) { |
|||
message.warning('启用状态不可编辑'); |
|||
return; |
|||
} |
|||
|
|||
console.log('record: ', record); |
|||
|
|||
//modal 方式打开 |
|||
openModal(record); |
|||
}; |
|||
|
|||
const handleDelete = (id: string) => { |
|||
delRowConfirm([id]); |
|||
}; |
|||
/** |
|||
* @description 打开弹窗 |
|||
*/ |
|||
const openModal = async (record: Partial<API.VersionType> = {}, isReadOnly = false) => { |
|||
if (!currentType.value.id) { |
|||
message.warning('请先选择左侧产品'); |
|||
return; |
|||
} |
|||
const [formRef] = await showModal<any>({ |
|||
modalProps: { |
|||
title: `${isReadOnly ? '查看' : record.id ? '编辑' : '新增'}版本`, |
|||
width: 700, |
|||
onFinish: async (values) => { |
|||
console.log('新增/编辑版本', values); |
|||
values.id = record.id; |
|||
values.productId = currentType.value.id; |
|||
await (record.id ? updateVersion : createVersion)(values); |
|||
message.success(`${record.id ? '编辑' : '新增'}成功`); |
|||
dynamicTableInstance?.reload(); |
|||
}, |
|||
footer: isReadOnly ? null : undefined, |
|||
}, |
|||
formProps: { |
|||
labelWidth: 100, |
|||
schemas: editFormSchema, |
|||
autoSubmitOnEnter: true, |
|||
disabled: isReadOnly, |
|||
}, |
|||
}); |
|||
|
|||
formRef?.setFieldsValue(record); |
|||
// if (record?.id) { |
|||
// const { roles } = await getTenantInfo({ employeeId: record.id }); |
|||
// formRef?.setFieldsValue({ roles }); |
|||
// } |
|||
}; |
|||
|
|||
const rowSelection = ref<any>({ |
|||
selectedRowKeys: [] as string[], |
|||
onChange: (selectedRowKeys: string[], selectedRows: API.VersionType[]) => { |
|||
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows); |
|||
rowSelection.value.selectedRowKeys = selectedRowKeys; |
|||
}, |
|||
}); |
|||
|
|||
// 是否勾选了表格行 |
|||
const isCheckRows = computed(() => rowSelection.value.selectedRowKeys.length); |
|||
|
|||
const loadData = async ( |
|||
params, |
|||
onChangeParams?: OnChangeCallbackParams, |
|||
): Promise<API.TableListResult> => { |
|||
console.log('params', params); |
|||
console.log('onChangeParams', onChangeParams); |
|||
|
|||
if (!currentType.value.id) { |
|||
return { |
|||
list: [], |
|||
pagination: { |
|||
total: 0, |
|||
size: params.limit, |
|||
...params, |
|||
}, |
|||
}; |
|||
} |
|||
|
|||
const res = await fetchVersionPageList({ |
|||
...params, |
|||
productId: currentType.value.id, |
|||
current: params.page, |
|||
size: params.limit, |
|||
}); |
|||
console.log('res: ', res); |
|||
rowSelection.value.selectedRowKeys = []; |
|||
|
|||
return { |
|||
list: res.data, |
|||
pagination: { |
|||
total: Number(res.data.total), |
|||
...params, |
|||
}, |
|||
}; |
|||
}; |
|||
const handleResizeColumn = (w, col) => { |
|||
// console.log('w', w, col); |
|||
col.width = w; |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="less" scoped></style> |
|||
@ -0,0 +1,14 @@ |
|||
/* |
|||
* @Author: AaronWu 2463371514@qq.com |
|||
* @Date: 2025-04-01 13:24:31 |
|||
* @LastEditors: AaronWu 2463371514@qq.com |
|||
* @LastEditTime: 2025-04-01 13:25:12 |
|||
* @FilePath: /IssueSupportManage/src/views/system/dictionary/mockData.ts |
|||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
|||
*/ |
|||
export const mockTree: any[] = [ |
|||
{ |
|||
id: 1, |
|||
name: '字典类别', |
|||
}, |
|||
]; |
|||
Loading…
Reference in new issue