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

feat: 商品价格完成

上级 97cd8e95
...@@ -141,6 +141,7 @@ export interface Goods { ...@@ -141,6 +141,7 @@ export interface Goods {
updateTime?: Date; updateTime?: Date;
goodsCategoryList: Array<{ id: number }> | number[]; goodsCategoryList: Array<{ id: number }> | number[];
name: string;
} }
export type GoodsPageResult = PageResult<Goods>; export type GoodsPageResult = PageResult<Goods>;
......
import { defHttp } from '/@/utils/http/axios';
const baseApi = '/v1/product/goods-price-distributor-relation';
/**
* 新增
*/
export const add = (data) => defHttp.post({ url: `${baseApi}/`, data: data });
export const search = (params) => defHttp.get({ url: `${baseApi}/search`, params });
export const getById = (id) => defHttp.get({ url: `${baseApi}/${id}` });
export const update = (data) => defHttp.put({ url: `${baseApi}/`, data });
export const remove = (id) => defHttp.delete({ url: `${baseApi}/${id}` });
...@@ -41,3 +41,8 @@ ...@@ -41,3 +41,8 @@
-ms-user-select: none; -ms-user-select: none;
user-select: none; user-select: none;
} }
p {
padding: 0;
margin: 0;
}
...@@ -43,3 +43,8 @@ svg, ...@@ -43,3 +43,8 @@ svg,
span { span {
outline: none !important; outline: none !important;
} }
p {
padding: 0 !important;
margin: 0 !important;
}
...@@ -8,11 +8,13 @@ import { createRouter, createWebHashHistory } from 'vue-router'; ...@@ -8,11 +8,13 @@ import { createRouter, createWebHashHistory } from 'vue-router';
export type LayoutMapKey = 'LAYOUT'; export type LayoutMapKey = 'LAYOUT';
const IFRAME = () => import('/@/views/common/iframe/FrameBlank.vue'); const IFRAME = () => import('/@/views/common/iframe/FrameBlank.vue');
const FULLSCREEN = () => import('/@/layouts/page/index.vue');
const LayoutMap = new Map<string, () => Promise<typeof import('*.vue')>>(); const LayoutMap = new Map<string, () => Promise<typeof import('*.vue')>>();
LayoutMap.set('LAYOUT', LAYOUT); LayoutMap.set('LAYOUT', LAYOUT);
LayoutMap.set('IFRAME', IFRAME); LayoutMap.set('IFRAME', IFRAME);
LayoutMap.set('FULLSCREEN', FULLSCREEN);
let dynamicViewsModules: Record<string, () => Promise<Recordable>>; let dynamicViewsModules: Record<string, () => Promise<Recordable>>;
...@@ -40,10 +42,7 @@ function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) { ...@@ -40,10 +42,7 @@ function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
}); });
} }
function dynamicImport( function dynamicImport(dynamicViewsModules: Record<string, () => Promise<Recordable>>, component: string) {
dynamicViewsModules: Record<string, () => Promise<Recordable>>,
component: string,
) {
const keys = Object.keys(dynamicViewsModules); const keys = Object.keys(dynamicViewsModules);
const matchKeys = keys.filter((key) => { const matchKeys = keys.filter((key) => {
const k = key.replace('../../views', ''); const k = key.replace('../../views', '');
...@@ -72,7 +71,7 @@ export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModul ...@@ -72,7 +71,7 @@ export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModul
routeList.forEach((route) => { routeList.forEach((route) => {
const component = route.component as string; const component = route.component as string;
if (component) { if (component) {
if (component.toUpperCase() === 'LAYOUT') { if (component.toUpperCase() === 'LAYOUT' || component.toUpperCase() === 'FULLSCREEN') {
route.component = LayoutMap.get(component.toUpperCase()); route.component = LayoutMap.get(component.toUpperCase());
} else { } else {
route.children = [cloneDeep(route)]; route.children = [cloneDeep(route)];
...@@ -123,11 +122,7 @@ function promoteRouteLevel(routeModule: AppRouteModule) { ...@@ -123,11 +122,7 @@ function promoteRouteLevel(routeModule: AppRouteModule) {
} }
// Add all sub-routes to the secondary route // Add all sub-routes to the secondary route
function addToChildren( function addToChildren(routes: RouteRecordNormalized[], children: AppRouteRecordRaw[], routeModule: AppRouteModule) {
routes: RouteRecordNormalized[],
children: AppRouteRecordRaw[],
routeModule: AppRouteModule,
) {
for (let index = 0; index < children.length; index++) { for (let index = 0; index < children.length; index++) {
const child = children[index]; const child = children[index];
const route = routes.find((item) => item.name === child.name); const route = routes.find((item) => item.name === child.name);
......
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
import { DataItem } from '/@/views/product/goods-category/type'; import { DataItem } from '/@/views/product/goods-category/type';
import { GoodsCategory } from '/@/api/model/goodsCategory'; import { GoodsCategory } from '/@/api/model/goodsCategory';
import { fieldNames, rulesRef } from './schema'; import { fieldNames, rulesRef } from './schema';
import lodash from 'lodash';
const visible = ref<boolean>(false); const visible = ref<boolean>(false);
const emits = defineEmits(['handleSuccess', 'update:editId']); const emits = defineEmits(['handleSuccess', 'update:editId']);
...@@ -97,11 +98,10 @@ ...@@ -97,11 +98,10 @@
GoodsCategoryApi.getById(props.editId).then((res) => { GoodsCategoryApi.getById(props.editId).then((res) => {
for (const key in formData) { for (const key in formData) {
formData[key] = res[key]; formData[key] = res[key];
formData.id = res.id; }
if (res.lineThirdId) { if (res.lineThirdId) {
formData.lineThirdId = res.lineThirdId * 1; formData.lineThirdId = res.lineThirdId * 1;
} }
}
}); });
}; };
...@@ -111,19 +111,20 @@ ...@@ -111,19 +111,20 @@
const handleOk = () => { const handleOk = () => {
formRef.value.validate().then(() => { formRef.value.validate().then(() => {
if (formData.parentId != 0) { const data = lodash.cloneDeep(formData);
formData.lineName = undefined; if (data.parentId != 0) {
formData.lineThirdId = undefined; data.lineName = undefined;
data.lineThirdId = undefined;
} }
let api; let api;
if (props.editId) { if (props.editId) {
data.id = props.editId;
api = GoodsCategoryApi.update; api = GoodsCategoryApi.update;
} else { } else {
if (formData.id) delete formData.id;
api = GoodsCategoryApi.add; api = GoodsCategoryApi.add;
} }
api(formData).then(() => { api(data).then(() => {
message.success('操作成功'); message.success('操作成功');
emits('handleSuccess'); emits('handleSuccess');
handleCancel(); handleCancel();
......
...@@ -14,14 +14,15 @@ ...@@ -14,14 +14,15 @@
<a-form-item label="商品名称" name="goodsName"> <a-form-item label="商品名称" name="goodsName">
<a-input v-model:value="formState.goodsName" /> <a-input v-model:value="formState.goodsName" />
</a-form-item> </a-form-item>
<a-form-item label="产品编号" name="goodsName"> <a-form-item label="经销商" name="distributorName">
<a-input v-model:value="formState.goodsName" /> <a-input v-model:value="formState.distributorName" />
</a-form-item>
<a-form-item label="产品线" name="goodsName">
<a-input v-model:value="formState.goodsName" />
</a-form-item> </a-form-item>
<a-form-item label="折扣时间" name="goodsName"> <a-form-item label="结束时间" name="discountEndTime">
<a-input v-model:value="formState.goodsName" /> <a-date-picker
v-model:value="formState.discountEndTimeTo"
:show-time="{ format: 'HH:mm:ss' }"
valueFormat="YYYY-MM-DD HH:mm:ss"
/>
</a-form-item> </a-form-item>
<a-form-item :wrapper-col="{ offset: 8, span: 16 }"> <a-form-item :wrapper-col="{ offset: 8, span: 16 }">
<a-button @click="handleReset">重置</a-button> <a-button @click="handleReset">重置</a-button>
...@@ -34,32 +35,76 @@ ...@@ -34,32 +35,76 @@
<span class="title">商品分类</span> <span class="title">商品分类</span>
<a-button type="primary" @click="handleAdd">新增</a-button> <a-button type="primary" @click="handleAdd">新增</a-button>
</div> </div>
<a-table :dataSource="dataSource" :columns="columns" :pagination="pagination"> </a-table> <a-table :dataSource="dataSource" :columns="columns" :pagination="pagination" :loading="tableLoading">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'name'">
<span>{{ record.goodsDto.name }}</span>
</template>
<template v-if="column.key === 'lineName'">
<span>{{ record.goodsDto.lineName }}</span>
</template>
<template v-if="column.key === 'distributor'">
<span>{{ record.distributor.name }}</span>
</template>
<template v-if="column.key === 'time'">
<span>{{ record.discountStartTime + ' - ' + record.discountEndTime }} </span>
</template>
<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" @click="handleEdit(record.id)">编辑</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> </div>
<Modal ref="modalRef" v-model:editId="editId" @handleSuccess="getData"></Modal>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue'; import { reactive, ref, onMounted } from 'vue';
import { usePagination } from '/@/hooks/myhooks/index'; import { usePagination } from '/@/hooks/myhooks/index';
import * as GoodsApi from '/@/api/product/goodsApi'; import * as GoodsPriceApi from '/@/api/product/goodsPriceApi';
import { columns } from './schema'; import { columns } from './schema';
import Modal from './modal.vue';
import { message } from 'ant-design-vue';
import { usePermission } from '/@/hooks/web/usePermission';
const { hasPermission } = usePermission();
const formRef = ref(); const formRef = ref();
const modalRef = ref();
const tableLoading = ref(false);
const formState = reactive<FormState>({ const formState = reactive({
goodsName: undefined, goodsName: undefined,
distributorName: undefined,
discountEndTimeTo: undefined,
}); });
const dataSource = ref<Goods[]>(); const dataSource = ref();
const editId = ref();
const getData = () => { const getData = () => {
GoodsApi.search(Object.assign({ pageSize: pagination.pageSize, pageNum: pagination.current }, formState)).then( tableLoading.value = true;
(res) => { GoodsPriceApi.search(Object.assign({ pageSize: pagination.pageSize, pageNum: pagination.current }, formState))
.then((res) => {
pagination.total = res.total; pagination.total = res.total;
dataSource.value = res.records; dataSource.value = res.records;
}, })
); .finally(() => {
tableLoading.value = false;
});
}; };
const pagination = usePagination(getData); const pagination = usePagination(getData);
...@@ -68,7 +113,24 @@ ...@@ -68,7 +113,24 @@
formRef.value.resetFields(); formRef.value.resetFields();
}; };
const handleAdd = () => {}; const handleAdd = () => {
modalRef.value.visible = true;
};
const handleEdit = (id) => {
editId.value = id;
handleAdd();
};
const handleDelete = (id) => {
GoodsPriceApi.remove(id).then((res) => {
message.success('删除成功');
getData();
});
};
onMounted(() => {
getData();
});
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
......
...@@ -14,27 +14,170 @@ ...@@ -14,27 +14,170 @@
ref="formRef" ref="formRef"
:rules="rulesRef" :rules="rulesRef"
> >
<a-form-item label="产品线" name="name"> <a-form-item label="经销商" name="distributorId">
<a-input v-model:value="formData.name" /> <a-select
v-model:value="formData.distributorId"
style="width: 100%"
placeholder="请选择"
:fieldNames="{ label: 'name', value: 'id' }"
:options="distributorOptions"
></a-select>
</a-form-item> </a-form-item>
<a-form-item label="商品" name="name"> <a-form-item label="商品" name="goods">
<a-input v-model:value="formData.name" /> <a-select
v-model:value="formData.goods"
show-search
label-in-value
placeholder="请搜索商品"
style="width: 100%"
:filter-option="false"
:not-found-content="fetching ? undefined : null"
:options="goodsOptions"
@search="fetchGoods"
>
<template v-if="fetching" #notFoundContent>
<a-spin size="small" />
</template>
</a-select>
</a-form-item> </a-form-item>
<a-form-item label="折扣时间期限" name="name"> <a-form-item label="折扣时间期限" name="time">
<a-input v-model:value="formData.name" /> <a-range-picker
v-model:value="formData.time"
:show-time="{ format: 'HH:mm:ss' }"
valueFormat="YYYY-MM-DD HH:mm:ss"
:placeholder="['开始时间', '结束时间']"
/>
</a-form-item> </a-form-item>
<a-form-item label="折扣设置" name="name"> <a-form-item label="折扣设置" name="discountRate">
<a-input v-model:value="formData.name" /> <a-input-number v-model:value="formData.discountRate" :max="10" :min="0" />
</a-form-item> </a-form-item>
<a-form-item label="状态" name="name"> <a-form-item label="状态" name="status">
<a-input v-model:value="formData.name" /> <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>
</a-form> </a-form>
</a-modal> </a-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineComponent } from 'vue'; import { defineExpose, ref, reactive, defineEmits, watch, defineProps } from 'vue';
import { rulesRef } from './schema';
import { message } from 'ant-design-vue';
import * as GoodsPriceApi from '/@/api/product/goodsPriceApi';
import * as DistributorApi from '/@/api/system/distributorApi';
import * as GoodsApi from '/@/api/product/goodsApi';
import { debounce, cloneDeep } from 'lodash-es';
import { Data } from './type';
const props = defineProps(['editId']);
const emits = defineEmits(['handleSuccess', 'update:editId']);
const formRef = ref<any>();
const visible = ref<boolean>(false);
const formData = reactive<Data>({
distributorId: undefined,
goodsId: undefined,
goods: undefined,
time: <string[]>[],
discountStartTime: '',
discountEndTime: '',
discountRate: 10,
status: 'NO',
id: undefined,
});
const distributorOptions = ref<any>([]);
const goodsOptions = ref();
const getDistributor = () => {
DistributorApi.all().then((res) => {
distributorOptions.value = res;
});
};
let lastFetchId = 0;
const fetching = ref(false);
const fetchGoods = debounce((value) => {
lastFetchId += 1;
const fetchId = lastFetchId;
goodsOptions.value = [];
fetching.value = true;
GoodsApi.search({ pageNum: 1, pageSize: 20, goodsName: value }).then((body) => {
if (fetchId !== lastFetchId) {
return;
}
const data = body.records.map((item) => ({
label: item.name,
value: item.id,
}));
goodsOptions.value = data;
fetching.value = false;
});
}, 300);
const handleOk = () => {
formRef.value.validate().then(() => {
const data = cloneDeep(formData);
data.discountStartTime = data.time[0];
data.discountEndTime = data.time[1];
if (data.goods) {
data.goodsId = data.goods.value;
}
let api;
if (props.editId) {
data.id = props.editId;
api = GoodsPriceApi.update;
} else {
api = GoodsPriceApi.add;
}
api(data).then((res) => {
message.success('操作成功');
emits('handleSuccess');
handleCancel();
});
});
};
const handleCancel = () => {
formRef.value.resetFields();
emits('update:editId', undefined);
visible.value = false;
};
const getEditInfo = () => {
GoodsPriceApi.getById(props.editId).then((res) => {
for (const key in formData) {
formData[key] = res[key];
}
formData.time = [res.discountStartTime, res.discountEndTime];
formData.goods = { value: res.goodsId };
fetchGoods(res.goodsDto.name);
});
};
watch(
() => visible.value,
(n) => {
if (n) {
getDistributor();
}
},
);
watch(
() => props.editId,
(newValue) => {
if (newValue) {
getEditInfo();
}
},
);
defineExpose({ visible });
</script> </script>
<style lang="less" scoped></style> <style lang="less" scoped></style>
export const columns = [ export const columns = [
{
title: '商品名称',
dataIndex: 'name',
key: 'name',
},
{ {
title: '产品线', title: '产品线',
dataIndex: 'lineName', dataIndex: 'lineName',
key: 'lineName', key: 'lineName',
}, },
{ {
title: '商品名称', title: '经销商',
dataIndex: 'name', dataIndex: 'distributor',
key: 'name', key: 'distributor',
}, },
{ {
title: '原价', title: '原价',
dataIndex: 'original', dataIndex: 'discountPrice',
key: 'original', key: 'discountPrice',
}, },
{ {
title: '折扣', title: '折扣',
dataIndex: 'discount', dataIndex: 'discountRate',
key: 'discount', key: 'discountRate',
}, },
{ {
title: '折扣时间期限', title: '折扣时间期限',
...@@ -35,3 +40,36 @@ export const columns = [ ...@@ -35,3 +40,36 @@ export const columns = [
width: '350px', width: '350px',
}, },
]; ];
export const rulesRef = {
distributorId: [
{
required: true,
message: '请选择经销商',
},
],
goods: [
{
required: true,
message: '请选择商品',
},
],
time: [
{
required: true,
message: '请选择折扣时间期限',
},
],
discountRate: [
{
required: true,
message: '请设置折扣',
},
],
status: [
{
required: true,
message: '请选择状态',
},
],
};
export interface Data {
distributorId?: string;
goodsId?: string;
goods: { value: string } | undefined;
time: string[];
discountStartTime: string;
discountEndTime: string;
discountRate: number;
status: string;
id?: number;
}
...@@ -35,9 +35,9 @@ ...@@ -35,9 +35,9 @@
<div class="tableWrap"> <div class="tableWrap">
<div class="titleWrap"> <div class="titleWrap">
<span class="title">商品分类</span> <span class="title">商品分类</span>
<a-button type="primary" @click="handleAdd">新增</a-button> <a-button type="primary" @click="handleAdd(false)">新增</a-button>
</div> </div>
<a-table :dataSource="dataSource" :columns="columns" :pagination="pagination"> <a-table :dataSource="dataSource" :columns="columns" :pagination="pagination" :loading="tableLoading">
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'"> <template v-if="column.key === 'status'">
<span v-if="record.status === 'YES'"></span> <span v-if="record.status === 'YES'"></span>
...@@ -82,6 +82,7 @@ ...@@ -82,6 +82,7 @@
const go = useGo(); const go = useGo();
const formRef = ref(); const formRef = ref();
const tableLoading = ref(false);
const formState = reactive<FormState>({ const formState = reactive<FormState>({
goodsName: undefined, goodsName: undefined,
...@@ -96,15 +97,18 @@ ...@@ -96,15 +97,18 @@
const dataSource = ref<Goods[]>(); const dataSource = ref<Goods[]>();
const getData = () => { const getData = () => {
tableLoading.value = true;
const data: any = {}; const data: any = {};
stateChange.value.forEach((item) => { stateChange.value.forEach((item) => {
data[item] = 'YES'; data[item] = 'YES';
}); });
GoodsApi.search( GoodsApi.search(Object.assign({ pageSize: pagination.pageSize, pageNum: pagination.current }, formState, data))
Object.assign({ pageSize: pagination.pageSize, pageNum: pagination.current }, formState, data), .then((res) => {
).then((res) => {
pagination.total = res.total; pagination.total = res.total;
dataSource.value = res.records; dataSource.value = res.records;
})
.finally(() => {
tableLoading.value = false;
}); });
}; };
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论