feat: 新增产品分类模块

This commit is contained in:
xiongqian 2023-01-28 21:56:11 +08:00
parent 7f321213a8
commit 37c4e654ee
7 changed files with 474 additions and 5 deletions

View File

@ -0,0 +1,25 @@
// 产品分类
import server from '@/utils/request'
import { CategoryItem } from '@/views/device/Category/typings'
/**
*
*/
export const queryTree = (params?: Record<string, any>) => server.post<CategoryItem>('/device/category/_tree', params)
/**
*
*/
export const saveTree = (data: any) =>server.post('/device/category', data)
/**
* Id修改
*/
export const updateTree = (data: any, id:string) => server.put(`/device/category/${id}`, data)
/**
* Id删除数据
*/
export const deleteTree = (id:string) => server.remove(`/device/category/${id}`)

View File

@ -26,7 +26,8 @@ const iconKeys = [
'ExportOutlined',
'SyncOutlined',
'ExclamationCircleOutlined',
'UploadOutlined'
'UploadOutlined',
'PlusCircleOutlined'
]
const Icon = (props: {type: string}) => {

View File

@ -128,4 +128,10 @@ export default [
path: '/northbound/AliCloud',
component: () => import('@/views/northbound/AliCloud/index.vue')
},
// 产品分类
{
path: '/iot/device/Category',
component: () => import('@/views/device/Category/index.vue')
}
]

View File

@ -0,0 +1,203 @@
<!-- 新增编辑弹窗 -->
<template>
<a-modal
:title="props.title"
:maskClosable="false"
destroy-on-close
v-model:visible="visible"
@ok="submitData"
@cancel="close"
okText="确定"
cancelText="取消"
v-bind="layout"
>
<a-form
layout="vertical"
v-model="formModel"
:rules="rules"
ref="formRef"
>
<a-form-item label="名称" name="name" v-bind="validateInfos.name">
<a-input v-model:value="formModel.name" :maxlength="64" />
</a-form-item>
<a-form-item
label="排序"
name="sortIndex"
v-bind="validateInfos.sortIndex"
>
<a-input-number
style="width: 100%"
id="inputNumber"
v-model:value="formModel.sortIndex"
:min="1"
/>
</a-form-item>
<a-form-item label="说明">
<a-textarea
v-model:value="formModel.description"
show-count
:maxlength="200"
/>
</a-form-item>
</a-form>
</a-modal>
</template>
<script setup lang="ts" name="modifyModal">
import { PropType } from 'vue';
import { Form } from 'ant-design-vue';
import { queryTree } from '@/api/device/category';
import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface';
import { list } from '@/api/iot-card/home';
const emits = defineEmits(['refresh']);
const formRef = ref();
const useForm = Form.useForm;
const props = defineProps({
formData: {
type: Object as PropType<Record<string, any>>,
default: () => {},
},
title: {
type: String,
defult: '',
},
isAdd: {
type: Number,
default: 0,
},
isChild: {
type: Boolean,
default: false,
},
});
interface formState {
name: string;
sortIndex: number;
description: string;
}
const listData = ref([]);
/**
* 表单数据
*/
const formModel = ref<formState>({
name: '',
sortIndex: 1,
description: '',
});
const rules = ref({
name: [{ required: true, message: '请输入名称' }],
sortIndex: [{ required: true, message: '请输入排序' }],
});
const visible = ref(false);
const { resetFields, validate, validateInfos } = useForm(
formModel.value,
rules.value,
);
/**
* 提交数据
*/
const submitData = async () => {
validate()
.then(async () => {})
.catch((error: ValidateErrorEntity<formState>) => {});
};
/**
* 显示弹窗
*/
const show = (row: any) => {
if (props.isAdd === 0) {
//
if (props.isChild) {
//
if (row.children && row.children.length > 0) {
let childArr = [];
childArr = row.children.sort(compare('sortIndex'));
formModel.value = {
name: '',
sortIndex: childArr[childArr.length - 1].sortIndex + 1,
description: '',
};
} else {
formModel.value = {
name: '',
sortIndex: 1,
description: '',
};
}
} else {
let arr = [];
arr = listData.value.sort(compare('sortIndex'));
if (arr.length > 0) {
formModel.value = {
name: '',
sortIndex: arr[arr.length - 1].sortIndex + 1,
description: '',
};
} else {
formModel.value = {
name: '',
sortIndex: 1,
description: '',
};
}
}
visible.value = true;
} else if (props.isAdd === 2) {
//
formModel.value = {
name: row.name,
sortIndex: row.sortIndex,
description: row.description,
};
visible.value = true;
}
};
/**
* 判断是新增还是编辑
*/
const judgeIsAdd = () => {};
/**
* 排序
*/
const compare = (property: any) => {
return function (obj1: any, obj2: any) {
var value1 = obj1[property];
var value2 = obj2[property];
return value1 - value2; //
};
},
/**
* 获取列表数据
*/
getTableData = async () => {
const params = {
paging: false,
sorts: [
{ name: 'sortIndex', order: 'asc' },
{
name: 'createTime',
order: 'desc',
},
],
};
const res = await queryTree(params);
if (res.status === 200) {
listData.value = res.result;
console.log(listData.value, 'listData.value');
}
};
/**
* 关闭弹窗
*/
const close = () => {
visible.value = false;
resetFields();
};
getTableData();
//ID
watch([() => props.isAdd], () => {}, { immediate: false, deep: true });
defineExpose({
show: show,
});
</script>
<style></style>

View File

@ -0,0 +1,221 @@
<!--产品分类 -->
<template>
<a-card class="product-category">
<Search :columns="query.columns" target="category" />
<JTable
ref="tableRef"
:columns="table.columns"
:request="queryTree"
model="TABLE"
:params="query.params"
>
<template #headerTitle>
<a-button type="primary" @click="add"
><plus-outlined />新增</a-button
>
</template>
<template #action="slotProps">
<a-space :size="16">
<a-tooltip
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
v-bind="i.tooltip"
>
<a-popconfirm
v-if="i.popConfirm"
v-bind="i.popConfirm"
:disabled="i.disabled"
>
<a-button
:disabled="i.disabled"
style="padding: 0"
type="link"
><AIcon :type="i.icon"
/></a-button>
</a-popconfirm>
<a-button
style="padding: 0"
type="link"
v-else
@click="i.onClick && i.onClick(slotProps)"
>
<a-button
:disabled="i.disabled"
style="padding: 0"
type="link"
><AIcon :type="i.icon"
/></a-button>
</a-button>
</a-tooltip>
</a-space>
</template>
</JTable>
<!-- 新增和编辑弹窗 -->
<ModifyModal
ref="modifyRef"
:formData="currentForm"
:title="title"
:isAdd="isAdd"
:isChild="isChild"
@refresh="() => modifyRef.value?.reload()"
/>
</a-card>
</template>
<script lang="ts" name="Category" setup>
import { queryTree, deleteTree } from '@/api/device/category';
import type { ActionsType } from '@/components/Table/index.vue';
import ModifyModal from './components/modifyModal/index.vue';
import type { TableColumnType, TableProps } from 'ant-design-vue';
import { message } from 'ant-design-vue';
const tableRef = ref<Record<string, any>>({});
const modifyRef = ref();
const dataSource = ref([]);
const currentForm = ref({});
const title = ref('');
const isAdd = ref(0);
const isChild = ref(false);
//
const query = reactive({
columns: [
{
title: '名称',
dataIndex: 'name',
ellipsis: true,
},
{
title: '排序',
dataIndex: 'sortIndex',
valueType: 'digit',
sorter: true,
},
{
title: '描述',
key: 'description',
ellipsis: true,
dataIndex: 'description',
filters: true,
onFilter: true,
},
{
title: '操作',
valueType: 'option',
width: 200,
fixed: 'right',
},
],
params: {
paging: false,
sorts: [
{ name: 'sortIndex', order: 'asc' },
{
name: 'createTime',
order: 'desc',
},
],
},
});
/**
* 操作栏按钮
*/
const getActions = (
data: Partial<Record<string, any>>,
type: 'table',
): ActionsType[] => {
if (!data) return [];
const actions = [
{
key: 'edit',
text: '编辑',
tooltip: {
title: '编辑',
},
icon: 'EditOutlined',
onClick: async () => {
title.value = '编辑分类';
isAdd.value = 2;
currentForm.value = data;
nextTick(() => {
modifyRef.value.show(data);
});
},
},
{
key: 'add',
text: '添加子分类',
tooltip: {
title: '添加子分类',
},
icon: 'PlusCircleOutlined',
onClick: () => {
title.value = '新增子分类';
isAdd.value = 0;
isChild.value = true;
currentForm.value = {};
nextTick(() => {
modifyRef.value.show(data);
});
},
},
{
key: 'delete',
text: '删除',
popConfirm: {
title: '确认删除?',
okText: ' 确定',
cancelText: '取消',
onConfirm: async () => {
const resp = await deleteTree(data.id);
if (resp.status === 200) {
message.success('操作成功!');
tableRef.value?.reload();
} else {
message.error('操作失败!');
}
},
},
icon: 'DeleteOutlined',
},
];
return actions;
};
const table = reactive({
columns: [
{ title: '名称', dataIndex: 'name', key: 'name' },
{
title: '排序',
dataIndex: 'sortIndex',
key: 'sortIndex',
},
{
title: '说明',
dataIndex: 'describe',
key: 'describe',
},
{
title: '操作',
key: 'action',
fixed: 'right',
width: 250,
scopedSlots: true,
},
],
/**
* 添加产品分类
*/
add: async () => {
title.value = '新增分类';
isAdd.value = 0;
isChild.value = false;
nextTick(() => {
modifyRef.value.show(currentForm.value);
});
},
});
const { add, columns } = toRefs(table);
/**
* 初始化
*/
</script>
<style scoped lang="less"></style>

10
src/views/device/Category/typings.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
export type CategoryItem = {
id: string;
name: string;
level: number;
key: string;
parentId: string;
path: string;
sortIndex: number;
children?: Category[];
};

View File

@ -117,7 +117,7 @@
<a-upload
name="file"
:action="
action
FILE_UPLOAD
"
:headers="
headers
@ -259,7 +259,7 @@
<a-upload
name="file"
:action="
action
FILE_UPLOAD
"
:headers="
headers
@ -354,7 +354,9 @@
>
<a-upload
name="file"
:action="action"
:action="
FILE_UPLOAD
"
:headers="headers"
:beforeUpload="
beforeBackUpload
@ -773,6 +775,7 @@ import {
saveInit,
} from '@/api/initHome';
import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
import { FILE_UPLOAD } from '@/api/comm';
import { LocalStore } from '@/utils/comm';
import { message } from 'ant-design-vue';
import { Form } from 'ant-design-vue';
@ -899,7 +902,7 @@ const activeKey = ref<string>('1');
const spinning = ref<boolean>(false);
const visible = ref<boolean>(false);
const flag = ref<boolean>(false);
const action = ref<string>(`${BASE_API_PATH}/file/static`);
// const action = ref<string>(`${BASE_API_PATH}/file/static`);
const headers = ref({ [TOKEN_KEY]: LocalStore.get(TOKEN_KEY) });
/**
* 角色勾选数据