salary
parent
a557255b4a
commit
94943df4f9
@ -1,92 +0,0 @@ |
||||
import request from '@/config/axios' |
||||
|
||||
export interface Property { |
||||
propertyId?: number // 属性编号
|
||||
propertyName?: string // 属性名称
|
||||
valueId?: number // 属性值编号
|
||||
valueName?: string // 属性值名称
|
||||
} |
||||
|
||||
// TODO puhui999:是不是直接叫 Sku 更简洁一点哈。type 待后面,总感觉有个类型?
|
||||
export interface SkuType { |
||||
id?: number // 商品 SKU 编号
|
||||
spuId?: number // SPU 编号
|
||||
properties?: Property[] // 属性数组
|
||||
price?: number // 商品价格
|
||||
marketPrice?: number // 市场价
|
||||
costPrice?: number // 成本价
|
||||
barCode?: string // 商品条码
|
||||
picUrl?: string // 图片地址
|
||||
stock?: number // 库存
|
||||
weight?: number // 商品重量,单位:kg 千克
|
||||
volume?: number // 商品体积,单位:m^3 平米
|
||||
subCommissionFirstPrice?: number // 一级分销的佣金
|
||||
subCommissionSecondPrice?: number // 二级分销的佣金
|
||||
salesCount?: number // 商品销量
|
||||
} |
||||
|
||||
// TODO puhui999:是不是直接叫 Spu 更简洁一点哈。type 待后面,总感觉有个类型?
|
||||
export interface SpuType { |
||||
id?: number |
||||
name?: string // 商品名称
|
||||
categoryId?: number | null // 商品分类
|
||||
keyword?: string // 关键字
|
||||
unit?: number | null // 单位
|
||||
picUrl?: string // 商品封面图
|
||||
sliderPicUrls?: string[] // 商品轮播图
|
||||
introduction?: string // 商品简介
|
||||
deliveryTemplateId?: number | null // 运费模版
|
||||
brandId?: number | null // 商品品牌编号
|
||||
specType?: boolean // 商品规格
|
||||
subCommissionType?: boolean // 分销类型
|
||||
skus: SkuType[] // sku数组
|
||||
description?: string // 商品详情
|
||||
sort?: string // 商品排序
|
||||
giveIntegral?: number // 赠送积分
|
||||
virtualSalesCount?: number // 虚拟销量
|
||||
recommendHot?: boolean // 是否热卖
|
||||
recommendBenefit?: boolean // 是否优惠
|
||||
recommendBest?: boolean // 是否精品
|
||||
recommendNew?: boolean // 是否新品
|
||||
recommendGood?: boolean // 是否优品
|
||||
} |
||||
|
||||
// 获得 Spu 列表
|
||||
export const getSpuPage = (params: PageParam) => { |
||||
return request.get({ url: '/product/spu/page', params }) |
||||
} |
||||
|
||||
// 获得 Spu 列表 tabsCount
|
||||
export const getTabsCount = () => { |
||||
return request.get({ url: '/product/spu/get-count' }) |
||||
} |
||||
|
||||
// 创建商品 Spu
|
||||
export const createSpu = (data: SpuType) => { |
||||
return request.post({ url: '/product/spu/create', data }) |
||||
} |
||||
|
||||
// 更新商品 Spu
|
||||
export const updateSpu = (data: SpuType) => { |
||||
return request.put({ url: '/product/spu/update', data }) |
||||
} |
||||
|
||||
// 更新商品 Spu status
|
||||
export const updateStatus = (data: { id: number; status: number }) => { |
||||
return request.put({ url: '/product/spu/update-status', data }) |
||||
} |
||||
|
||||
// 获得商品 Spu
|
||||
export const getSpu = (id: number) => { |
||||
return request.get({ url: `/product/spu/get-detail?id=${id}` }) |
||||
} |
||||
|
||||
// 删除商品 Spu
|
||||
export const deleteSpu = (id: number) => { |
||||
return request.delete({ url: `/product/spu/delete?id=${id}` }) |
||||
} |
||||
|
||||
// 导出商品 Spu Excel
|
||||
export const exportSpu = async (params) => { |
||||
return await request.download({ url: '/product/spu/export', params }) |
||||
} |
@ -0,0 +1,25 @@ |
||||
import request from '@/config/axios' |
||||
// 查询列表
|
||||
export const getPurchasePage = async (params) => { |
||||
return await request.get({ url: '/admin-api/crm/erp-purchase/page', params }) |
||||
} |
||||
|
||||
// 新增
|
||||
export const createPurchase = async (data) => { |
||||
return await request.post({ url: '/admin-api/crm/erp-purchase/create', data: data }) |
||||
} |
||||
|
||||
// 修改
|
||||
export const updatePurchase = async (params) => { |
||||
return await request.put({ url: '/admin-api/crm/erp-purchase/update', data: params }) |
||||
} |
||||
|
||||
// 删除
|
||||
export const deletePurchase = async (id) => { |
||||
return await request.delete({ url: '/admin-api/crm/erp-purchase/delete?id=' + id }) |
||||
} |
||||
|
||||
// 审核
|
||||
export const auditPurchase = async (params) => { |
||||
return await request.get({ url: '/admin-api/crm/erp-purchase/audit', params }) |
||||
} |
@ -0,0 +1,26 @@ |
||||
import request from '@/config/axios' |
||||
|
||||
// 查询知识库列表
|
||||
export const getLibraryPage = (params) => { |
||||
return request.get({ url: '/admin-api/crm/knowledge-lib/page', params }) |
||||
} |
||||
|
||||
// 查询知识库详情
|
||||
export const getLibrary = (id) => { |
||||
return request.get({ url: '/admin-api/crm/knowledge-lib/get?id=' + id }) |
||||
} |
||||
|
||||
// 新增知识库
|
||||
export const createLibrary = (data) => { |
||||
return request.post({ url: '/admin-api/crm/knowledge-lib/create', data }) |
||||
} |
||||
|
||||
// 修改知识库
|
||||
export const updateLibrary = (data) => { |
||||
return request.put({ url: '/admin-api/crm/knowledge-lib/update', data }) |
||||
} |
||||
|
||||
// 删除知识库
|
||||
export const deleteLibrary = (id) => { |
||||
return request.delete({ url: '/admin-api/crm/knowledge-lib/delete?id=' + id }) |
||||
} |
@ -0,0 +1,26 @@ |
||||
import request from '@/config/axios' |
||||
|
||||
// 查询资源列表
|
||||
export const getResourcePage = (params) => { |
||||
return request.get({ url: '/admin-api/crm/knowledge-lib-info/page', params }) |
||||
} |
||||
|
||||
// 查询资源详情
|
||||
export const getResource = (id) => { |
||||
return request.get({ url: '/admin-api/crm/knowledge-lib-info/get?id=' + id }) |
||||
} |
||||
|
||||
// 新增资源
|
||||
export const createResource = (data) => { |
||||
return request.post({ url: '/admin-api/crm/knowledge-lib-info/create', data }) |
||||
} |
||||
|
||||
// 修改资源
|
||||
export const updateResource = (data) => { |
||||
return request.put({ url: '/admin-api/crm/knowledge-lib-info/update', data }) |
||||
} |
||||
|
||||
// 删除资源
|
||||
export const deleteResource = (id) => { |
||||
return request.delete({ url: '/admin-api/crm/knowledge-lib-info/delete?id=' + id }) |
||||
} |
@ -1,317 +0,0 @@ |
||||
<template> |
||||
<el-table |
||||
:data="isBatch ? skuList : formData.skus" |
||||
border |
||||
class="tabNumWidth" |
||||
max-height="500" |
||||
size="small" |
||||
> |
||||
<el-table-column align="center" fixed="left" label="图片" min-width="100"> |
||||
<template #default="{ row }"> |
||||
<UploadImg v-model="row.picUrl" height="80px" width="100%" /> |
||||
</template> |
||||
</el-table-column> |
||||
<template v-if="formData.specType && !isBatch"> |
||||
<!-- 根据商品属性动态添加 --> |
||||
<el-table-column |
||||
v-for="(item, index) in tableHeaders" |
||||
:key="index" |
||||
:label="item.label" |
||||
align="center" |
||||
min-width="120" |
||||
> |
||||
<template #default="{ row }"> |
||||
<!-- TODO puhui999:展示成蓝色,有点区分度哈 --> |
||||
{{ row.properties[index]?.valueName }} |
||||
</template> |
||||
</el-table-column> |
||||
</template> |
||||
<el-table-column align="center" label="商品条码" min-width="168"> |
||||
<template #default="{ row }"> |
||||
<el-input v-model="row.barCode" class="w-100%" /> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column align="center" label="销售价(元)" min-width="168"> |
||||
<template #default="{ row }"> |
||||
<el-input-number v-model="row.price" :min="0" :precision="2" :step="0.1" class="w-100%" /> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column align="center" label="市场价(元)" min-width="168"> |
||||
<template #default="{ row }"> |
||||
<el-input-number |
||||
v-model="row.marketPrice" |
||||
:min="0" |
||||
:precision="2" |
||||
:step="0.1" |
||||
class="w-100%" |
||||
/> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column align="center" label="成本价(元)" min-width="168"> |
||||
<template #default="{ row }"> |
||||
<el-input-number |
||||
v-model="row.costPrice" |
||||
:min="0" |
||||
:precision="2" |
||||
:step="0.1" |
||||
class="w-100%" |
||||
/> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column align="center" label="库存" min-width="168"> |
||||
<template #default="{ row }"> |
||||
<el-input-number v-model="row.stock" :min="0" class="w-100%" /> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column align="center" label="重量(kg)" min-width="168"> |
||||
<template #default="{ row }"> |
||||
<el-input-number v-model="row.weight" :min="0" :precision="2" :step="0.1" class="w-100%" /> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column align="center" label="体积(m^3)" min-width="168"> |
||||
<template #default="{ row }"> |
||||
<el-input-number v-model="row.volume" :min="0" :precision="2" :step="0.1" class="w-100%" /> |
||||
</template> |
||||
</el-table-column> |
||||
<template v-if="formData.subCommissionType"> |
||||
<el-table-column align="center" label="一级返佣(元)" min-width="168"> |
||||
<template #default="{ row }"> |
||||
<el-input-number |
||||
v-model="row.subCommissionFirstPrice" |
||||
:min="0" |
||||
:precision="2" |
||||
:step="0.1" |
||||
class="w-100%" |
||||
/> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column align="center" label="二级返佣(元)" min-width="168"> |
||||
<template #default="{ row }"> |
||||
<el-input-number |
||||
v-model="row.subCommissionSecondPrice" |
||||
:min="0" |
||||
:precision="2" |
||||
:step="0.1" |
||||
class="w-100%" |
||||
/> |
||||
</template> |
||||
</el-table-column> |
||||
</template> |
||||
<el-table-column v-if="formData.specType" align="center" fixed="right" label="操作" width="80"> |
||||
<template #default="{ row }"> |
||||
<el-button v-if="isBatch" link size="small" type="primary" @click="batchAdd"> |
||||
批量添加 |
||||
</el-button> |
||||
<el-button v-else link size="small" type="primary" @click="deleteSku(row)">删除</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
</template> |
||||
<script lang="ts" name="SkuList" setup> |
||||
import { PropType } from 'vue' |
||||
import { copyValueToTarget } from '@/utils' |
||||
import { propTypes } from '@/utils/propTypes' |
||||
import { UploadImg } from '@/components/UploadFile' |
||||
import type { Property, SkuType, SpuType } from '@/api/mall/product/spu' |
||||
|
||||
const props = defineProps({ |
||||
propFormData: { |
||||
type: Object as PropType<SpuType>, |
||||
default: () => {} |
||||
}, |
||||
propertyList: { |
||||
type: Array, |
||||
default: () => [] |
||||
}, |
||||
isBatch: propTypes.bool.def(false) // 是否作为批量操作组件 |
||||
}) |
||||
const formData = ref<SpuType>() // 表单数据 |
||||
const skuList = ref<SkuType[]>([ |
||||
{ |
||||
price: 0, // 商品价格 |
||||
marketPrice: 0, // 市场价 |
||||
costPrice: 0, // 成本价 |
||||
barCode: '', // 商品条码 |
||||
picUrl: '', // 图片地址 |
||||
stock: 0, // 库存 |
||||
weight: 0, // 商品重量 |
||||
volume: 0, // 商品体积 |
||||
subCommissionFirstPrice: 0, // 一级分销的佣金 |
||||
subCommissionSecondPrice: 0 // 二级分销的佣金 |
||||
} |
||||
]) // 批量添加时的临时数据 |
||||
// TODO @puhui999:保存时,每个商品规格的表单要校验下。例如说,销售金额最低是 0.01 这种。 |
||||
|
||||
/** 批量添加 */ |
||||
const batchAdd = () => { |
||||
formData.value.skus.forEach((item) => { |
||||
copyValueToTarget(item, skuList.value[0]) |
||||
}) |
||||
} |
||||
|
||||
/** 删除 sku */ |
||||
const deleteSku = (row) => { |
||||
const index = formData.value.skus.findIndex( |
||||
// 直接把列表转成字符串比较 |
||||
(sku) => JSON.stringify(sku.properties) === JSON.stringify(row.properties) |
||||
) |
||||
formData.value.skus.splice(index, 1) |
||||
} |
||||
const tableHeaders = ref<{ prop: string; label: string }[]>([]) // 多属性表头 |
||||
|
||||
/** |
||||
* 将传进来的值赋值给 skuList |
||||
*/ |
||||
watch( |
||||
() => props.propFormData, |
||||
(data) => { |
||||
if (!data) return |
||||
formData.value = data |
||||
}, |
||||
{ |
||||
deep: true, |
||||
immediate: true |
||||
} |
||||
) |
||||
|
||||
/** 生成表数据 */ |
||||
const generateTableData = (propertyList: any[]) => { |
||||
// 构建数据结构 |
||||
const propertyValues = propertyList.map((item) => |
||||
item.values.map((v) => ({ |
||||
propertyId: item.id, |
||||
propertyName: item.name, |
||||
valueId: v.id, |
||||
valueName: v.name |
||||
})) |
||||
) |
||||
// TODO @puhui:是不是 buildSkuList,这样容易理解一点哈。item 改成 sku |
||||
const buildList = build(propertyValues) |
||||
// 如果回显的 sku 属性和添加的属性不一致则重置 skus 列表 |
||||
if (!validateData(propertyList)) { |
||||
// 如果不一致则重置表数据,默认添加新的属性重新生成 sku 列表 |
||||
formData.value!.skus = [] |
||||
} |
||||
for (const item of buildList) { |
||||
const row = { |
||||
properties: Array.isArray(item) ? item : [item], // 如果只有一个属性的话返回的是一个 property 对象 |
||||
price: 0, |
||||
marketPrice: 0, |
||||
costPrice: 0, |
||||
barCode: '', |
||||
picUrl: '', |
||||
stock: 0, |
||||
weight: 0, |
||||
volume: 0, |
||||
subCommissionFirstPrice: 0, |
||||
subCommissionSecondPrice: 0 |
||||
} |
||||
// 如果存在属性相同的 sku 则不做处理 |
||||
const index = formData.value!.skus.findIndex( |
||||
(sku) => JSON.stringify(sku.properties) === JSON.stringify(row.properties) |
||||
) |
||||
if (index !== -1) { |
||||
continue |
||||
} |
||||
formData.value.skus.push(row) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 生成 skus 前置校验 |
||||
*/ |
||||
const validateData = (propertyList: any[]) => { |
||||
const skuPropertyIds = [] |
||||
formData.value.skus.forEach((sku) => |
||||
sku.properties |
||||
?.map((property) => property.propertyId) |
||||
.forEach((propertyId) => { |
||||
if (skuPropertyIds.indexOf(propertyId) === -1) { |
||||
skuPropertyIds.push(propertyId) |
||||
} |
||||
}) |
||||
) |
||||
const propertyIds = propertyList.map((item) => item.id) |
||||
return skuPropertyIds.length === propertyIds.length |
||||
} |
||||
|
||||
/** 构建所有排列组合 */ |
||||
const build = (propertyValuesList: Property[][]) => { |
||||
if (propertyValuesList.length === 0) { |
||||
return [] |
||||
} else if (propertyValuesList.length === 1) { |
||||
return propertyValuesList[0] |
||||
} else { |
||||
const result: Property[][] = [] |
||||
const rest = build(propertyValuesList.slice(1)) |
||||
for (let i = 0; i < propertyValuesList[0].length; i++) { |
||||
for (let j = 0; j < rest.length; j++) { |
||||
// 第一次不是数组结构,后面的都是数组结构 |
||||
if (Array.isArray(rest[j])) { |
||||
result.push([propertyValuesList[0][i], ...rest[j]]) |
||||
} else { |
||||
result.push([propertyValuesList[0][i], rest[j]]) |
||||
} |
||||
} |
||||
} |
||||
return result |
||||
} |
||||
} |
||||
|
||||
/** 监听属性列表,生成相关参数和表头 */ |
||||
watch( |
||||
() => props.propertyList, |
||||
(propertyList) => { |
||||
// 如果不是多规格则结束 |
||||
if (!formData.value.specType) { |
||||
return |
||||
} |
||||
// 如果当前组件作为批量添加数据使用,则重置表数据 |
||||
if (props.isBatch) { |
||||
skuList.value = [ |
||||
{ |
||||
price: 0, |
||||
marketPrice: 0, |
||||
costPrice: 0, |
||||
barCode: '', |
||||
picUrl: '', |
||||
stock: 0, |
||||
weight: 0, |
||||
volume: 0, |
||||
subCommissionFirstPrice: 0, |
||||
subCommissionSecondPrice: 0 |
||||
} |
||||
] |
||||
} |
||||
|
||||
// 判断代理对象是否为空 |
||||
if (JSON.stringify(propertyList) === '[]') { |
||||
return |
||||
} |
||||
// 重置表头 |
||||
tableHeaders.value = [] |
||||
// 生成表头 |
||||
propertyList.forEach((item, index) => { |
||||
// name加属性项index区分属性值 |
||||
tableHeaders.value.push({ prop: `name${index}`, label: item.name }) |
||||
}) |
||||
|
||||
// 如果回显的 sku 属性和添加的属性一致则不处理 |
||||
if (validateData(propertyList)) { |
||||
return |
||||
} |
||||
// 添加新属性没有属性值也不做处理 |
||||
if (propertyList.some((item) => item.values.length === 0)) { |
||||
return |
||||
} |
||||
// 生成 table 数据,即 sku 列表 |
||||
generateTableData(propertyList) |
||||
}, |
||||
{ |
||||
deep: true, |
||||
immediate: true |
||||
} |
||||
) |
||||
// 暴露出生成 sku 方法,给添加属性成功时调用 |
||||
defineExpose({ generateTableData }) |
||||
</script> |
Loading…
Reference in new issue