提交 ce8bc884 authored 作者: 袁伟伟's avatar 袁伟伟

feat: 商品管理

上级 a36c4f29
......@@ -139,6 +139,8 @@ export interface Goods {
* update_time
*/
updateTime?: Date;
goodsCategoryList: Array<{ id: number }> | number[];
}
export type GoodsPageResult = PageResult<Goods>;
......
......@@ -127,6 +127,10 @@ export interface GoodsCategory {
* update_time
*/
updateTime?: Date;
lineThirdId?: number;
lineName?: string;
status: string;
}
export type GoodsCategoryPageResult = PageResult<GoodsCategory>;
......
......@@ -13,6 +13,7 @@ import {
GoodsCategoryPageResponse,
GoodsCategoryResponse,
} from '../model/goodsCategory';
import { DataItem } from '/@/views/product/goods-category/type';
const baseApi = '/v1/product/goods-category';
......@@ -79,7 +80,8 @@ export const count = (params?: GoodsCategoryParams) => defHttp.get<Number>({ url
/**
* 查询商品分类树
*/
export const tree = () =>
defHttp.get<Number>({
export const tree = (params) =>
defHttp.get<DataItem[]>({
url: `${baseApi}/tree`,
params,
});
.container {
.containe {
padding: 16px;
}
.container .queryWrap {
.containe .queryWrap {
background: #fff;
padding: 12px 10px 6px;
margin-bottom: 16px;
}
.container .queryWrap .ant-form-item {
.containe .queryWrap .ant-form-item {
width: 30%;
margin-bottom: 8px;
}
.container .queryWrap .ant-form-item .ant-btn {
.containe .queryWrap .ant-form-item .ant-btn {
margin-right: 15px;
}
.container .queryWrap .checkBoxWrap {
.containe .queryWrap .checkBoxWrap {
width: 50%;
margin-left: 4%;
}
.container .tableWrap {
.containe .tableWrap {
padding: 6px;
background-color: #fff;
border-radius: 2px;
}
.container .tableWrap .titleWrap {
.containe .tableWrap .titleWrap {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.container .tableWrap .titleWrap .title {
.containe .tableWrap .titleWrap .title {
position: relative;
display: flex;
padding-left: 7px;
......
import lodash from 'lodash';
import { reactive } from 'vue';
const pagination = {
current: 1,
pageSize: 10,
total: 0,
showTotal: (total) => `共 ${total} 条数据`,
getData: () => {},
onChange: (page) => {},
onShowSizeChange: (current, size) => {},
size: 'small',
showSizeChanger: true,
pageSizeOptions: ['10', '50', '100'],
};
export const usePagination = (fun: () => void) => {
const p = lodash.cloneDeep(pagination);
p.getData = fun;
p.onChange = (page) => {
p.current = page;
p.getData();
};
p.onShowSizeChange = (current, size) => {
p.current = 1;
p.pageSize = size;
p.getData();
};
return reactive(p);
};
.container {
.containe {
padding: 16px;
.queryWrap {
......
<template>
<div class="container">
<div class="containe">
<div class="tableWrap">
<div class="titleWrap">
<span class="title"></span>
<a-button type="primary" @click="handleAdd">新增</a-button>
<a-button type="primary" @click="handleAdd" v-if="hasPermission('AUTH_PRODUCT_GOODS_CATEGORY:ADD')"
>新增</a-button
>
</div>
<a-table :columns="columns" :data-source="data" :pagination="false">
<a-table :columns="columns" :data-source="data" :pagination="false" :loading="tableLoading">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'">
<span v-if="record.status === 'YES'">启用</span>
<span v-else>禁用</span>
</template>
<template v-if="column.key === 'action'">
<a-button type="link">编辑</a-button>
<a-button type="link">禁用</a-button>
<a-button
type="link"
@click="handleEdit(record.id)"
v-if="hasPermission('AUTH_PRODUCT_GOODS_CATEGORY:EDIT')"
>编辑</a-button
>
<a-button type="link" v-if="record.status === 'YES'" @click="handleChangeStatus(record.id, 'NO')"
>禁用</a-button
>
<a-button type="link" v-else @click="handleChangeStatus(record.id, 'YES')">启用</a-button>
<a-button type="link">添加商品</a-button>
<a-button type="link">添加节点</a-button>
<a-button type="link">删除</a-button>
<a-popconfirm
title="是否确认删除?"
ok-text="是"
cancel-text="否"
@confirm="handleDelete(record.id)"
v-if="hasPermission('AUTH_PRODUCT_GOODS_CATEGORY:DELETE')"
>
<a-button type="link">删除</a-button>
</a-popconfirm>
</template>
</template>
</a-table>
</div>
<Modal ref="modalRef"></Modal>
<Modal ref="modalRef" @handleSuccess="getTreeData" v-model:editId="editId"></Modal>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { ref, onMounted } from 'vue';
import Modal from './modal.vue';
import * as GoodsCategoryApi from '/@/api/product/goodsCategoryApi';
import { DataItem } from './type';
import { columns } from './schema';
import { message } from 'ant-design-vue';
import { usePermission } from '/@/hooks/web/usePermission';
const { hasPermission } = usePermission();
const modalRef = ref();
const columns = [
{
title: '分类名称',
dataIndex: 'name',
key: 'name',
},
{
title: '排序',
dataIndex: 'age',
key: 'age',
},
{
title: '层级',
dataIndex: 'address',
key: 'address',
},
{
title: '状态',
dataIndex: 'state',
key: 'state',
},
{
title: '操作',
key: 'action',
},
];
const data = ref<DataItem[]>([]);
const tableLoading = ref(false);
const editId = ref<undefined | number>();
interface DataItem {
key: number;
name: string;
age: number;
address: string;
children?: DataItem[];
}
// 获取树结构
const getTreeData = () => {
tableLoading.value = true;
GoodsCategoryApi.tree({ parentId: 0 })
.then((res: DataItem[]) => {
data.value = res;
})
.finally(() => {
tableLoading.value = false;
});
};
const data = ref<DataItem[]>([
{
key: 1,
name: 'John Brown sr.',
age: 60,
address: 'New York No. 1 Lake Park',
children: [
{
key: 11,
name: 'John Brown',
age: 42,
address: 'New York No. 2 Lake Park',
},
],
},
]);
const handleAdd = () => {
modalRef.value.visible = true;
};
const getData = () => {
GoodsCategoryApi.tree().then((res) => {
console.log(res);
const handleDelete = (id: number) => {
GoodsCategoryApi.remove(id).then(() => {
message.success('删除成功');
getTreeData();
});
};
const handleAdd = () => {
const handleEdit = (id: number) => {
modalRef.value.visible = true;
editId.value = id;
};
const handleChangeStatus = (id: number, status: string) => {
GoodsCategoryApi.update({ id, status }).then(() => {
message.success('设置成功');
getTreeData();
});
};
onMounted(() => {
getTreeData();
});
</script>
<style lang="less" scoped>
......
<template>
<a-modal v-model:visible="visible" title="新增商品分类" @ok="handleOk" class="myModal">
<a-form :label-col="{ span: 6 }" :wrapper-col="{ span: 14 }">
<a-form-item label="分类类型" v-bind="validateInfos.parentId">
<a-select ref="select" v-model:value="formData.parentId">
<a-select-option :value="item.id" v-for="item in classifyOption">{{ item.name }}</a-select-option>
</a-select>
<a-modal
v-model:visible="visible"
:title="props.editId ? '编辑商品分类' : '新增商品分类'"
@ok="handleOk"
@cancel="handleCancel"
class="myModal"
>
<a-form
:model="formData"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 14 }"
autocomplete="off"
ref="formRef"
:rules="rulesRef"
>
<a-form-item label="分类类型" name="parentId">
<a-tree-select
v-model:value="formData.parentId"
style="width: 100%"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
tree-default-expand-all
:tree-data="classifyTree"
:defaultValue="0"
:fieldNames="fieldNames"
>
</a-tree-select>
</a-form-item>
<a-form-item label="产品线" v-bind="validateInfos.thirdProductId" v-if="formData.parentId === 0">
<a-select ref="select" v-model:value="formData.thirdProductId">
<a-select-option :value="item.id" v-for="item in thirdProductOption">{{ item.name }}</a-select-option>
<a-form-item label="产品线" v-if="formData.parentId === 0" name="lineThirdId">
<a-select ref="select" v-model:value="formData.lineThirdId" @select="handleChangeLine">
<a-select-option :value="item.id" v-for="item in thirdProductOption" :key="item.name">{{
item.name
}}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="分类名称" v-bind="validateInfos.name">
<a-form-item label="分类名称" name="name">
<a-input v-model:value="formData.name" />
</a-form-item>
<a-form-item label="排序" v-bind="validateInfos.sort">
<a-input v-model:value="formData.sort" />
<a-form-item label="排序" name="sort">
<a-input-number v-model:value="formData.sort" :min="0" />
</a-form-item>
<a-form-item label="状态" v-bind="validateInfos.status">
<a-input v-model:value="formData.status" />
<a-form-item label="状态" name="status">
<a-radio-group v-model:value="formData.status">
<a-radio value="YES">启用</a-radio>
<a-radio value="NO">禁用</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="页面关键词" v-bind="validateInfos.name">
<!-- <a-form-item label="页面关键词" v-bind="validateInfos.name">
<a-input v-model:value="formData.name" />
</a-form-item>
<a-form-item label="页面描述" v-bind="validateInfos.remark">
</a-form-item> -->
<a-form-item label="页面描述" name="remark">
<a-input v-model:value="formData.remark" />
</a-form-item>
</a-form>
......@@ -31,44 +56,108 @@
</template>
<script lang="ts" setup>
import { defineExpose, ref, reactive } from 'vue';
import { Form } from 'ant-design-vue';
import { defineExpose, ref, reactive, defineEmits, watch, defineProps } from 'vue';
import { message } from 'ant-design-vue';
import * as GoodsCategoryApi from '/@/api/product/goodsCategoryApi';
import { DataItem } from '/@/views/product/goods-category/type';
import { GoodsCategory } from '/@/api/model/goodsCategory';
import { fieldNames, rulesRef } from './schema';
const visible = ref<boolean>(false);
const useForm = Form.useForm;
const formData = reactive({
const emits = defineEmits(['handleSuccess', 'update:editId']);
const props = defineProps(['editId']);
const formRef = ref<any>();
const formData = reactive<GoodsCategory>({
name: '',
remark: '',
status: 'NO',
sort: 0,
thirdProductId: 1,
lineName: undefined,
lineThirdId: undefined,
parentId: 0,
});
const rulesRef = reactive({
name: [
{
required: true,
message: 'Please input name',
},
],
});
const classifyOption = ref([
{
name: '顶级分类',
id: 0,
},
]);
// 树结构选项
const classifyTree = ref<DataItem[]>([]);
const thirdProductOption = ref([{ name: '产品线1', id: 1 }]);
const { resetFields, validate, validateInfos } = useForm(formData, rulesRef);
// 获取树结构
const getTreeData = () => {
GoodsCategoryApi.tree({ parentId: 0 }).then((res: DataItem[]) => {
res.unshift({
name: '顶级分类',
id: 0,
});
classifyTree.value = res;
console.log(classifyTree.value);
});
};
const getEditInfo = () => {
GoodsCategoryApi.getById(props.editId).then((res) => {
for (const key in formData) {
formData[key] = res[key];
formData.id = res.id;
if (res.lineThirdId) {
formData.lineThirdId = res.lineThirdId * 1;
}
}
});
};
const handleChangeLine = (value, option) => {
formData.lineName = option.key;
};
const handleOk = () => {
validate().then(() => {
console.log(111);
formRef.value.validate().then(() => {
if (formData.parentId != 0) {
formData.lineName = undefined;
formData.lineThirdId = undefined;
}
let api;
if (props.editId) {
api = GoodsCategoryApi.update;
} else {
if (formData.id) delete formData.id;
api = GoodsCategoryApi.add;
}
api(formData).then(() => {
message.success('操作成功');
emits('handleSuccess');
handleCancel();
});
});
// visible.value = false;
};
const handleCancel = () => {
formRef.value.resetFields();
emits('update:editId', undefined);
visible.value = false;
};
watch(
() => visible.value,
(newValue) => {
if (newValue) {
getTreeData();
}
},
);
watch(
() => props.editId,
(newValue) => {
if (newValue) {
getEditInfo();
}
},
{
immediate: true,
},
);
defineExpose({ visible });
</script>
......
/**
* 项目:-
* 模型分组:订单管理
* 模型名称:商品分类
* @Author: xiongwei
* @Date: 2022-06-28 11:50:00
*/
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import get from 'lodash.get';
const colProps = { xs: { span: 24 }, sm: { span: 24 }, lg: { span: 8 } };
const colPropsInDrawer = { span: 24 };
import { reactive } from 'vue';
export const columns = [
{
title: '分类名称',
dataIndex: 'name',
key: 'name',
},
{
title: '排序',
dataIndex: 'sort',
key: 'sort',
},
{
title: '层级',
dataIndex: 'level',
key: 'level',
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
},
{
title: '操作',
key: 'action',
width: '350px',
},
];
export const fieldNames = {
children: 'children',
label: 'name',
key: 'id',
value: 'id',
};
export const schema = {
model: 'GoodsCategory',
viewInPage: true,
properties: [
{
field: 'id',
label: 'ID系统自动生成',
defaultValue: undefined,
form: {
componentProps: {
allowClear: false,
placeholder: 'ID系统自动生成',
},
colProps,
component: 'InputNumber',
rules: [{ required: true, message: '请输入ID系统自动生成!' }],
},
table: {
},
},
{
field: 'distributorId',
label: '经销商id',
defaultValue: undefined,
form: {
componentProps: {
allowClear: false,
placeholder: '经销商id',
},
colProps,
component: 'InputNumber',
rules: [{ required: true, message: '请输入经销商id!' }],
},
table: {
},
},
export const rulesRef = reactive({
lineThirdId: [
{
field: 'name',
label: '产品分类名称',
defaultValue: undefined,
form: {
componentProps: {
allowClear: false,
placeholder: '产品分类名称',
},
colProps,
component: 'Input',
rules: [{ required: true, message: '请输入产品分类名称!' }],
},
table: {
},
},
{
field: 'icon',
label: '图标',
defaultValue: undefined,
form: {
componentProps: {
allowClear: false,
placeholder: '图标',
},
colProps,
component: 'Input',
rules: [{ required: true, message: '请输入图标!' }],
},
table: {
},
},
{
field: 'parentId',
label: '父级ID',
defaultValue: 0,
form: {
componentProps: {
allowClear: false,
placeholder: '父级ID',
},
colProps,
component: 'InputNumber',
rules: [{ required: true, message: '请输入父级ID!' }],
},
table: {
},
},
{
field: 'sort',
label: '排序',
defaultValue: 1,
form: {
componentProps: {
allowClear: false,
placeholder: '排序',
},
colProps,
component: 'InputNumber',
rules: [{ required: true, message: '请输入排序!' }],
},
table: {
},
},
{
field: 'remark',
label: '描述',
defaultValue: undefined,
form: {
componentProps: {
allowClear: true,
placeholder: '描述',
},
colProps,
component: 'Input',
},
table: {
},
},
{
field: 'editorId',
label: '操作人ID',
defaultValue: 1,
form: {
componentProps: {
allowClear: false,
placeholder: '操作人ID',
},
colProps,
component: 'InputNumber',
rules: [{ required: true, message: '请输入操作人ID!' }],
},
table: {
},
},
{
field: 'editorName',
label: '操作人',
defaultValue: 'admin',
form: {
componentProps: {
allowClear: false,
placeholder: '操作人',
},
colProps,
component: 'Input',
rules: [{ required: true, message: '请输入操作人!' }],
},
table: {
},
},
{
field: 'createTime',
label: 'CreateTime',
defaultValue: undefined,
form: {
colProps,
componentProps: {
allowClear: false,
placeholder: ['开始时间', '结束时间'],
format: 'YYYY-MM-DD',
showTime: false,
},
component: 'RangePicker',
rules: [{ required: true, message: '请输入CreateTime!' }],
},
table: {
},
required: true,
message: '请选择产品线',
},
],
name: [
{
field: 'updateTime',
label: 'UpdateTime',
defaultValue: undefined,
form: {
colProps,
componentProps: {
allowClear: false,
placeholder: ['开始时间', '结束时间'],
format: 'YYYY-MM-DD',
showTime: false,
},
component: 'RangePicker',
rules: [{ required: true, message: '请输入UpdateTime!' }],
},
table: {
},
required: true,
message: '请输入分类名称',
},
],
};
const queryFields = ['id','distributorId','name','icon','parentId','sort','remark','editorId','editorName','createTime','updateTime'];
const editFields = ['distributorId','name','icon','parentId','sort','remark'];
const tableFields = ['id','distributorId','name','icon','parentId','sort','remark','editorId','editorName','createTime','updateTime'];
const descriptionFields = ['id','distributorId','name','icon','parentId','sort','remark','editorId','editorName','createTime','updateTime'];
export const searchFormSchema: FormSchema[] = schema.properties.filter(item => queryFields.includes(item.field))
.map(
({ field, label, form: { rules = [], ...formProps } }) =>
({
field,
label,
defaultValue: undefined,
rules: rules.filter((r) => !r.required),
...formProps,
} as FormSchema),
);
export const formSchema: FormSchema[] = schema.properties.filter(item => editFields.includes(item.field))
.map(
({ field, label, defaultValue, form }) =>
({
field,
label,
defaultValue,
...form,
colProps: colPropsInDrawer,
} as FormSchema),
);
export const columns: BasicColumn[] = schema.properties.filter(item => tableFields.includes(item.field))
.map(
({ field, label, table }) =>
({
dataIndex: field,
title: label,
...table,
} as BasicColumn)
);
export const descriptionColumns: BasicColumn[] = schema.properties.filter(item => descriptionFields.includes(item.field))
.map(
({ field, label, table }) =>
({
dataIndex: field,
title: label,
...table,
} as BasicColumn),
);
});
export interface DataItem {
name: string;
id: number;
}
<template>
<div class="containe">
<div class="queryWrap">
<a-form
:model="formState"
name="basic"
ref="formRef"
layout="inline"
:label-col="{ span: 8 }"
:wrapper-col="{ span: 16 }"
autocomplete="off"
class="ant-row"
>
<a-form-item label="商品名称" name="goodsName">
<a-input v-model:value="formState.goodsName" />
</a-form-item>
<a-form-item label="产品编号" name="goodsName">
<a-input v-model:value="formState.goodsName" />
</a-form-item>
<a-form-item label="产品线" name="goodsName">
<a-input v-model:value="formState.goodsName" />
</a-form-item>
<a-form-item label="折扣时间" name="goodsName">
<a-input v-model:value="formState.goodsName" />
</a-form-item>
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
<a-button @click="handleReset">重置</a-button>
<a-button type="primary" @click="getData">查询</a-button>
</a-form-item>
</a-form>
</div>
<div class="tableWrap">
<div class="titleWrap">
<span class="title">商品分类</span>
<a-button type="primary" @click="handleAdd">新增</a-button>
</div>
<a-table :dataSource="dataSource" :columns="columns" :pagination="pagination"> </a-table>
</div>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { usePagination } from '/@/hooks/myhooks/index';
import * as GoodsApi from '/@/api/product/goodsApi';
import { columns } from './schema';
const formRef = ref();
const formState = reactive<FormState>({
goodsName: undefined,
});
const dataSource = ref<Goods[]>();
const getData = () => {
GoodsApi.search(Object.assign({ pageSize: pagination.pageSize, pageNum: pagination.current }, formState)).then(
(res) => {
pagination.total = res.total;
dataSource.value = res.records;
},
);
};
const pagination = usePagination(getData);
const handleReset = () => {
formRef.value.resetFields();
};
const handleAdd = () => {};
</script>
<style lang="less" scoped>
@import url('/@/style/index.less');
</style>
<template>
<a-modal
v-model:visible="visible"
:title="props.editId ? '编辑' : '新增'"
@ok="handleOk"
@cancel="handleCancel"
class="myModal"
>
<a-form
:model="formData"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 14 }"
autocomplete="off"
ref="formRef"
:rules="rulesRef"
>
<a-form-item label="产品线" name="name">
<a-input v-model:value="formData.name" />
</a-form-item>
<a-form-item label="商品" name="name">
<a-input v-model:value="formData.name" />
</a-form-item>
<a-form-item label="折扣时间期限" name="name">
<a-input v-model:value="formData.name" />
</a-form-item>
<a-form-item label="折扣设置" name="name">
<a-input v-model:value="formData.name" />
</a-form-item>
<a-form-item label="状态" name="name">
<a-input v-model:value="formData.name" />
</a-form-item>
</a-form>
</a-modal>
</template>
<script lang="ts" setup>
import { defineComponent } from 'vue';
</script>
<style lang="less" scoped></style>
export const columns = [
{
title: '产品线',
dataIndex: 'lineName',
key: 'lineName',
},
{
title: '商品名称',
dataIndex: 'name',
key: 'name',
},
{
title: '原价',
dataIndex: 'original',
key: 'original',
},
{
title: '折扣',
dataIndex: 'discount',
key: 'discount',
},
{
title: '折扣时间期限',
dataIndex: 'time',
key: 'time',
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
},
{
title: '操作',
key: 'action',
width: '350px',
},
];
<template>
<div>
<a-form
:model="formData"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 14 }"
autocomplete="off"
ref="formRef"
:rules="rulesRef"
>
<a-form-item label="商品分类" name="goodsCategoryList">
<a-tree-select
v-model:value="formData.goodsCategoryList"
style="width: 100%"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
tree-default-expand-all
tree-checkable
:tree-data="classifyTree"
:fieldNames="fieldNames"
>
</a-tree-select>
</a-form-item>
<a-form-item label="商品名称" name="name">
<a-input v-model:value="formData.name" />
</a-form-item>
<a-form-item label="上架" name="status">
<a-radio-group v-model:value="formData.status">
<a-radio value="YES"></a-radio>
<a-radio value="NO"></a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="重点" name="isImport">
<a-radio-group v-model:value="formData.isImport">
<a-radio value="YES"></a-radio>
<a-radio value="NO"></a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="新品" name="isNews">
<a-radio-group v-model:value="formData.isNews">
<a-radio value="YES"></a-radio>
<a-radio value="NO"></a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="非常规" name="isUnconventional">
<a-radio-group v-model:value="formData.isUnconventional">
<a-radio value="YES"></a-radio>
<a-radio value="NO"></a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="促销商品" name="isPromotion">
<a-radio-group v-model:value="formData.isPromotion">
<a-radio value="YES"></a-radio>
<a-radio value="NO"></a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="排序" name="sort">
<a-input-number v-model:value="formData.sort" :min="0" />
</a-form-item>
<a-form-item label="页面关键词" name="pageKeyword">
<a-input v-model:value="formData.pageKeyword" />
</a-form-item>
<a-form-item label="页面描述" name="pageRemark">
<a-input v-model:value="formData.pageRemark" />
</a-form-item>
<a-form-item label="商品描述" name="remark">
<a-input v-model:value="formData.remark" />
</a-form-item>
</a-form>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, onMounted, defineExpose, defineEmits } from 'vue';
import { rulesRef } from '../schema';
import { BasicData } from '../type';
import { DataItem } from '/@/views/product/goods-category/type';
import * as GoodsCategoryApi from '/@/api/product/goodsCategoryApi';
import { fieldNames } from '/@/views/product/goods-category/schema';
const emits = defineEmits(['handleSubmit']);
const formRef = ref<any>();
const formData = reactive<BasicData>({
goodsCategoryList: [],
name: '',
status: 'NO',
isImport: 'NO',
isNews: 'NO',
isUnconventional: 'NO',
isPromotion: 'NO',
sort: 0,
pageKeyword: '',
pageRemark: '',
remark: '',
});
const classifyTree = ref<DataItem[]>([]);
// 获取树结构
const getTreeData = () => {
GoodsCategoryApi.tree({ parentId: 0 }).then((res: DataItem[]) => {
classifyTree.value = res;
});
};
const validate = () => {
formRef.value.validate().then(() => {
emits('handleSubmit');
});
};
onMounted(() => {
getTreeData();
});
defineExpose({ formData, validate });
</script>
<style lang="less" scoped></style>
<template>
<div class="containe">
<div class="tableWrap">
<div class="titleWrap">
<span class="title"></span>
<a-button type="primary" @click="handleAdd">新增</a-button>
</div>
<a-table :dataSource="dataSource" :columns="productColumns" :pagination="false">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<a-button type="link">编辑</a-button>
<a-button type="link">删除</a-button>
</template>
</template>
</a-table>
</div>
<a-modal v-model:visible="visible" title="新增" @ok="handleSubmit">
<a-form
:model="formData"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 14 }"
autocomplete="off"
ref="formRef"
:rules="productRulesRef"
>
<a-form-item label="产品编号" name="code">
<a-input v-model:value="formData.code" />
</a-form-item>
<a-form-item label="数量" name="number">
<a-input v-model:value="formData.number" />
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { productColumns, productRulesRef } from '../schema';
const visible = ref(false);
const dataSource = ref();
const formRef = ref();
const formData = ref({
code: '',
number: '',
});
const handleAdd = () => {
visible.value = true;
};
const handleSubmit = () => {
formRef.value.validate().then(() => {
visible.value = false;
});
};
</script>
<style lang="less" scoped>
@import url('/@/style/index.less');
</style>
<template>
<Card :bordered="false">
<Descriptions bordered :column="3">
<Descriptions.Item
v-for="p in displayProps"
:key="p.title"
:label="p.title"
:span="['avatar'].includes(p.name) ? 3 : 1"
>
<span v-if="p.key === 'avatar'">
<img :src="p.value" style="width: 120px; height: 120px" />
</span>
<template v-else>
{{ p.value }}
</template>
</Descriptions.Item>
</Descriptions>
</Card>
</template>
<script lang="ts" setup name="DeviceDetail">
import { onMounted, computed, ref, reactive } from 'vue';
import { useRoute } from 'vue-router';
import { ComputedRef } from '@vue/reactivity';
import { Descriptions, Card } from 'ant-design-vue';
import { descriptionColumns } from './schema';
import * as GoodsApi from '/@/api/product/goodsApi';
import { Device } from '/@/api/model/device';
const route = useRoute();
const id = ref(route.params?.id);
let data = reactive({
detail: {},
isOver: false,
});
const getDetail = () => {
GoodsApi.getById(id.value).then((res: Device) => {
data.isOver = true;
data.detail = res;
});
};
onMounted(() => {
getDetail();
});
const displayProps: ComputedRef<Array<any>> = computed(() => {
if (!data.isOver) return {};
const display: any = descriptionColumns.map(({ title, dataIndex = '', customRender }) => ({
key: dataIndex,
title,
value: customRender ? customRender(data.detail[dataIndex], data.detail) : data.detail[dataIndex],
}));
return display;
});
</script>
<style scoped></style>
<template>
<BasicDrawer v-bind="$attrs" @register="registerDrawer" showFooter :title="getTitle" width="600px" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicDrawer>
</template>
<script lang="ts" setup name="GoodsDrawer">
import { defineEmits, ref, computed, unref } from 'vue';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from './schema';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import * as GoodsApi from '/@/api/product/goodsApi';
const emit = defineEmits(['success', 'register']);
const isUpdate = ref(true);
const entityId = ref(0);
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
labelWidth: 120,
schemas: formSchema,
showActionButtonGroup: false,
});
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
await resetFields();
setDrawerProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
entityId.value = data?.record?.id;
if (unref(isUpdate)) {
await setFieldsValue({
...data.record,
});
}
});
const getTitle = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
async function handleSubmit() {
try {
const values = await validate();
setDrawerProps({ confirmLoading: true });
const {
...rest
} = values;
const action = !unref(isUpdate) ? GoodsApi.add : GoodsApi.update;
const data = !unref(isUpdate)
? {
...rest,
}
: Object.assign({},
{
...rest,
id: unref(entityId),
},
);
await action(data);
closeDrawer();
emit('success');
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>
<template>
<div class="container">
<div class="containe">
<div class="queryWrap">
<a-form
:model="formState"
......@@ -9,8 +9,6 @@
:label-col="{ span: 8 }"
:wrapper-col="{ span: 16 }"
autocomplete="off"
@finish="onFinish"
@finishFailed="onFinishFailed"
class="ant-row"
>
<a-form-item label="商品名称" name="goodsName">
......@@ -25,15 +23,12 @@
<a-form-item label="产品编码" name="productCode">
<a-input v-model:value="formState.productCode" />
</a-form-item>
<a-form-item label="是否为促销" name="promotion">
<a-input v-model:value="formState.promotion" />
</a-form-item>
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
<a-button @click="handleReset">重置</a-button>
<a-button type="primary" html-type="submit">查询</a-button>
<a-button type="primary" @click="getData">查询</a-button>
</a-form-item>
<a-form-item class="checkBoxWrap">
<a-checkbox-group v-model:value="stateChange" name="checkboxgroup" :options="stateOption" />
<a-checkbox-group v-model:value="stateChange" :options="stateOption" />
</a-form-item>
</a-form>
</div>
......@@ -44,8 +39,28 @@
</div>
<a-table :dataSource="dataSource" :columns="columns" :pagination="pagination">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'">
<span v-if="record.status === 'YES'"></span>
<span v-else></span>
</template>
<template v-if="column.key === 'isImport'">
<span v-if="record.isImport === 'YES'"></span>
<span v-else></span>
</template>
<template v-if="column.key === 'isNews'">
<span v-if="record.isNews === 'YES'"></span>
<span v-else></span>
</template>
<template v-if="column.key === 'isUnconventional'">
<span v-if="record.isUnconventional === 'YES'"></span>
<span v-else></span>
</template>
<template v-if="column.key === 'isPromotion'">
<span v-if="record.isPromotion === 'YES'"></span>
<span v-else></span>
</template>
<template v-if="column.key === 'action'">
<a-button type="link">编辑</a-button>
<a-button type="link" @click="handleAdd(record.id)">编辑</a-button>
<a-button type="link">删除</a-button>
</template>
</template>
......@@ -54,17 +69,14 @@
</div>
</template>
<script lang="ts" setup name="DeviceIndex">
import { ref, reactive } from 'vue';
import { ref, reactive, onMounted } from 'vue';
import { useGo } from '/@/hooks/web/usePage';
import { usePermission } from '/@/hooks/web/usePermission';
interface FormState {
goodsName: string;
classify: string;
productLine: string;
productCode: string;
promotion: boolean | null;
}
import { FormState } from './type';
import { columns, stateOption } from './schema';
import * as GoodsApi from '/@/api/product/goodsApi';
import { Goods } from '/@/api/model/goods';
import { usePagination } from '/@/hooks/myhooks/index';
const { hasPermission } = usePermission();
const go = useGo();
......@@ -72,105 +84,48 @@
const formRef = ref();
const formState = reactive<FormState>({
goodsName: '',
classify: '',
productLine: '',
productCode: '',
promotion: null,
goodsName: undefined,
classify: undefined,
productLine: undefined,
productCode: undefined,
promotion: undefined,
});
const stateChange = ref([]);
const dataSource = [
{
index: '1',
name: '胡彦斌',
classify: '分类1',
line: '产品线1',
grounding: 1,
emphasis: 1,
new: 1,
unconventionality: 1,
},
];
const columns = [
{
title: '序号',
dataIndex: 'index',
key: 'index',
},
{
title: '商品名称',
dataIndex: 'name',
key: 'name',
},
{
title: '分类',
dataIndex: 'classify',
key: 'classify',
},
{
title: '产品线',
dataIndex: 'line',
key: 'line',
},
{
title: '上架',
dataIndex: 'grounding',
key: 'grounding',
},
{
title: '重点',
dataIndex: 'emphasis',
key: 'emphasis',
},
{
title: '新品',
dataIndex: 'new',
key: 'new',
},
{
title: '非常规',
dataIndex: 'unconventionality',
key: 'unconventionality',
},
{
title: '操作',
key: 'action',
},
];
const dataSource = ref<Goods[]>();
const stateOption = ['上架', '重点', '非常规', '新品'];
const pagination = {
current: 1,
pageSize: 10,
total: 85,
showTotal: (total) => `共 ${total} 条数据`,
onChange: (page, pageSize) => {
console.log(page, pageSize);
},
size: 'small',
};
const onFinish = (values: any) => {
console.log('Success:', values);
const getData = () => {
const data: any = {};
stateChange.value.forEach((item) => {
data[item] = 'YES';
});
GoodsApi.search(
Object.assign({ pageSize: pagination.pageSize, pageNum: pagination.current }, formState, data),
).then((res) => {
pagination.total = res.total;
dataSource.value = res.records;
});
};
const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
};
const pagination = usePagination(getData);
const handleReset = () => {
stateChange.value = [];
formRef.value.resetFields();
};
const handleAdd = () => {};
const handleView = (record) => {
go('/product/goods/' + record.id);
const handleAdd = (id: number | boolean) => {
if (id) {
go('/main/goods-add' + `?id=${id}`);
} else {
go('/main/goods-add');
}
};
onMounted(() => {
getData();
});
</script>
<style lang="less" scoped>
......
<template>
<div class="containe">
<div class="tableWrap">
<a-tabs v-model:activeKey="activeKey" centered>
<a-tab-pane key="1" tab="基本信息"><BasicInfo ref="basicInfoRef" @handleSubmit="handleSubmit" /> </a-tab-pane>
<a-tab-pane key="2" tab="商品描述" force-render>Content of Tab Pane 2</a-tab-pane>
<a-tab-pane key="3" tab="商品图片">Content of Tab Pane 3</a-tab-pane>
<a-tab-pane key="4" tab="产品规格"><Product /></a-tab-pane>
</a-tabs>
<div class="btnWrap">
<a-button type="primary" @click="handleAdd">提交</a-button>
<a-button @click="handleBack">返回</a-button>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import BasicInfo from './components/basicInfo.vue';
import * as GoodsApi from '/@/api/product/goodsApi';
import Product from './components/product.vue';
import { useGo } from '/@/hooks/web/usePage';
import lodash from 'lodash';
import { message } from 'ant-design-vue';
const route = useRoute();
const go = useGo();
const basicInfoRef = ref();
const activeKey = ref('1');
const id = route.query.id;
let basicInfo;
const getInfo = () => {
GoodsApi.getById(id).then((res) => {
const goodsCategoryList = <number[]>[];
res.goodsCategoryList.forEach((item) => {
goodsCategoryList.push(item.id);
});
res.goodsCategoryList = goodsCategoryList;
for (const key in basicInfo) {
basicInfo[key] = res[key];
}
});
};
const handleAdd = () => {
basicInfoRef.value.validate();
};
const handleSubmit = () => {
const data = lodash.cloneDeep(basicInfoRef.value.formData);
data.goodsCategoryList.forEach((item, index) => {
data.goodsCategoryList[index] = { id: item };
});
let api;
if (id) {
data.id = id;
api = GoodsApi.update;
} else {
api = GoodsApi.add;
}
api(data).then(() => {
message.success('操作成功');
handleBack();
});
};
const handleBack = () => {
go('/main/product/goods');
};
onMounted(() => {
basicInfo = basicInfoRef.value.formData;
if (id) {
getInfo();
}
});
</script>
<style lang="less" scoped>
@import url('/@/style/index.less');
.btnWrap {
margin-bottom: 20px;
text-align: center;
.ant-btn {
margin: 0 5px;
}
}
</style>
export interface FormState {
goodsName?: string;
classify?: string;
productLine?: string;
productCode?: string;
promotion?: boolean;
}
export interface BasicData {
goodsCategoryList: number[] | goodsCategory[];
name: string;
status: string;
isImport: string;
isNews: string;
isUnconventional: string;
isPromotion: string;
sort?: number;
pageKeyword?: string;
pageRemark?: string;
remark?: string;
}
export interface goodsCategory {
id: number;
}
<template>
<div class="">
<a-input-search
v-model:value="value"
placeholder="input search text"
enter-button="Search"
size="large"
@search="onSearch"
/>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
</script>
<style lang="less" scoped></style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论