fetch(modify):修改bug
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 5m45s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 5m45s
This commit is contained in:
@@ -5,7 +5,8 @@
|
||||
<ArtSearchBar
|
||||
v-model:filter="searchForm"
|
||||
:items="searchFormItems"
|
||||
:show-expand="false"
|
||||
:show-expand="true"
|
||||
label-width="85"
|
||||
@reset="handleReset"
|
||||
@search="handleSearch"
|
||||
></ArtSearchBar>
|
||||
@@ -40,70 +41,15 @@
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 修改成本价对话框 -->
|
||||
<ElDialog
|
||||
v-model="costPriceDialogVisible"
|
||||
title="修改成本价"
|
||||
width="500px"
|
||||
:close-on-click-modal="false"
|
||||
@closed="handleCostPriceDialogClosed"
|
||||
>
|
||||
<ElForm
|
||||
ref="costPriceFormRef"
|
||||
:model="costPriceForm"
|
||||
:rules="costPriceRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<ElFormItem label="套餐名称">
|
||||
<ElInput v-model="costPriceForm.package_name" disabled />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="店铺名称">
|
||||
<ElInput v-model="costPriceForm.shop_name" disabled />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="原成本价(元)">
|
||||
<ElInputNumber
|
||||
v-model="costPriceForm.old_cost_price"
|
||||
disabled
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="新成本价(元)" prop="cost_price">
|
||||
<ElInputNumber
|
||||
v-model="costPriceForm.cost_price"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
placeholder="请输入新成本价"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="costPriceDialogVisible = false">取消</ElButton>
|
||||
<ElButton
|
||||
type="primary"
|
||||
@click="handleCostPriceSubmit(costPriceFormRef)"
|
||||
:loading="costPriceSubmitLoading"
|
||||
>
|
||||
提交
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 新增/编辑对话框 -->
|
||||
<ElDialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogType === 'add' ? '新增分配' : '编辑分配'"
|
||||
width="600px"
|
||||
width="30%"
|
||||
:close-on-click-modal="false"
|
||||
@closed="handleDialogClosed"
|
||||
>
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="120px">
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="90px">
|
||||
<ElFormItem label="选择套餐" prop="package_id" v-if="dialogType === 'add'">
|
||||
<ElSelect
|
||||
v-model="form.package_id"
|
||||
@@ -125,23 +71,18 @@
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="选择店铺" prop="shop_id" v-if="dialogType === 'add'">
|
||||
<ElSelect
|
||||
<ElTreeSelect
|
||||
v-model="form.shop_id"
|
||||
:data="shopTreeData"
|
||||
:props="{ label: 'shop_name', value: 'id', children: 'children' }"
|
||||
placeholder="请选择店铺"
|
||||
style="width: 100%"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="searchShop"
|
||||
:loading="shopLoading"
|
||||
clearable
|
||||
>
|
||||
<ElOption
|
||||
v-for="shop in shopOptions"
|
||||
:key="shop.id"
|
||||
:label="shop.shop_name"
|
||||
:value="shop.id"
|
||||
/>
|
||||
</ElSelect>
|
||||
:loading="shopLoading"
|
||||
check-strictly
|
||||
:render-after-expand="false"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="成本价(元)" prop="cost_price">
|
||||
<ElInputNumber
|
||||
@@ -171,7 +112,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { ShopPackageAllocationService, PackageManageService, ShopService } from '@/api/modules'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ShopPackageAllocationService, PackageManageService, ShopService, ShopSeriesAllocationService } from '@/api/modules'
|
||||
import { ElMessage, ElMessageBox, ElSwitch } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type { ShopPackageAllocationResponse, PackageResponse, ShopResponse } from '@/types/api'
|
||||
@@ -180,6 +122,7 @@
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import { RoutesAlias } from '@/router/routesAlias'
|
||||
import {
|
||||
CommonStatus,
|
||||
getStatusText,
|
||||
@@ -190,26 +133,29 @@
|
||||
defineOptions({ name: 'PackageAssign' })
|
||||
|
||||
const { hasAuth } = useAuth()
|
||||
const router = useRouter()
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const costPriceDialogVisible = ref(false)
|
||||
const loading = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
const costPriceSubmitLoading = ref(false)
|
||||
const packageLoading = ref(false)
|
||||
const shopLoading = ref(false)
|
||||
const tableRef = ref()
|
||||
const formRef = ref<FormInstance>()
|
||||
const costPriceFormRef = ref<FormInstance>()
|
||||
const packageOptions = ref<PackageResponse[]>([])
|
||||
const shopOptions = ref<ShopResponse[]>([])
|
||||
const shopTreeData = ref<ShopResponse[]>([])
|
||||
const searchPackageOptions = ref<PackageResponse[]>([])
|
||||
const searchShopOptions = ref<ShopResponse[]>([])
|
||||
const searchAllocatorShopOptions = ref<ShopResponse[]>([])
|
||||
const searchSeriesAllocationOptions = ref<any[]>([])
|
||||
|
||||
// 搜索表单初始值
|
||||
const initialSearchState = {
|
||||
shop_id: undefined as number | undefined,
|
||||
package_id: undefined as number | undefined,
|
||||
series_allocation_id: undefined as number | undefined,
|
||||
allocator_shop_id: undefined as number | undefined,
|
||||
status: undefined as number | undefined
|
||||
}
|
||||
|
||||
@@ -219,7 +165,7 @@
|
||||
// 搜索表单配置
|
||||
const searchFormItems = computed<SearchFormItem[]>(() => [
|
||||
{
|
||||
label: '店铺',
|
||||
label: '被分配店铺',
|
||||
prop: 'shop_id',
|
||||
type: 'select',
|
||||
config: {
|
||||
@@ -254,6 +200,44 @@
|
||||
value: p.id
|
||||
}))
|
||||
},
|
||||
{
|
||||
label: '系列分配',
|
||||
prop: 'series_allocation_id',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
filterable: true,
|
||||
remote: true,
|
||||
remoteMethod: handleSearchSeriesAllocation,
|
||||
loading: loading.value,
|
||||
placeholder: '请选择或搜索系列分配'
|
||||
},
|
||||
options: () =>
|
||||
searchSeriesAllocationOptions.value.map((s) => ({
|
||||
label: `${s.series_name} - ${s.shop_name}`,
|
||||
value: s.id
|
||||
}))
|
||||
},
|
||||
{
|
||||
label: '分配者店铺',
|
||||
prop: 'allocator_shop_id',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
filterable: true,
|
||||
remote: true,
|
||||
remoteMethod: handleSearchAllocatorShop,
|
||||
loading: shopLoading.value,
|
||||
placeholder: '请选择或搜索分配者店铺'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '平台', value: 0 },
|
||||
...searchAllocatorShopOptions.value.map((s) => ({
|
||||
label: s.shop_name,
|
||||
value: s.id
|
||||
}))
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
@@ -278,10 +262,11 @@
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: 'ID', prop: 'id' },
|
||||
{ label: '套餐编码', prop: 'package_code' },
|
||||
{ label: '套餐名称', prop: 'package_name' },
|
||||
{ label: '店铺名称', prop: 'shop_name' },
|
||||
{ label: '系列名称', prop: 'series_name' },
|
||||
{ label: '被分配店铺', prop: 'shop_name' },
|
||||
{ label: '分配者', prop: 'allocator_shop_name' },
|
||||
{ label: '成本价', prop: 'cost_price' },
|
||||
{ label: '状态', prop: 'status' },
|
||||
{ label: '创建时间', prop: 'created_at' },
|
||||
@@ -320,45 +305,47 @@
|
||||
package_base_price: 0 // 存储选中套餐的成本价,用于验证
|
||||
})
|
||||
|
||||
// 成本价表单验证规则
|
||||
const costPriceRules = reactive<FormRules>({
|
||||
cost_price: [{ required: true, message: '请输入新成本价', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
// 成本价表单数据
|
||||
const costPriceForm = reactive<any>({
|
||||
id: 0,
|
||||
package_name: '',
|
||||
shop_name: '',
|
||||
old_cost_price: 0,
|
||||
cost_price: 0
|
||||
})
|
||||
|
||||
const allocationList = ref<ShopPackageAllocationResponse[]>([])
|
||||
const dialogType = ref('add')
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{
|
||||
prop: 'id',
|
||||
label: 'ID',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
prop: 'package_code',
|
||||
label: '套餐编码',
|
||||
minWidth: 150
|
||||
minWidth: 200,
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
{
|
||||
prop: 'package_name',
|
||||
label: '套餐名称',
|
||||
minWidth: 180
|
||||
},
|
||||
{
|
||||
prop: 'series_name',
|
||||
label: '系列名称',
|
||||
minWidth: 150
|
||||
},
|
||||
{
|
||||
prop: 'shop_name',
|
||||
label: '店铺名称',
|
||||
label: '被分配店铺',
|
||||
minWidth: 180
|
||||
},
|
||||
{
|
||||
prop: 'allocator_shop_name',
|
||||
label: '分配者',
|
||||
formatter: (row: ShopPackageAllocationResponse) => {
|
||||
// 如果是平台分配(allocator_shop_id为0),显示"平台"标签
|
||||
if (row.allocator_shop_id === 0) {
|
||||
return h(
|
||||
'span',
|
||||
{ style: 'color: #409eff; font-weight: bold' },
|
||||
row.allocator_shop_name || '平台'
|
||||
)
|
||||
}
|
||||
return row.allocator_shop_name
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'cost_price',
|
||||
label: '成本价',
|
||||
@@ -399,24 +386,22 @@
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 230,
|
||||
width: 200,
|
||||
fixed: 'right',
|
||||
formatter: (row: ShopPackageAllocationResponse) => {
|
||||
const buttons = []
|
||||
|
||||
if (hasAuth('package_assign:update_cost')) {
|
||||
buttons.push(
|
||||
h(ArtButtonTable, {
|
||||
text: '修改成本价',
|
||||
onClick: () => showCostPriceDialog(row)
|
||||
})
|
||||
)
|
||||
}
|
||||
buttons.push(
|
||||
h(ArtButtonTable, {
|
||||
type:"view",
|
||||
onClick: () => handleViewDetail(row)
|
||||
})
|
||||
)
|
||||
|
||||
if (hasAuth('package_assign:edit')) {
|
||||
buttons.push(
|
||||
h(ArtButtonTable, {
|
||||
type: 'edit',
|
||||
type:"edit",
|
||||
onClick: () => showDialog('edit', row)
|
||||
})
|
||||
)
|
||||
@@ -425,7 +410,7 @@
|
||||
if (hasAuth('package_assign:delete')) {
|
||||
buttons.push(
|
||||
h(ArtButtonTable, {
|
||||
type: 'delete',
|
||||
type:"delete",
|
||||
onClick: () => deleteAllocation(row)
|
||||
})
|
||||
)
|
||||
@@ -436,11 +421,40 @@
|
||||
}
|
||||
])
|
||||
|
||||
// 构建树形结构数据
|
||||
const buildTreeData = (items: ShopResponse[]) => {
|
||||
const map = new Map<number, ShopResponse & { children?: ShopResponse[] }>()
|
||||
const tree: ShopResponse[] = []
|
||||
|
||||
// 先将所有项放入 map
|
||||
items.forEach((item) => {
|
||||
map.set(item.id, { ...item, children: [] })
|
||||
})
|
||||
|
||||
// 构建树形结构
|
||||
items.forEach((item) => {
|
||||
const node = map.get(item.id)!
|
||||
if (item.parent_id && map.has(item.parent_id)) {
|
||||
// 有父节点,添加到父节点的 children 中
|
||||
const parent = map.get(item.parent_id)!
|
||||
if (!parent.children) parent.children = []
|
||||
parent.children.push(node)
|
||||
} else {
|
||||
// 没有父节点或父节点不存在,作为根节点
|
||||
tree.push(node)
|
||||
}
|
||||
})
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadPackageOptions()
|
||||
loadShopOptions()
|
||||
loadSearchPackageOptions()
|
||||
loadSearchShopOptions()
|
||||
loadSearchAllocatorShopOptions()
|
||||
loadSearchSeriesAllocationOptions()
|
||||
getTableData()
|
||||
})
|
||||
|
||||
@@ -466,20 +480,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 加载店铺选项(用于新增对话框,默认加载10条)
|
||||
const loadShopOptions = async (shopName?: string) => {
|
||||
// 加载店铺选项(用于新增对话框,加载所有店铺并构建树形结构)
|
||||
const loadShopOptions = async () => {
|
||||
shopLoading.value = true
|
||||
try {
|
||||
const params: any = {
|
||||
// 加载所有店铺,不分页
|
||||
const res = await ShopService.getShops({
|
||||
page: 1,
|
||||
page_size: 10
|
||||
}
|
||||
if (shopName) {
|
||||
params.shop_name = shopName
|
||||
}
|
||||
const res = await ShopService.getShops(params)
|
||||
page_size: 10000 // 使用较大的值获取所有店铺
|
||||
})
|
||||
if (res.code === 0) {
|
||||
shopOptions.value = res.data.items || []
|
||||
// 构建树形结构数据
|
||||
shopTreeData.value = buildTreeData(shopOptions.value)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载店铺选项失败:', error)
|
||||
@@ -524,15 +537,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索店铺(用于新增对话框)
|
||||
const searchShop = (query: string) => {
|
||||
if (query) {
|
||||
loadShopOptions(query)
|
||||
} else {
|
||||
loadShopOptions()
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索套餐(用于搜索栏)
|
||||
const handleSearchPackage = async (query: string) => {
|
||||
if (!query) {
|
||||
@@ -573,6 +577,73 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 加载搜索栏分配者店铺选项(默认加载10条)
|
||||
const loadSearchAllocatorShopOptions = async () => {
|
||||
try {
|
||||
const res = await ShopService.getShops({ page: 1, page_size: 10 })
|
||||
if (res.code === 0) {
|
||||
searchAllocatorShopOptions.value = res.data.items || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载搜索栏分配者店铺选项失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索分配者店铺(用于搜索栏)
|
||||
const handleSearchAllocatorShop = async (query: string) => {
|
||||
if (!query) {
|
||||
loadSearchAllocatorShopOptions()
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await ShopService.getShops({
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
shop_name: query
|
||||
})
|
||||
if (res.code === 0) {
|
||||
searchAllocatorShopOptions.value = res.data.items || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('搜索分配者店铺失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 加载搜索栏系列分配选项(默认加载10条)
|
||||
const loadSearchSeriesAllocationOptions = async () => {
|
||||
try {
|
||||
const res = await ShopSeriesAllocationService.getShopSeriesAllocations({
|
||||
page: 1,
|
||||
page_size: 10
|
||||
})
|
||||
if (res.code === 0) {
|
||||
searchSeriesAllocationOptions.value = res.data.items || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载搜索栏系列分配选项失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索系列分配(用于搜索栏)
|
||||
const handleSearchSeriesAllocation = async (query: string) => {
|
||||
if (!query) {
|
||||
loadSearchSeriesAllocationOptions()
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await ShopSeriesAllocationService.getShopSeriesAllocations({
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
series_name: query
|
||||
})
|
||||
if (res.code === 0) {
|
||||
searchSeriesAllocationOptions.value = res.data.items || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('搜索系列分配失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取分配列表
|
||||
const getTableData = async () => {
|
||||
loading.value = true
|
||||
@@ -582,6 +653,8 @@
|
||||
page_size: pagination.page_size,
|
||||
shop_id: searchForm.shop_id || undefined,
|
||||
package_id: searchForm.package_id || undefined,
|
||||
series_allocation_id: searchForm.series_allocation_id || undefined,
|
||||
allocator_shop_id: searchForm.allocator_shop_id || undefined,
|
||||
status: searchForm.status || undefined
|
||||
}
|
||||
const res = await ShopPackageAllocationService.getShopPackageAllocations(params)
|
||||
@@ -657,9 +730,9 @@
|
||||
// 从套餐选项中找到选中的套餐
|
||||
const selectedPackage = packageOptions.value.find((pkg) => pkg.id === packageId)
|
||||
if (selectedPackage) {
|
||||
// 将套餐的价格(分)转换为元显示
|
||||
form.cost_price = selectedPackage.price / 100
|
||||
form.package_base_price = selectedPackage.price // 保持原始值(分)用于验证
|
||||
// 将套餐的成本价(分)转换为元显示
|
||||
form.cost_price = selectedPackage.cost_price / 100
|
||||
form.package_base_price = selectedPackage.cost_price // 保持原始值(分)用于验证
|
||||
}
|
||||
} else {
|
||||
// 清空时重置成本价
|
||||
@@ -744,60 +817,6 @@
|
||||
})
|
||||
}
|
||||
|
||||
// 显示修改成本价对话框
|
||||
const showCostPriceDialog = (row: ShopPackageAllocationResponse) => {
|
||||
costPriceDialogVisible.value = true
|
||||
costPriceForm.id = row.id
|
||||
costPriceForm.package_name = row.package_name
|
||||
costPriceForm.shop_name = row.shop_name
|
||||
costPriceForm.old_cost_price = row.cost_price / 100 // 分转换为元显示
|
||||
costPriceForm.cost_price = row.cost_price / 100 // 分转换为元显示
|
||||
|
||||
// 重置表单验证状态
|
||||
nextTick(() => {
|
||||
costPriceFormRef.value?.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
// 处理成本价弹窗关闭事件
|
||||
const handleCostPriceDialogClosed = () => {
|
||||
// 清除表单验证状态
|
||||
costPriceFormRef.value?.clearValidate()
|
||||
// 重置表单数据
|
||||
costPriceForm.id = 0
|
||||
costPriceForm.package_name = ''
|
||||
costPriceForm.shop_name = ''
|
||||
costPriceForm.old_cost_price = 0
|
||||
costPriceForm.cost_price = 0
|
||||
}
|
||||
|
||||
// 提交成本价修改
|
||||
const handleCostPriceSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
costPriceSubmitLoading.value = true
|
||||
try {
|
||||
// 将元转换为分提交给后端
|
||||
const costPriceInCents = Math.round(costPriceForm.cost_price * 100)
|
||||
|
||||
await ShopPackageAllocationService.updateShopPackageAllocationCostPrice(
|
||||
costPriceForm.id,
|
||||
costPriceInCents
|
||||
)
|
||||
ElMessage.success('修改成本价成功')
|
||||
costPriceDialogVisible.value = false
|
||||
await getTableData()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
costPriceSubmitLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 状态切换
|
||||
const handleStatusChange = async (
|
||||
row: ShopPackageAllocationResponse,
|
||||
@@ -814,6 +833,11 @@
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 查看详情
|
||||
const handleViewDetail = (row: ShopPackageAllocationResponse) => {
|
||||
router.push(`${RoutesAlias.PackageAssignDetail}/${row.id}`)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
Reference in New Issue
Block a user