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