|
|
@@ -1,7 +1,13 @@
|
|
|
<template>
|
|
|
<!-- 规格对话框表单 -->
|
|
|
- <el-dialog class="ba-operate-dialog" :close-on-click-modal="false" :destroy-on-close="true" v-model="dialogVisible"
|
|
|
- @close="handleClose" width="700px">
|
|
|
+ <el-dialog
|
|
|
+ class="ba-operate-dialog spec-dialog"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ :destroy-on-close="true"
|
|
|
+ v-model="dialogVisible"
|
|
|
+ @close="handleClose"
|
|
|
+ width="750px"
|
|
|
+ >
|
|
|
<template #header>
|
|
|
<div class="title" v-drag="['.ba-operate-dialog', '.el-dialog__header']" v-zoom="'.ba-operate-dialog'">
|
|
|
{{ dialogType === 'add' ? '添加规格' : '编辑规格' }}
|
|
|
@@ -9,81 +15,127 @@
|
|
|
</template>
|
|
|
<el-scrollbar v-loading="loading" class="ba-table-form-scrollbar">
|
|
|
<div class="ba-operate-form">
|
|
|
- <el-form ref="formRef" :model="formData" :rules="rules" label-width="120px" class="form-container">
|
|
|
+ <el-form
|
|
|
+ ref="formRef"
|
|
|
+ :model="formData"
|
|
|
+ :rules="rules"
|
|
|
+ label-width="110px"
|
|
|
+ class="form-container"
|
|
|
+ >
|
|
|
<el-form-item label="规格名称" prop="spec_name">
|
|
|
- <el-input v-model="formData.spec_name" placeholder="请输入规格名称" />
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item label="价格" prop="price">
|
|
|
- <el-input-number
|
|
|
- v-model.number="formData.price"
|
|
|
- :min="0"
|
|
|
- placeholder="价格"
|
|
|
- style="width: 100%"
|
|
|
+ <el-input
|
|
|
+ v-model="formData.spec_name"
|
|
|
+ placeholder="请输入规格名称"
|
|
|
+ clearable
|
|
|
+ maxlength="50"
|
|
|
+ show-word-limit
|
|
|
/>
|
|
|
- <span class="form-unit">元</span>
|
|
|
</el-form-item>
|
|
|
|
|
|
- <el-form-item label="库存" prop="stock">
|
|
|
- <el-input-number
|
|
|
- v-model.number="formData.stock"
|
|
|
- :min="0"
|
|
|
- placeholder="库存数量"
|
|
|
- style="width: 100%"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item label="套餐类型" prop="type">
|
|
|
- <el-select v-model="formData.type" placeholder="请选择套餐类型" style="width: 100%">
|
|
|
- <el-option
|
|
|
- v-for="opt in packageTypeOptions"
|
|
|
- :key="opt.value"
|
|
|
- :label="opt.label"
|
|
|
- :value="opt.value"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="价格" prop="price">
|
|
|
+ <div class="input-with-unit">
|
|
|
+ <el-input-number
|
|
|
+ v-model.number="formData.price"
|
|
|
+ :min="0"
|
|
|
+ :precision="2"
|
|
|
+ placeholder="请输入价格"
|
|
|
+ style="width: 100%"
|
|
|
+ controls-position="right"
|
|
|
+ />
|
|
|
+ <span class="form-unit">元</span>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="库存" prop="stock">
|
|
|
+ <div class="input-with-unit">
|
|
|
+ <el-input-number
|
|
|
+ v-model.number="formData.stock"
|
|
|
+ :min="0"
|
|
|
+ placeholder="请输入库存"
|
|
|
+ style="width: 100%"
|
|
|
+ controls-position="right"
|
|
|
+ />
|
|
|
+ <span class="form-unit">件</span>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
|
|
|
- <el-form-item label="卡类型" prop="card_type">
|
|
|
- <el-select
|
|
|
- v-model="formData.card_type"
|
|
|
- placeholder="请选择卡类型"
|
|
|
- style="width: 100%"
|
|
|
- @change="handleCardTypeChange"
|
|
|
- >
|
|
|
- <el-option
|
|
|
- v-for="opt in cardTypeOptions"
|
|
|
- :key="opt.value"
|
|
|
- :label="opt.label"
|
|
|
- :value="opt.value"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="套餐类型" prop="type">
|
|
|
+ <el-select
|
|
|
+ v-model="formData.type"
|
|
|
+ placeholder="请选择套餐类型"
|
|
|
+ style="width: 100%"
|
|
|
+ clearable
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="opt in packageTypeOptions"
|
|
|
+ :key="opt.value"
|
|
|
+ :label="opt.label"
|
|
|
+ :value="opt.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="卡类型" prop="card_type">
|
|
|
+ <el-select
|
|
|
+ v-model="formData.card_type"
|
|
|
+ placeholder="请选择卡类型"
|
|
|
+ style="width: 100%"
|
|
|
+ @change="handleCardTypeChange"
|
|
|
+ clearable
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="opt in cardTypeOptions"
|
|
|
+ :key="opt.value"
|
|
|
+ :label="opt.label"
|
|
|
+ :value="opt.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
|
|
|
<el-form-item
|
|
|
+ v-if="formData.card_type === '1'"
|
|
|
label="次卡次数"
|
|
|
prop="unit_value"
|
|
|
- v-if="formData.card_type === '1'"
|
|
|
>
|
|
|
- <el-input-number
|
|
|
- v-model.number="formData.unit_value"
|
|
|
- :min="0"
|
|
|
- placeholder="请输入次卡次数"
|
|
|
- style="width: 100%"
|
|
|
- />
|
|
|
+ <div class="input-with-unit">
|
|
|
+ <el-input-number
|
|
|
+ v-model.number="formData.unit_value"
|
|
|
+ :min="1"
|
|
|
+ placeholder="请输入次卡次数"
|
|
|
+ style="width: 100%"
|
|
|
+ controls-position="right"
|
|
|
+ />
|
|
|
+ <span class="form-unit">次</span>
|
|
|
+ </div>
|
|
|
+ <div class="form-tip">当选择次卡时必填</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item
|
|
|
+ v-if="formData.card_type === '2'"
|
|
|
label="积分数"
|
|
|
prop="points_value"
|
|
|
- v-if="formData.card_type === '2'"
|
|
|
>
|
|
|
- <el-input-number
|
|
|
- v-model.number="formData.points_value"
|
|
|
- :min="0"
|
|
|
- placeholder="请输入积分数"
|
|
|
- style="width: 100%"
|
|
|
- />
|
|
|
+ <div class="input-with-unit">
|
|
|
+ <el-input-number
|
|
|
+ v-model.number="formData.points_value"
|
|
|
+ :min="1"
|
|
|
+ placeholder="请输入积分数"
|
|
|
+ style="width: 100%"
|
|
|
+ controls-position="right"
|
|
|
+ />
|
|
|
+ <span class="form-unit">分</span>
|
|
|
+ </div>
|
|
|
+ <div class="form-tip">当选择按积分时必填</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="说明描述" prop="description">
|
|
|
@@ -92,6 +144,8 @@
|
|
|
type="textarea"
|
|
|
:rows="4"
|
|
|
placeholder="请输入说明描述"
|
|
|
+ maxlength="500"
|
|
|
+ show-word-limit
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
@@ -99,9 +153,10 @@
|
|
|
</el-scrollbar>
|
|
|
<template #footer>
|
|
|
<div class="dialog-footer">
|
|
|
- <el-button @click="handleClose" size="large" class="cancel-btn">{{ t('Cancel') }}</el-button>
|
|
|
- <el-button @click="onSubmit()" type="primary" size="large" :loading="loading"
|
|
|
- class="submit-btn">确定</el-button>
|
|
|
+ <el-button @click="handleClose" size="default">{{ t('Cancel') }}</el-button>
|
|
|
+ <el-button @click="onSubmit()" type="primary" size="default" :loading="loading">
|
|
|
+ 确定
|
|
|
+ </el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
@@ -218,14 +273,27 @@ const editDialog = (pkgId: number, specData: any) => {
|
|
|
// 清理校验状态
|
|
|
formRef.value?.clearValidate()
|
|
|
|
|
|
- // 回填数据
|
|
|
+ // 辅助函数:安全地将值转换为数字
|
|
|
+ const toNumber = (value: any): number | undefined => {
|
|
|
+ if (value == null || value === '') return undefined
|
|
|
+ const num = Number(value)
|
|
|
+ return isNaN(num) ? undefined : num
|
|
|
+ }
|
|
|
+
|
|
|
+ // 回填数据,确保数字类型正确转换
|
|
|
formData.spec_name = specData.spec_name || specData.specName || ''
|
|
|
- formData.price = specData.price
|
|
|
- formData.stock = specData.stock
|
|
|
+ // 价格:转换为数字,如果为空或无效则设为 undefined
|
|
|
+ formData.price = toNumber(specData.price)
|
|
|
+ // 库存:转换为数字,如果为空或无效则设为 undefined
|
|
|
+ formData.stock = toNumber(specData.stock)
|
|
|
formData.type = String(specData.type || specData.packageType || '')
|
|
|
formData.card_type = String(specData.card_type || specData.chargeType || '')
|
|
|
- formData.unit_value = specData.unit_value || (specData.card_type === '1' ? specData.quantity : undefined)
|
|
|
- formData.points_value = specData.points_value || (specData.card_type === '2' ? specData.quantity : undefined)
|
|
|
+ // 次卡次数:转换为数字,如果为空或无效则设为 undefined
|
|
|
+ formData.unit_value = toNumber(specData.unit_value) ||
|
|
|
+ (specData.card_type === '1' ? toNumber(specData.quantity) : undefined)
|
|
|
+ // 积分数:转换为数字,如果为空或无效则设为 undefined
|
|
|
+ formData.points_value = toNumber(specData.points_value) ||
|
|
|
+ (specData.card_type === '2' ? toNumber(specData.quantity) : undefined)
|
|
|
formData.description = specData.description || specData.remark || ''
|
|
|
}
|
|
|
|
|
|
@@ -264,9 +332,11 @@ const onSubmit = async () => {
|
|
|
// 构建提交数据(按照用户要求的字段)
|
|
|
const submitData: any = {
|
|
|
id: currentSpecId.value || '',
|
|
|
+ package_id: packageId.value,
|
|
|
spec_name: formData.spec_name,
|
|
|
- price: formData.price,
|
|
|
- stock: formData.stock,
|
|
|
+ // 确保数字类型正确
|
|
|
+ price: formData.price != null ? Number(formData.price) : undefined,
|
|
|
+ stock: formData.stock != null ? Number(formData.stock) : undefined,
|
|
|
type: formData.type,
|
|
|
card_type: formData.card_type,
|
|
|
description: formData.description,
|
|
|
@@ -274,12 +344,12 @@ const onSubmit = async () => {
|
|
|
|
|
|
// 根据卡类型添加对应的值
|
|
|
// 当选择次卡时必填 unit_value,选择其他天数的卡可以不传
|
|
|
- if (formData.card_type === '1' && formData.unit_value !== undefined) {
|
|
|
- submitData.unit_value = formData.unit_value
|
|
|
+ if (formData.card_type === '1' && formData.unit_value !== undefined && formData.unit_value != null) {
|
|
|
+ submitData.unit_value = Number(formData.unit_value)
|
|
|
}
|
|
|
// 当选择积分时必填 points_value,选择其他天数的卡可以不传
|
|
|
- if (formData.card_type === '2' && formData.points_value !== undefined) {
|
|
|
- submitData.points_value = formData.points_value
|
|
|
+ if (formData.card_type === '2' && formData.points_value !== undefined && formData.points_value != null) {
|
|
|
+ submitData.points_value = Number(formData.points_value)
|
|
|
}
|
|
|
|
|
|
// 调用接口
|
|
|
@@ -313,10 +383,128 @@ defineExpose({ openDialog, editDialog })
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
+.spec-dialog {
|
|
|
+ :deep(.el-dialog__body) {
|
|
|
+ padding: 20px 28px;
|
|
|
+ max-height: 70vh;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-dialog__footer) {
|
|
|
+ padding: 16px 28px;
|
|
|
+ border-top: 1px solid #ebeef5;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.ba-table-form-scrollbar) {
|
|
|
+ max-height: calc(70vh - 100px);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
.form-container {
|
|
|
+ padding: 4px 0;
|
|
|
+
|
|
|
+ :deep(.el-form-item) {
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-form-item__label {
|
|
|
+ font-weight: 500;
|
|
|
+ color: #606266;
|
|
|
+ padding-right: 12px;
|
|
|
+ padding-bottom: 0;
|
|
|
+ line-height: 32px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-form-item__content {
|
|
|
+ line-height: 32px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-row) {
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-col {
|
|
|
+ .el-form-item {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .input-with-unit {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+
|
|
|
+ .el-input-number {
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
.form-unit {
|
|
|
- margin-left: 8px;
|
|
|
- color: #666;
|
|
|
+ color: #909399;
|
|
|
+ font-size: 14px;
|
|
|
+ white-space: nowrap;
|
|
|
+ min-width: 24px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-tip {
|
|
|
+ margin-top: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ line-height: 1.5;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-input__wrapper) {
|
|
|
+ border-radius: 4px;
|
|
|
+ transition: all 0.2s;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ box-shadow: 0 0 0 1px #c0c4cc inset;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-textarea__inner) {
|
|
|
+ border-radius: 4px;
|
|
|
+ transition: all 0.2s;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ border-color: #c0c4cc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-select) {
|
|
|
+ .el-select__wrapper {
|
|
|
+ border-radius: 4px;
|
|
|
+ transition: all 0.2s;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ box-shadow: 0 0 0 1px #c0c4cc inset;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-input-number) {
|
|
|
+ .el-input__wrapper {
|
|
|
+ border-radius: 4px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.dialog-footer {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ gap: 12px;
|
|
|
+
|
|
|
+ .el-button {
|
|
|
+ min-width: 88px;
|
|
|
+ border-radius: 4px;
|
|
|
}
|
|
|
}
|
|
|
</style>
|