新增套餐基本信息编辑功能,包括更新套餐名称和备注,支持客户筛选和绑定客户显示。

This commit is contained in:
wuweihua
2026-11-02 11:52:08 +08:00
parent 1b1b934d87
commit e93f0c0233
9 changed files with 170 additions and 27 deletions
@@ -102,6 +102,16 @@ public class PriceSetController extends BaseController
return toAjax(priceSetService.updatePrcPriceSet(set));
}
/** Update package name and note only. */
@PreAuthorize("@ss.hasPermi('price:set:edit')")
@Log(title = "价格套餐基本信息", businessType = BusinessType.UPDATE)
@PutMapping("/basic")
public AjaxResult editBasic(@RequestBody PrcPriceSet set)
{
set.setUpdateBy(getUsername());
return toAjax(priceSetService.updateBasicInfo(set));
}
@PreAuthorize("@ss.hasPermi('price:set:remove')")
@Log(title = "价格套餐", businessType = BusinessType.DELETE)
@DeleteMapping("/{priceSetIds}")
@@ -34,8 +34,12 @@ public class PrcPriceSet extends BaseEntity
private Integer productCount;
private Integer customerCount;
/** List display: bound customer code/name summary (not a DB column). */
private String boundCustomers;
private Boolean expired;
private String keyword;
/** Query only: filter packages by bound customer id. */
private Long customerId;
private String submitFlag;
/** current version on create/edit save */
private PrcPriceSetVersion version;
@@ -21,6 +21,9 @@ public interface PrcPriceSetMapper
public int updatePrcPriceSet(PrcPriceSet set);
/** Update name / note only (does not touch set_type / discount / status). */
public int updateBasicInfo(PrcPriceSet set);
public int updatePrcPriceSetStatus(PrcPriceSet set);
public int deletePrcPriceSetByIds(Long[] priceSetIds);
@@ -26,6 +26,9 @@ public interface IPrcPriceSetService
public int updatePrcPriceSet(PrcPriceSet set);
/** Update package name and note only; allowed for effect / draft / stopped. */
public int updateBasicInfo(PrcPriceSet set);
public int deletePrcPriceSetByIds(Long[] priceSetIds);
public int submit(Long priceSetId, String updateBy);
@@ -258,6 +258,30 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
return setMapper.updatePrcPriceSet(set);
}
@Override
public int updateBasicInfo(PrcPriceSet set)
{
if (set == null || set.getPriceSetId() == null)
{
throw new ServiceException(MessageUtils.message("price.set.notExists"));
}
PrcPriceSet db = requireSet(set.getPriceSetId());
if (STATUS_AUDIT.equals(db.getStatus()))
{
throw new ServiceException(MessageUtils.message("price.set.edit.audit"));
}
if (StringUtils.isEmpty(set.getPriceSetName()))
{
throw new ServiceException(MessageUtils.message("price.set.name.empty"));
}
set.setPriceSetName(set.getPriceSetName().trim());
if (setMapper.countByName(set) > 0)
{
throw new ServiceException(MessageUtils.message("price.set.name.exists"));
}
return setMapper.updateBasicInfo(set);
}
@Override
@Transactional
public int deletePrcPriceSetByIds(Long[] priceSetIds)
@@ -21,6 +21,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="updateTime" column="update_time" />
<result property="productCount" column="product_count" />
<result property="customerCount" column="customer_count" />
<result property="boundCustomers" column="bound_customers" />
</resultMap>
<sql id="selectPrcPriceSetVo">
@@ -33,7 +34,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
inner join prc_price_set_version v on v.psv_id = p.psv_id
where v.price_set_id = s.price_set_id
and ifnull(p.is_del, '0') = '0') as product_count,
(select count(1) from prc_customer_price_set c where c.price_set_id = s.price_set_id) as customer_count
(select count(1) from prc_customer_price_set c where c.price_set_id = s.price_set_id) as customer_count,
(select group_concat(
concat(ifnull(c.customer_code, ''),
case when ifnull(c.customer_name, '') = '' then '' else concat(' ', c.customer_name) end)
order by c.bind_priority asc, c.customer_priceset_id asc
separator '、')
from prc_customer_price_set c
where c.price_set_id = s.price_set_id) as bound_customers
from prc_price_set s
</sql>
@@ -47,7 +55,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
s.set_type, s.default_discount, s.default_type, s.calculate_sign,
s.status, s.tms_id,
s.created_by, s.create_time, s.updated_by, s.update_time,
null as product_count, null as customer_count
null as product_count, null as customer_count, null as bound_customers
from prc_price_set s
where s.price_set_id = #{priceSetId}
</select>
@@ -71,14 +79,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND (
s.price_set_code like concat('%', #{keyword}, '%')
OR s.price_set_name like concat('%', #{keyword}, '%')
OR exists (
select 1 from prc_customer_price_set c
where c.price_set_id = s.price_set_id
and (
c.customer_name like concat('%', #{keyword}, '%')
or concat(c.customer_id, '') like concat('%', #{keyword}, '%')
)
)
)
</if>
<if test="customerId != null">
AND exists (
select 1 from prc_customer_price_set c
where c.price_set_id = s.price_set_id
and c.customer_id = #{customerId}
)
</if>
<!-- Data scope: customer sales / creator / explicit viewer bind.
@@ -167,6 +174,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where price_set_id = #{priceSetId}
</update>
<update id="updateBasicInfo" parameterType="PrcPriceSet">
update prc_price_set
<set>
<if test="priceSetName != null and priceSetName != ''">price_set_name = #{priceSetName},</if>
price_set_note = #{priceSetNote},
<if test="updateBy != null and updateBy != ''">updated_by = #{updateBy},</if>
update_time = sysdate()
</set>
where price_set_id = #{priceSetId}
</update>
<update id="updatePrcPriceSetStatus" parameterType="PrcPriceSet">
update prc_price_set
<set>
+9
View File
@@ -86,6 +86,15 @@ export function updatePriceSet(data) {
})
}
/** Update package name and note only. */
export function updatePriceSetBasic(data) {
return request({
url: '/price/set/basic',
method: 'put',
data: data
})
}
export function delPriceSet(priceSetIds) {
return request({
url: '/price/set/' + priceSetIds,
@@ -4,11 +4,10 @@
<el-form ref="formRef" :model="basic" :rules="rules" label-width="120px" class="max-form">
<el-form-item label="套餐名称" prop="priceSetName">
<el-input v-model="basic.priceSetName" maxlength="50" placeholder="如:金牌电商专属套餐" />
<div class="form-hint">显示给客户的套餐对外名称</div>
</el-form-item>
<el-form-item label="说明备注" prop="priceSetNote">
<el-input v-model="basic.priceSetNote" type="textarea" :rows="3" maxlength="200" placeholder="套餐业务说明,显示给客户与运营" />
<el-input v-model="basic.priceSetNote" type="textarea" :rows="3" maxlength="200" placeholder="请输入" />
</el-form-item>
</el-form>
</el-card>
+88 -15
View File
@@ -19,6 +19,17 @@
</el-col>
</template>
<template #search-customerId="{ model }">
<customer-select
v-model="model.customerId"
option-select
remote-search
:page-size="20"
placeholder="客户名称 / 代码"
style="width: 240px"
/>
</template>
<template #col-setType="{ row }">
<el-tag :type="row.setType === 'FIXED' ? 'warning' : 'primary'" size="small" effect="plain">
{{ row.setType === 'FIXED' ? 'FIXED 固定价' : 'DISCOUNT 折扣' }}
@@ -29,6 +40,12 @@
<el-tag :type="statusTag(row)" size="small">{{ statusLabel(row) }}</el-tag>
</template>
<template #col-boundCustomers="{ row }">
<span v-if="row.boundCustomers">{{ row.boundCustomers }}</span>
<span v-else class="text-muted">-</span>
<el-tag v-if="row.customerCount > 0" size="small" type="info" effect="plain" class="cust-count">{{ row.customerCount }}</el-tag>
</template>
<template #col-activeDetail="{ row }">
<el-button
link
@@ -41,6 +58,7 @@
<template #col-action="{ row }">
<el-button link type="primary" @click="handleDetail(row)" v-hasPermi="['price:set:query']">详情</el-button>
<el-button link type="primary" @click="openBasicEdit(row)" v-hasPermi="['price:set:edit']">修改</el-button>
<el-button
v-if="row.status === 'E'"
link
@@ -58,6 +76,24 @@
</template>
</basic-table>
<el-dialog v-model="basicDialog.visible" :title="basicDialogTitle" width="520px" append-to-body destroy-on-close>
<el-form ref="basicFormRef" :model="basicForm" :rules="basicRules" label-width="96px">
<el-form-item label="套餐编码">
<el-input :model-value="basicForm.priceSetCode" disabled />
</el-form-item>
<el-form-item label="套餐名称" prop="priceSetName">
<el-input v-model="basicForm.priceSetName" maxlength="50" show-word-limit placeholder="请输入套餐名称" />
</el-form-item>
<el-form-item label="说明备注" prop="priceSetNote">
<el-input v-model="basicForm.priceSetNote" type="textarea" :rows="3" maxlength="200" show-word-limit placeholder="可选" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="basicDialog.visible = false">取消</el-button>
<el-button type="primary" :loading="basicDialog.saving" @click="submitBasicEdit">确定</el-button>
</template>
</el-dialog>
<set-version-detail-drawer
v-model="drawerVisible"
:version="activeVersion"
@@ -69,9 +105,10 @@
<script setup name="PriceSet">
import {
listPriceSet, disablePriceSet, enablePriceSet, copyPriceSet, getPriceSet
listPriceSet, disablePriceSet, enablePriceSet, copyPriceSet, getPriceSet, updatePriceSetBasic
} from '@/api/price/set'
import SetVersionDetailDrawer from './components/detail/SetVersionDetailDrawer.vue'
import CustomerSelect from '@/components/CustomerSelect/index.vue'
import { setStatusLabel, setStatusTagType } from './utils/priceSet'
const { proxy } = getCurrentInstance()
@@ -79,17 +116,6 @@ const tableRef = ref()
const isFirstActivate = ref(true)
const searchColumns = [
{
label: '类型',
prop: 'setType',
component: 'select',
options: [
{ label: 'FIXED 固定价', value: 'FIXED' },
{ label: 'DISCOUNT 折扣', value: 'DISCOUNT' }
],
placeholder: '全部类型',
width: '160px'
},
{
label: '状态',
prop: 'status',
@@ -102,17 +128,19 @@ const searchColumns = [
placeholder: '全部状态',
width: '140px'
},
{ label: '关键字', prop: 'keyword', component: 'input', placeholder: '套餐ID / 名称 / 客户', width: '240px' }
{ label: '关键字', prop: 'keyword', component: 'input', placeholder: '套餐编码 / 名称', width: '200px' },
{ label: '客户', prop: 'customerId', placeholder: '客户名称 / 代码', width: '240px' }
]
const columns = [
{ label: '套餐编码', prop: 'priceSetCode', width: 110 },
{ label: '套餐名称', prop: 'priceSetName', minWidth: 160 },
{ label: '类型', prop: 'setType', width: 140 },
{ label: '说明', prop: 'priceSetNote', minWidth: 160 },
{ label: '绑定客户', prop: 'boundCustomers', minWidth: 220 },
{ label: '说明', prop: 'priceSetNote', minWidth: 140 },
{ label: '状态', prop: 'status', width: 90 },
{ label: '生效明细', prop: 'activeDetail', width: 100 },
{ label: '操作', prop: 'action', width: 160, showInToolbar: false }
{ label: '操作', prop: 'action', width: 200, showInToolbar: false }
]
function queryList(params) {
@@ -135,6 +163,49 @@ function handleDetail(row) {
proxy.$router.push({ path: '/customer/setDetail', query: { priceSetId: row.priceSetId } })
}
const basicDialog = reactive({ visible: false, saving: false })
const basicFormRef = ref()
const basicForm = reactive({
priceSetId: null,
priceSetCode: '',
priceSetName: '',
priceSetNote: ''
})
const basicRules = {
priceSetName: [{ required: true, message: '套餐名称不能为空', trigger: 'blur' }]
}
const basicDialogTitle = computed(() => '修改套餐基本信息')
function openBasicEdit(row) {
if (!row || row.priceSetId == null) return
basicForm.priceSetId = row.priceSetId
basicForm.priceSetCode = row.priceSetCode || ''
basicForm.priceSetName = row.priceSetName || ''
basicForm.priceSetNote = row.priceSetNote || ''
basicDialog.visible = true
nextTick(() => basicFormRef.value && basicFormRef.value.clearValidate())
}
function submitBasicEdit() {
basicFormRef.value.validate(valid => {
if (!valid) return
basicDialog.saving = true
updatePriceSetBasic({
priceSetId: basicForm.priceSetId,
priceSetName: basicForm.priceSetName,
priceSetNote: basicForm.priceSetNote
}).then(() => {
proxy.$modal.msgSuccess('保存成功')
basicDialog.visible = false
refresh()
}).finally(() => {
basicDialog.saving = false
})
})
}
/** 生效明细:拉详情找生效版本(status=1)弹抽屉 */
const drawerVisible = ref(false)
const activeVersion = ref(null)
@@ -200,6 +271,8 @@ function handleCopy(row) {
</script>
<style scoped>
.text-muted { color: #909399; }
.cust-count { margin-left: 6px; vertical-align: middle; }
.hint-card {
margin-top: 16px;
}