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

feat: 商城基本结构完成

上级 078039c5
......@@ -26,7 +26,7 @@ export function generateModifyVars(dark = false) {
'info-color': primary,
'processing-color': primary,
'success-color': '#55D187', // Success color
'error-color': '#ED6F6F', // False color
'error-color': '#ff4d4f', // False color
'warning-color': '#EFBD47', // Warning color
//'border-color-base': '#EEEEEE',
'font-size-base': '14px', // Main font size
......
......@@ -94,11 +94,11 @@ export interface Goods {
/**
* ID系统自动生成
*/
id?: number;
id: number;
/**
* ID系统自动生成
*/
productList?: Array<Product>;
productList: Array<Product>;
/**
* 经销商id
*/
......@@ -139,12 +139,19 @@ export interface Goods {
* update_time
*/
updateTime?: Date;
// 商品分类列表
goodsCategoryList: Array<{ id: number }> | number[];
// 名称
name: string;
// 图片
pic?: string | string[];
// 是否新品
isNews: string;
// 页面描述
pageRemark?: string;
// 套件数量
quantity: number;
uuid: string;
}
export type GoodsPageResult = PageResult<Goods>;
......
......@@ -100,6 +100,10 @@ export interface Product {
updateTime?: Date;
quantity: number;
// 记录使用
basicQuantity: number;
uuid: string;
type: string;
}
export type ProductPageResult = PageResult<Product>;
......
import { defineStore } from 'pinia';
import { store } from '/@/store';
interface ShoppingStore {
shoppingCart: any[];
}
export const useShoppingStore = defineStore({
id: 'app-shoppingStore',
state: (): ShoppingStore => ({
shoppingCart: [
{
id: 5,
goodsCategoryList: [
{
id: 33,
distributorId: 0,
name: '正天生物型翻修柄成套手术器械',
parentId: 32,
sort: 0,
status: 'YES',
lineName: '正天关节',
lineThirdId: '3',
remark: '',
editorId: 1,
editorName: '管理员',
createTime: '2022-11-07 14:03:12',
updateTime: '2022-11-07 14:03:12',
},
],
distributorId: 0,
name: '医用持针钳',
pic: 'http://192.168.101.69:8087/upload/20221031/d4844172-f412-4bc9-93ec-86db1fc7fbf6.png',
price: 0,
pageRemark: '提示:A类为临床常规规格,B类为临床少用规格,C类为临床极少用规格;定制专区产品,订货不退不换',
pageKeyword: '钳子',
remark: '医用不锈钢止血钳 结实耐用',
status: 'YES',
isImport: 'NO',
isNews: 'YES',
isUnconventional: 'NO',
isPromotion: 'NO',
sort: 1,
goodsType: 'PRODUCT',
deleteStatus: 'NO',
editorId: 1,
editorName: 'root',
createTime: '2022-10-31 16:54:06',
updateTime: '2022-11-08 15:42:08',
lineName: '正天关节',
categoryName: '正天生物型翻修柄成套手术器械',
productList: [
{
id: 4,
distributorId: 0,
thirdProductId: 'ZT.QC12046',
editorId: 1,
editorName: '管理员',
createTime: '2022-10-31 16:54:06',
updateTime: '2022-10-31 16:54:06',
quantity: 1,
uuid: '5-4',
type: 'PRODUCT',
},
{
id: 5,
distributorId: 0,
thirdProductId: 'ZT.QC12045',
editorId: 1,
editorName: '管理员',
createTime: '2022-10-31 16:54:06',
updateTime: '2022-10-31 16:54:06',
quantity: 1,
uuid: '5-5',
type: 'PRODUCT',
},
{
id: 6,
distributorId: 0,
thirdProductId: 'ZT.QC12047',
editorId: 1,
editorName: '管理员',
createTime: '2022-10-31 16:54:06',
updateTime: '2022-10-31 16:54:06',
quantity: 1,
uuid: '5-6',
type: 'PRODUCT',
},
],
uuid: '5',
},
{
id: 7,
goodsCategoryList: [
{
id: 33,
distributorId: 0,
name: '正天生物型翻修柄成套手术器械',
parentId: 32,
sort: 0,
status: 'YES',
lineName: '正天关节',
lineThirdId: '3',
remark: '',
editorId: 1,
editorName: '管理员',
createTime: '2022-11-07 14:03:12',
updateTime: '2022-11-09 15:49:50',
},
],
distributorId: 0,
name: 'NS2 白金钉棒成套器械',
pic: 'http://192.168.101.69:8087/upload/20221108/8232144a-3232-44d4-b6fc-0764d94642a9.jpg',
price: 0,
pageRemark: '提示:A类为临床常用规格,B类为临床少用规格,C类为临床极少用规格;定制专区产品,订货不退不换。',
pageKeyword: 'NS2 白金钉棒成套器械',
remark: '最新版NS2 白金钉棒成套器械',
status: 'YES',
isImport: 'NO',
isNews: 'NO',
isUnconventional: 'NO',
isPromotion: 'YES',
sort: 0,
goodsType: 'KIT',
deleteStatus: 'NO',
editorId: 1,
editorName: 'root',
createTime: '2022-11-08 14:26:57',
updateTime: '2022-11-08 14:27:08',
lineName: '正天关节',
categoryName: '正天生物型翻修柄成套手术器械',
productList: [
{
id: 1,
distributorId: 0,
thirdProductId: '1',
editorId: 1,
editorName: '管理员',
createTime: '2022-10-31 13:46:07',
updateTime: '2022-10-31 13:46:07',
quantity: 2,
basicQuantity: 1,
uuid: '7-1',
type: 'KIT',
},
{
id: 2,
distributorId: 0,
thirdProductId: '2',
editorId: 1,
editorName: '管理员',
createTime: '2022-10-31 13:46:07',
updateTime: '2022-10-31 13:46:07',
quantity: 4,
basicQuantity: 2,
uuid: '7-2',
type: 'KIT',
},
],
uuid: '7',
quantity: 2,
},
],
}),
getters: {
getShoppingCartList(): any[] {
return this.shoppingCart;
},
},
actions: {
setShoppingCart(goods: any) {
const flag = this.shoppingCart.some((item, index) => {
if (item.id === goods.id) {
this.shoppingCart[index] = goods;
return true;
}
});
if (!flag) {
this.shoppingCart.push(goods);
}
},
removeSoppingCartByGoodsId(id) {
const idx = this.shoppingCart.findIndex((item) => {
return item.id === id * 1;
});
this.shoppingCart.splice(idx, 1);
},
removeSoppingCartByProductId(ids) {
this.shoppingCart.some((item) => {
if (item.id === ids[0] * 1) {
const idx = item.productList.findIndex((pro) => {
return pro.id === ids[1] * 1;
});
item.productList.splice(idx, 1);
return true;
}
});
},
removeAll() {
this.shoppingCart.length = 0;
},
},
});
export function useShoppingStoreWithOut() {
return useShoppingStore(store);
}
......@@ -5,15 +5,17 @@ export enum logisticsValEnum {
EXPRESS = 'EXPRESS',
SPECIALLY_ASSIGNED = 'SPECIALLY_ASSIGNED',
TRAIN = 'TRAIN',
THIRD_PARTY = 'THIRD_PARTY',
FLY = 'FLY',
}
export enum logisticsLabelEnum {
SELF = '自提',
BAR = '大巴',
EXPRESS = '快递',
SPECIALLY_ASSIGNED = '专人配送',
TRAIN = '火车',
FLY = '空运',
SELF = '自提(亲自上门提货或还货)',
BAR = '大巴(车站至车站的汽运)',
EXPRESS = '快递(如需指定快递公司请备注)',
SPECIALLY_ASSIGNED = '专人配送(需电话申请,运费另计)',
TRAIN = '火车(需电话申请,运费另计)',
THIRD_PARTY = '第三方物流(零担,需先电话申请)',
FLY = '空运(需电话申请,运费另计)',
}
export const logisticsEnumOptions: any[] = [];
for (const key in logisticsLabelEnum) {
......
......@@ -36,6 +36,7 @@
<a-form-item label="分类名称" name="name">
<a-input v-model:value="formData.name" :disabled="formData.parentId === 0" />
</a-form-item>
<!-- <a-form-item label="图标" name="sort" v-if="selectClassifyLevel === 5"> <Picture /> </a-form-item> -->
<a-form-item label="排序" name="sort">
<a-input-number v-model:value="formData.sort" :min="0" />
</a-form-item>
......@@ -62,7 +63,7 @@
import * as thirdApi from '/@/api/system/thirdApi';
import { DataItem } from '/@/views/product/goods-category/type';
import { GoodsCategory } from '/@/api/model/goodsCategory';
// import Picture from '/@/views/product/goods/components/picture.vue';
import { fieldNames, rulesRef } from './schema';
import lodash from 'lodash';
......@@ -79,6 +80,7 @@
lineThirdId: undefined,
parentId: 0,
});
// const selectClassifyLevel = ref(0);
// 树结构选项
const classifyTree = ref<DataItem[]>([]);
......@@ -88,6 +90,7 @@
const getTreeData = () => {
GoodsCategoryApi.tree({ parentId: 0 }).then((res: DataItem[]) => {
res.unshift({
children: [],
name: '顶级分类',
id: 0,
});
......@@ -107,6 +110,11 @@
});
};
// 选择分类类型
// const handleChangeClass = (value, node, extra) => {
// selectClassifyLevel.value = node.level;
// };
const handleChangeLine = (value, option) => {
formData.name = option.key;
formData.lineName = option.key;
......
差异被折叠。
import { reactive } from 'vue';
export const rulesRef = reactive({
saleUserName: [
{
required: true,
message: '请选择业务员',
},
],
invoicingCompany: [
{
required: true,
message: '请输入开票公司',
},
],
exWarehouse: [
{
required: true,
message: '请选择出货仓库',
},
],
logisticsMode: [
{
required: true,
message: '请选择发货方式',
},
],
address: [
{
required: true,
message: '请选择收货地址',
},
],
receiveName: [
{
required: true,
message: '请输入收货人',
},
],
receivePhone: [
{
required: true,
message: '请输入联系电话',
},
],
});
<template>
<a-modal v-model:visible="visible" title="选择业务员" @ok="handleOk" width="800px">
<a-form
:model="formData"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 14 }"
autocomplete="off"
ref="formRef"
layout="inline"
class="ant-row"
>
<a-form-item label="收货人" name="receiveName">
<a-input v-model:value="formData.receiveName"></a-input>
</a-form-item>
<a-form-item label="电话" name="receivePhone">
<a-input v-model:value="formData.receivePhone"></a-input>
</a-form-item>
<a-form-item :wrapper-col="{ span: 24 }">
<a-button @click="handleReset">重置</a-button>
<a-button type="primary" @click="getSaleUser">查询</a-button>
</a-form-item>
</a-form>
<a-table
:dataSource="dataSource"
:columns="columns"
:pagination="pagination"
childrenColumnName="productList"
rowKey="uuid"
:scroll="{ y: 450 }"
:loading="tableLoading"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'active'">
<a-button type="link" @click="handleChange(record)">选择</a-button>
</template>
</template>
</a-table>
</a-modal>
</template>
<script lang="ts" setup>
import { ref, defineExpose, watch, reactive, defineEmits } from 'vue';
import * as ReceiverApi from '/@/api/system/receiverApi';
import { StatusValEnum as ReceiverStatusValEnum } from '/@/views/system/receiver/enum';
import { useUserStore } from '/@/store/modules/user';
import { usePagination } from '/@/hooks/myhooks/index';
const userStore = useUserStore();
const emits = defineEmits(['handleChange']);
const formRef = ref();
const visible = ref<boolean>(false);
const dataSource = ref<any>([]);
const tableLoading = ref(false);
const formData = reactive({
receiveName: undefined,
receivePhone: undefined,
});
const columns = [
{
title: '编号',
dataIndex: 'id',
key: 'id',
},
{
title: '地址',
dataIndex: 'address',
key: 'address',
},
{
title: '收货人',
dataIndex: 'receiveName',
key: 'receiveName',
},
{
title: '电话',
dataIndex: 'receivePhone',
key: 'receivePhone',
},
{
title: '操作',
key: 'active',
},
];
const handleOk = () => {
visible.value = false;
formRef.value.resetFields();
};
const getSaleUser = () => {
tableLoading.value = true;
ReceiverApi.search(
Object.assign(
{
status: ReceiverStatusValEnum.PASSED,
distributorId: userStore.getIsDistributor ? userStore.getDistributorId : undefined,
pageSize: pagination.pageSize,
pageNum: pagination.current,
},
formData,
),
)
.then((res) => {
pagination.total = res.total;
dataSource.value = res.records;
})
.finally(() => {
tableLoading.value = false;
});
};
const pagination = usePagination(getSaleUser);
const handleChange = (record) => {
emits('handleChange', record);
handleOk();
};
const handleReset = () => {
formRef.value.resetFields();
};
watch(
() => visible.value,
(n) => {
if (n) getSaleUser();
},
);
defineExpose({ visible });
</script>
<style lang="less" scoped>
@import url('/@/style/index.less');
.ant-row {
margin-bottom: 20px;
.ant-btn {
margin-right: 10px;
}
}
</style>
<template>
<a-modal v-model:visible="visible" title="选择业务员" @ok="handleOk" width="800px">
<a-form
:model="formData"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 14 }"
autocomplete="off"
ref="formRef"
layout="inline"
class="ant-row"
>
<a-form-item label="用户名" name="username">
<a-input v-model:value="formData.username"></a-input>
</a-form-item>
<a-form-item label="姓名" name="realName">
<a-input v-model:value="formData.realName"></a-input>
</a-form-item>
<a-form-item :wrapper-col="{ span: 24 }">
<a-button @click="handleReset">重置</a-button>
<a-button type="primary" @click="getSaleUser">查询</a-button>
</a-form-item>
</a-form>
<a-table
:dataSource="dataSource"
:columns="columns"
:pagination="pagination"
childrenColumnName="productList"
rowKey="uuid"
:scroll="{ y: 450 }"
:loading="tableLoading"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'active'">
<a-button type="link" @click="handleChange(record)">选择</a-button>
</template>
</template>
</a-table>
</a-modal>
</template>
<script lang="ts" setup>
import { ref, defineExpose, watch, reactive, defineEmits } from 'vue';
import * as UserApi from '/@/api/system/userApi';
import { RoleEnum } from '/@/views/system/role/enum';
import { StatusValEnum as UserStatusValEnum } from '/@/views/system/user/enum';
import { useUserStore } from '/@/store/modules/user';
import { usePagination } from '/@/hooks/myhooks/index';
const userStore = useUserStore();
const emits = defineEmits(['handleChange']);
const formRef = ref();
const visible = ref<boolean>(false);
const dataSource = ref<any>([]);
const tableLoading = ref(false);
const formData = reactive({
username: undefined,
realName: undefined,
});
const columns = [
{
title: '编号',
dataIndex: 'id',
key: 'id',
},
{
title: '用户名',
dataIndex: 'username',
key: 'username',
},
{
title: '姓名',
dataIndex: 'realName',
key: 'realName',
},
{
title: '操作',
key: 'active',
},
];
const handleOk = () => {
visible.value = false;
formRef.value.resetFields();
};
const getSaleUser = () => {
tableLoading.value = true;
UserApi.search(
Object.assign(
{
role: RoleEnum.SALESMAN,
status: UserStatusValEnum.PASSED,
distributorId: userStore.getIsDistributor ? userStore.getDistributorId : undefined,
pageSize: pagination.pageSize,
pageNum: pagination.current,
},
formData,
),
)
.then((res) => {
pagination.total = res.total;
dataSource.value = res.records;
})
.finally(() => {
tableLoading.value = false;
});
};
const pagination = usePagination(getSaleUser);
const handleChange = (record) => {
emits('handleChange', record);
handleOk();
};
const handleReset = () => {
formRef.value.resetFields();
};
watch(
() => visible.value,
(n) => {
if (n) getSaleUser();
},
);
defineExpose({ visible });
</script>
<style lang="less" scoped>
@import url('/@/style/index.less');
.ant-row {
margin-bottom: 20px;
.ant-btn {
margin-right: 10px;
}
}
</style>
......@@ -7,11 +7,29 @@
size="large"
@search="onSearch"
/>
<div class="shoppingCart" @click="handleGoShoppingCart">
<a-badge :count="shoppingCartNum.length">
<ShoppingCartOutlined />
</a-badge>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { ref, defineProps } from 'vue';
import { ShoppingCartOutlined } from '@ant-design/icons-vue';
import { useShoppingStoreWithOut } from '/@/store/modules/store';
import { useGo } from '/@/hooks/web/usePage';
const go = useGo();
const shoppingStore = useShoppingStoreWithOut();
const props = defineProps(['navId']);
const shoppingCartNum = shoppingStore.shoppingCart;
const handleGoShoppingCart = () => {
go('/main/store/shopping-cart' + `?nav=${props.navId}`);
};
const searchInfo = ref('');
const onSearch = () => {};
......@@ -19,7 +37,35 @@
<style lang="less" scoped>
.searchWrap {
width: 500px;
margin: 0 auto 30px;
width: 100%;
position: relative;
text-align: center;
.ant-input-group-wrapper {
width: 500px;
}
.shoppingCart {
width: 40px;
height: 40px;
text-align: center;
position: absolute;
right: 20px;
top: 0;
line-height: 40px;
font-size: 30px;
cursor: pointer;
&:hover {
background: #eee;
border-radius: 50%;
}
.ant-badge {
width: 40px;
height: 40px;
font-size: 30px;
}
}
}
</style>
<template>
<div class="containe">
<Search></Search>
<Search :navId="navId"></Search>
<div class="contentWrap">
<div class="top">
<div class="title">{{ title }}</div>
......@@ -22,38 +22,56 @@
<div class="title">
<p class="name">{{ goodsInfo?.name }}</p>
<p class="remark">{{ goodsInfo?.remark }}</p>
<div class="goodsNum">套数: <a-input-number id="inputNumber" v-model:value="goodsNum" :min="1" /></div>
<div class="goodsNum"
>套数: <a-input-number id="inputNumber" v-model:value="goodsNum" :min="0" @change="handleChangeGoodsNum"
/></div>
<p class="pageRemark">{{ goodsInfo?.pageRemark }}</p>
</div>
</div>
<div class="productList">
<p class="title">产品明细列表</p>
<a-table :dataSource="productList" :columns="columns">
<a-table :dataSource="productList" :columns="columns" :pagination="false">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'quantity'">
<a-input v-model:value="record.quantity" :disabled="isKIT" />
<a-input-number v-model:value="record.quantity" :min="0" :disabled="isKIT" />
</template>
</template>
</a-table>
<div class="shoppingBtn">
<a-button type="primary" danger size="large" @click="handleGoShoppingCart">
<template #icon>
<shopping-cart-outlined />
</template>
加入购物车
</a-button>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, watch, computed } from 'vue';
import { ref, onMounted, computed, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useNavTree } from '/@/hooks/myhooks/index';
import * as GoodsApi from '/@/api/product/goodsApi';
import { toNumber } from 'lodash';
import { useGo } from '/@/hooks/web/usePage';
import { toNumber, cloneDeep } from 'lodash';
import Search from '../components/search.vue';
import Nav from '../components/nav.vue';
import { DataItem } from '/@/views/product/goods-category/type';
import { Goods } from '/@/api/model/goods';
import { Product } from '/@/api/model/product';
import { columns } from './schema';
import { ShoppingCartOutlined } from '@ant-design/icons-vue';
import { useShoppingStoreWithOut } from '/@/store/modules/store';
import { message } from 'ant-design-vue';
const go = useGo();
const route = useRoute();
const navTree = useNavTree();
const shoppingStore = useShoppingStoreWithOut();
const query = route.query;
const navId = toNumber(query.nav); // 一级选择id
......@@ -64,46 +82,8 @@
const goodsInfo = ref<Goods>(); // 商品信息
const picList = ref<string[]>([]); // 图片列表
const changeImg = ref(''); // 选择查看的图片地址
const goodsNum = ref(1); // 选择套件数
const productList = ref<Array<Product>>([]);
const columns = [
{
title: '产品编号',
dataIndex: 'thirdProductId',
key: 'thirdProductId',
},
{
title: '名称',
dataIndex: 'age',
key: 'age',
},
{
title: '描述信息',
dataIndex: 'address',
key: 'address',
},
{
title: '型号',
dataIndex: 'address1',
key: 'address1',
},
{
title: '包装',
dataIndex: 'address2',
key: 'address2',
},
{
title: '类型',
dataIndex: 'address2',
key: 'address2',
},
{
title: '数量',
key: 'quantity',
width: '100px',
},
];
const goodsNum = ref(0); // 选择套件数
const productList = ref<Array<Product>>([]); // 产品列表
const getGrandsonList = (arr: DataItem[]) => {
arr.some((item) => {
......@@ -114,14 +94,20 @@
});
};
// 获取商品信息
const getGoodsInfo = () => {
GoodsApi.getById(goodsId).then((res) => {
goodsInfo.value = res;
if (res.productList) {
if (!isKIT.value) {
if (isPRODUCT.value) {
res.productList.forEach((item) => {
item.quantity = 0;
});
} else if (isKIT.value) {
res.productList.forEach((item) => {
item.basicQuantity = item.quantity;
item.quantity = 0;
});
}
productList.value = res.productList;
......@@ -131,19 +117,109 @@
picList.value = res.pic.split(',');
changeImg.value = picList.value[0];
}
// echo();
});
};
// 选择展示的图片
const handleChangeImg = (url) => {
changeImg.value = url;
};
// 选择套数
const handleChangeGoodsNum = (num) => {
if (isPRODUCT.value) {
productList.value.forEach((item) => {
item.quantity = num;
});
} else if (isKIT.value) {
productList.value.forEach((item) => {
item.quantity = num * item.basicQuantity;
});
}
};
// 加入购物车
const handleGoShoppingCart = () => {
const goods = cloneDeep(goodsInfo.value);
if (goods) {
goods.pic = picList.value[0];
goods.uuid = goods.id + '';
}
if (isKIT.value && goods) {
if (goodsNum.value === 0) {
return message.warning('请填写套件数量!');
}
goods.productList.forEach((item) => {
item.uuid = goods.id + '-' + item.id;
item.type = 'KIT';
});
goods.quantity = goodsNum.value;
shoppingStore.setShoppingCart(goods);
} else if (isPRODUCT.value && goods) {
let flag = true;
const list = <any[]>[];
productList.value.forEach((item) => {
if (item.quantity > 0) {
item.uuid = goods.id + '-' + item.id;
list.push(item);
item.type = 'PRODUCT';
flag = false;
}
});
if (flag) return message.warning('请填写产品数量!');
goods.productList = list;
shoppingStore.setShoppingCart(goods);
}
message.success('添加成功');
};
// 回显
// const echo = () => {
// if (isKIT.value) {
// shoppingStore.shoppingCart.some((item) => {
// if (goodsInfo.value && item.id === goodsInfo.value.id) {
// item.productList.forEach((shoppingProduct) => {
// productList.value.some((product) => {
// if (shoppingProduct.id === product.id) {
// product.quantity = shoppingProduct.quantity;
// return true;
// }
// });
// });
// goodsNum.value = item.quantity;
// return true;
// }
// });
// }
// };
//是否是套件
const isKIT = computed(() => goodsInfo.value?.goodsType === 'KIT');
const isPRODUCT = computed(() => goodsInfo.value?.goodsType === 'PRODUCT');
onMounted(() => {
navTree(navList, getGrandsonList, 'getGrandsonList');
getGoodsInfo();
});
watch(
() => navActiveKey.value,
(n) => {
shoppingStore.removeAll();
go('/main/store/home' + `?id=${n}`);
},
);
</script>
<style scoped lang="less">
......@@ -257,6 +333,11 @@
font-size: 20px;
margin-bottom: 20px;
}
.shoppingBtn {
margin-top: 20px;
text-align: right;
}
}
}
}
......
export const columns = [
{
title: '产品编号',
dataIndex: 'thirdProductId',
key: 'thirdProductId',
},
{
title: '名称',
dataIndex: 'age',
key: 'age',
},
{
title: '描述信息',
dataIndex: 'address',
key: 'address',
},
{
title: '型号',
dataIndex: 'address1',
key: 'address1',
},
{
title: '包装',
dataIndex: 'address2',
key: 'address2',
},
{
title: '类型',
dataIndex: 'address2',
key: 'address2',
},
{
title: '数量',
key: 'quantity',
width: '100px',
},
];
<template>
<div class="containe">
<Search></Search>
<Search :navId="navId"></Search>
<div class="contentWrap">
<div class="top">
<div class="title">{{ title }}</div>
......@@ -77,11 +77,13 @@
import * as GoodsApi from '/@/api/product/goodsApi';
import newPng from '/@/assets/images/new.png';
import nopl from '/@/assets/images/nopl.jpg';
import { useShoppingStoreWithOut } from '/@/store/modules/store';
const go = useGo();
const route = useRoute();
const navTree = useNavTree();
const userStore = useUserStore();
const shoppingStore = useShoppingStoreWithOut();
const query = route.query;
const navId = toNumber(query.nav); // 一级选择id
......@@ -100,7 +102,7 @@
const goodsList = ref<Goods[]>([]);
const pageNum = ref(1);
const pageSize = ref(10);
const total = ref(500);
const total = ref(0);
const formQuery = { isAll: true, goodsCategoryId: tabItemId };
// 获取四五级分类列表
......@@ -170,6 +172,7 @@
watch(
() => navActiveKey.value,
(n) => {
shoppingStore.removeAll();
go('/main/store/home' + `?id=${n}`);
},
);
......
<template>
<div class="containe">
<Search></Search>
<Search :navId="navActiveKey"></Search>
<div class="contentWrap">
<div class="top">
<div class="menu">
......
<template>
<div class="containe">
<Search :navId="navId"></Search>
<div class="contentWrap">
<div class="top">
<div class="title">{{ title }}</div>
<div class="wrap">
<Nav v-model:navList="navList" v-model:navActiveKey="navActiveKey" />
</div>
</div>
<div class="info">
<a-steps :current="0" size="small">
<a-step title="我的购物车" />
<a-step title="填写核对订单信息" />
<a-step title="提交订单" />
</a-steps>
<div class="productList">
<a-table
:dataSource="productList"
:columns="columns"
:pagination="false"
childrenColumnName="productList"
rowKey="uuid"
:scroll="{ y: 450 }"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'type'">
<span v-if="record.goodsType === 'PRODUCT'">产品</span>
<span v-else-if="record.goodsType === 'KIT'">套件</span>
</template>
<template v-if="column.key === 'quantity'">
<a-input-number
v-model:value="record.quantity"
:min="1"
@change="handleQuantityChange($event, record)"
:disabled="record.type === 'KIT'"
/>
</template>
<template v-if="column.key === 'active' && record.type != 'KIT'">
<a-popconfirm
title="是否确认删除?"
ok-text="是"
cancel-text="否"
@confirm="confirm(record.uuid)"
@cancel="() => {}"
>
<a-button type="link">删除</a-button>
</a-popconfirm>
</template>
</template>
</a-table>
<div class="btnWrap">
<a-button type="default" size="large" @click="handleEmptyShoppingCart">
<template #icon>
<shopping-cart-outlined />
</template>
清空购物车
</a-button>
<div class="right">
<span class="title"
>已选数量:<span class="num">{{ productNum }}</span
></span
>
<a-button type="primary" size="large" @click="handleGoCheckOrder"> 去结算 </a-button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, computed, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useNavTree } from '/@/hooks/myhooks/index';
import { useShoppingStoreWithOut } from '/@/store/modules/store';
import Search from '../components/search.vue';
import Nav from '../components/nav.vue';
import { DataItem } from '/@/views/product/goods-category/type';
import { toNumber } from 'lodash';
import { columns } from './schema';
import { ShoppingCartOutlined } from '@ant-design/icons-vue';
import { useGo } from '/@/hooks/web/usePage';
const go = useGo();
const navTree = useNavTree();
const route = useRoute();
const shoppingStore = useShoppingStoreWithOut();
const query = route.query;
const navId = toNumber(query.nav); // 一级选择id
const navList = ref<DataItem[]>([]); // 菜单树
const navActiveKey = ref(navId); // 一级标签选择
const title = ref(''); // 标题名称
const productList = shoppingStore.shoppingCart;
const getGrandsonList = (arr: DataItem[]) => {
arr.some((item) => {
if (item.id === navId) {
title.value = item.name;
return true;
}
});
};
// 删除
const confirm = (uuid) => {
const uuidArr = uuid.split('-');
if (uuidArr.length === 1) {
shoppingStore.removeSoppingCartByGoodsId(uuidArr[0]);
} else if (uuidArr.length === 2) {
shoppingStore.removeSoppingCartByProductId(uuidArr);
}
};
// 数量改变
const handleQuantityChange = (val, record) => {
if (record.productList) {
record.productList.forEach((product) => {
if (record.goodsType === 'KIT') {
product.quantity = product.basicQuantity * val;
} else if (record.goodsType === 'PRODUCT') {
product.quantity = val;
}
});
}
};
// 清空购物车
const handleEmptyShoppingCart = () => {
shoppingStore.removeAll();
};
const productNum = computed(() => {
let num = 0;
shoppingStore.shoppingCart.forEach((item) => {
item.productList.forEach((product) => {
num += product.quantity;
});
});
return num;
});
const handleGoCheckOrder = () => {
go('/main/store/check-order' + `?nav=${navId}`);
};
watch(
() => navActiveKey.value,
(n) => {
shoppingStore.removeAll();
go('/main/store/home' + `?id=${n}`);
},
);
onMounted(() => {
navTree(navList, getGrandsonList, 'getGrandsonList');
});
</script>
<style lang="less" scoped>
p {
margin: 0;
padding: 0;
}
.containe {
padding: 30px;
.contentWrap {
padding: 30px;
background: #fff;
border-radius: 10px;
max-width: 1400px;
min-width: 1200px;
margin: 0 auto;
.top {
display: flex;
justify-content: space-between;
.title {
width: 25%;
background: #f7f9fa;
color: #1890ff;
border-radius: 10px;
text-align: center;
height: 50px;
padding: 5px;
line-height: 40px;
font-size: 20px;
}
.wrap {
width: 73%;
margin: 0;
}
}
.info {
.ant-steps {
width: 800px;
margin: 20px auto;
}
.productList {
.ant-table-wrapper {
height: 505px;
}
.btnWrap {
background: #2d374b;
height: 80px;
line-height: 40px;
padding: 20px 40px;
border-radius: 0 0 10px 10px;
display: flex;
justify-content: space-between;
.right {
color: #fff;
height: 40px;
line-height: 40px;
display: flex;
align-content: center;
.title {
font-size: 20px;
margin-right: 40px;
.num {
font-size: 30px;
font-weight: 600;
color: #ff0003;
}
}
}
}
}
}
}
}
</style>
export const columns = [
{
title: '产品编号',
dataIndex: 'thirdProductId',
key: 'thirdProductId',
},
{
title: '名称',
dataIndex: 'name',
key: 'name',
},
{
title: '类型',
key: 'type',
},
{
title: '描述信息',
dataIndex: 'address',
key: 'address',
},
{
title: '型号',
dataIndex: 'address1',
key: 'address1',
},
{
title: '数量',
key: 'quantity',
dataIndex: 'quantity',
width: '120px',
},
{
title: '单位',
key: 'unit',
dataIndex: 'unit',
width: '80px',
},
{
title: '价格',
key: 'price',
dataIndex: 'price',
width: '120px',
},
{
title: '操作',
key: 'active',
width: '100px',
},
];
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论