feat: enhance AWS and product management
This commit is contained in:
+130
-100
@@ -526,8 +526,9 @@
|
||||
ref="productFormRef"
|
||||
:model="productForm"
|
||||
:rules="productRules"
|
||||
label-position="top"
|
||||
class="product-form"
|
||||
label-position="right"
|
||||
label-width="116px"
|
||||
class="product-form goods-form"
|
||||
>
|
||||
<!-- 顶部:封面 + 基本信息 -->
|
||||
<div class="product-form-header">
|
||||
@@ -608,40 +609,26 @@
|
||||
<el-tabs v-model="productFormTab" class="product-form-tabs">
|
||||
<el-tab-pane label="价格与销售" name="sales">
|
||||
<div class="form-grid">
|
||||
<el-form-item prop="price">
|
||||
<template #label>
|
||||
<span>商品价格<span class="unit-suffix">(元)</span></span>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="productForm.price"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
placeholder="请输入价格"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<el-form-item label="商品价格" prop="price">
|
||||
<div class="unit-input-row">
|
||||
<el-input-number v-model="productForm.price" :min="0" :precision="2" :step="0.01" placeholder="请输入价格" controls-position="right" />
|
||||
<span class="unit-text">元</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="单个商品数量" prop="pay_num">
|
||||
<el-input-number
|
||||
v-model="productForm.pay_num"
|
||||
:min="1"
|
||||
placeholder="请输入数量"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div class="unit-input-row">
|
||||
<el-input-number v-model="productForm.pay_num" :min="1" placeholder="请输入数量" controls-position="right" />
|
||||
<span class="unit-text">件</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item prop="expire_time">
|
||||
<template #label>
|
||||
<span>有效期<span class="unit-suffix">(天,0 为永久)</span></span>
|
||||
<span class="form-label-with-help">有效期<el-tooltip content="0 表示永久有效" placement="top"><el-icon><QuestionFilled /></el-icon></el-tooltip></span>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="productForm.expire_time"
|
||||
:min="0"
|
||||
placeholder="请输入有效期"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div class="unit-input-row">
|
||||
<el-input-number v-model="productForm.expire_time" :min="0" placeholder="请输入有效期" controls-position="right" />
|
||||
<span class="unit-text">天</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="允许续费" prop="can_renew">
|
||||
<el-switch
|
||||
@@ -652,17 +639,30 @@
|
||||
</el-form-item>
|
||||
<el-form-item prop="renew_price" v-if="productForm.can_renew">
|
||||
<template #label>
|
||||
<span>续费价格<span class="unit-suffix">(元,0 沿用商品价格)</span></span>
|
||||
<span class="form-label-with-help">续费价格<el-tooltip content="0 表示沿用商品价格" placement="top"><el-icon><QuestionFilled /></el-icon></el-tooltip></span>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="productForm.renew_price"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
placeholder="续费基础价格"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div class="unit-input-row">
|
||||
<el-input-number v-model="productForm.renew_price" :min="0" :precision="2" :step="0.01" placeholder="续费基础价格" controls-position="right" />
|
||||
<span class="unit-text">元</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item prop="max_renew_duration" v-if="productForm.can_renew">
|
||||
<template #label>
|
||||
<span class="form-label-with-help">最长续费时长<el-tooltip content="限制用户单次续费可选择的最大月数,0 表示不限制" placement="top"><el-icon><QuestionFilled /></el-icon></el-tooltip></span>
|
||||
</template>
|
||||
<div class="unit-input-row">
|
||||
<el-input-number v-model="productForm.max_renew_duration" :min="0" :precision="0" :step="1" placeholder="0 表示不限" controls-position="right" />
|
||||
<span class="unit-text">月</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item prop="renew_before_days" v-if="productForm.can_renew">
|
||||
<template #label>
|
||||
<span class="form-label-with-help">提前续费天数<el-tooltip content="仅在商品到期前指定天数内开放续费,0 表示随时允许" placement="top"><el-icon><QuestionFilled /></el-icon></el-tooltip></span>
|
||||
</template>
|
||||
<div class="unit-input-row">
|
||||
<el-input-number v-model="productForm.renew_before_days" :min="0" :precision="0" :step="1" placeholder="0 表示不限" controls-position="right" />
|
||||
<span class="unit-text">天</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="购买类型" prop="arg_type">
|
||||
<el-select
|
||||
@@ -675,21 +675,21 @@
|
||||
<el-option label="仅自定义参数" value="customize" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="需要实名" prop="require_real_name">
|
||||
<el-form-item prop="require_real_name">
|
||||
<template #label><span class="form-label-with-help">需要实名<el-tooltip content="启用后,用户购买、续费或升级此商品前须完成实名认证" placement="top"><el-icon><QuestionFilled /></el-icon></el-tooltip></span></template>
|
||||
<el-switch
|
||||
v-model="productForm.require_real_name"
|
||||
active-text="需要"
|
||||
inactive-text="不需要"
|
||||
/>
|
||||
<div style="font-size:12px;color:#909399;margin-top:4px">启用后,用户购买/续费/升级此商品前须完成实名认证</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="远端商品" prop="remote_goods">
|
||||
<el-form-item prop="remote_goods">
|
||||
<template #label><span class="form-label-with-help">远端商品<el-tooltip content="AWS 商品需同时将标签设为 aws,保存后到 AWS 商品绑定页配置目录规则" placement="top"><el-icon><QuestionFilled /></el-icon></el-tooltip></span></template>
|
||||
<el-switch
|
||||
v-model="productForm.remote_goods"
|
||||
active-text="远端计价/履约"
|
||||
inactive-text="普通商品"
|
||||
/>
|
||||
<div style="font-size:12px;color:#909399;margin-top:4px">AWS 商品请同时将标签设为 aws,保存后到 AWS 商品绑定页配置目录规则</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
@@ -704,43 +704,33 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="库存数量" prop="inventory">
|
||||
<el-input-number
|
||||
v-model="productForm.inventory"
|
||||
:min="0"
|
||||
:disabled="!productForm.inventory_control"
|
||||
placeholder="请输入库存"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div class="unit-input-row">
|
||||
<el-input-number v-model="productForm.inventory" :min="0" :disabled="!productForm.inventory_control" placeholder="请输入库存" controls-position="right" />
|
||||
<span class="unit-text">件</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="售罄状态" prop="sold_out">
|
||||
<el-form-item prop="sold_out">
|
||||
<template #label><span class="form-label-with-help">售罄状态<el-tooltip content="开启后用户端将无法选购该商品" placement="top"><el-icon><QuestionFilled /></el-icon></el-tooltip></span></template>
|
||||
<el-switch
|
||||
v-model="productForm.sold_out"
|
||||
active-text="售罄"
|
||||
inactive-text="正常"
|
||||
active-color="#f56c6c"
|
||||
/>
|
||||
<div style="font-size:12px;color:#909399;margin-top:4px">开启后用户端将无法选购该商品</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="购买限制" prop="max_per_user">
|
||||
<el-input-number
|
||||
v-model="productForm.max_per_user"
|
||||
:min="0"
|
||||
placeholder="0 表示不限"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div style="font-size:12px;color:#909399;margin-top:4px">限制单用户最大购买数量,0 表示不限制</div>
|
||||
<el-form-item prop="max_per_user">
|
||||
<template #label><span class="form-label-with-help">购买限制<el-tooltip content="限制单用户最大购买数量,0 表示不限制" placement="top"><el-icon><QuestionFilled /></el-icon></el-tooltip></span></template>
|
||||
<div class="unit-input-row">
|
||||
<el-input-number v-model="productForm.max_per_user" :min="0" placeholder="0 表示不限" controls-position="right" />
|
||||
<span class="unit-text">件</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="首购最大时长" prop="max_first_purchase_duration">
|
||||
<el-input-number
|
||||
v-model="productForm.max_first_purchase_duration"
|
||||
:min="0"
|
||||
placeholder="0 表示不限"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div style="font-size:12px;color:#909399;margin-top:4px">限制用户首次购买的最大时长(单位:月),0 表示不限制</div>
|
||||
<el-form-item prop="max_first_purchase_duration">
|
||||
<template #label><span class="form-label-with-help">首购最大时长<el-tooltip content="限制用户首次购买的最大月数,0 表示不限制" placement="top"><el-icon><QuestionFilled /></el-icon></el-tooltip></span></template>
|
||||
<div class="unit-input-row">
|
||||
<el-input-number v-model="productForm.max_first_purchase_duration" :min="0" placeholder="0 表示不限" controls-position="right" />
|
||||
<span class="unit-text">月</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
@@ -754,44 +744,31 @@
|
||||
inactive-text="禁用"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="recommend_rebate">
|
||||
<template #label>
|
||||
<span>推荐返还<span class="unit-suffix">(%)</span></span>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="productForm.recommend_rebate"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:disabled="!productForm.recommend"
|
||||
placeholder="返还百分比"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<el-form-item label="推荐返还" prop="recommend_rebate">
|
||||
<div class="unit-input-row">
|
||||
<el-input-number v-model="productForm.recommend_rebate" :min="0" :max="100" :disabled="!productForm.recommend" placeholder="返还百分比" controls-position="right" />
|
||||
<span class="unit-text">%</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item prop="renew_recommend_rebate">
|
||||
<template #label>
|
||||
<span>续费推介返还<span class="unit-suffix">(%,0 沿用推荐返还)</span></span>
|
||||
<span class="form-label-with-help">续费推介返还<el-tooltip content="0 表示沿用推荐返还比例" placement="top"><el-icon><QuestionFilled /></el-icon></el-tooltip></span>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="productForm.renew_recommend_rebate"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:disabled="!productForm.recommend"
|
||||
placeholder="续费推介返还百分比"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div class="unit-input-row">
|
||||
<el-input-number v-model="productForm.renew_recommend_rebate" :min="0" :max="100" :disabled="!productForm.recommend" placeholder="续费推介返还百分比" controls-position="right" />
|
||||
<span class="unit-text">%</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="推荐词" prop="recommend_words">
|
||||
<el-input v-model="productForm.recommend_words" placeholder="推荐词(可选,如:热销、新品)" clearable style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="购买通知" prop="send_notice">
|
||||
<el-form-item prop="send_notice">
|
||||
<template #label><span class="form-label-with-help">购买通知<el-tooltip content="用户购买后是否向管理员发送通知" placement="top"><el-icon><QuestionFilled /></el-icon></el-tooltip></span></template>
|
||||
<el-switch
|
||||
v-model="productForm.send_notice"
|
||||
active-text="发送"
|
||||
inactive-text="不发送"
|
||||
/>
|
||||
<div style="font-size:12px;color:#909399;margin:4px">用户购买后是否发送通知给管理员</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
@@ -856,7 +833,7 @@
|
||||
import { ref, reactive, computed, onMounted, onActivated, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Refresh, Search, Folder, ArrowRight, Loading, Grid, List, Document, Picture, Delete, CollectionTag } from '@element-plus/icons-vue'
|
||||
import { Plus, Refresh, Search, Folder, ArrowRight, Loading, Grid, List, Document, Picture, Delete, CollectionTag, QuestionFilled } from '@element-plus/icons-vue'
|
||||
import {
|
||||
getProductGroupList,
|
||||
createProductGroup,
|
||||
@@ -973,6 +950,8 @@ const productForm = reactive({
|
||||
sold_out: false,
|
||||
max_per_user: 0,
|
||||
max_first_purchase_duration: 0,
|
||||
max_renew_duration: 0,
|
||||
renew_before_days: 0,
|
||||
send_notice: false,
|
||||
renew_price: 0,
|
||||
renew_recommend_rebate: 0,
|
||||
@@ -1634,6 +1613,8 @@ const handleAddProduct = () => {
|
||||
remote_goods: false,
|
||||
max_per_user: 0,
|
||||
max_first_purchase_duration: 0,
|
||||
max_renew_duration: 0,
|
||||
renew_before_days: 0,
|
||||
recommend_words: ''
|
||||
})
|
||||
|
||||
@@ -1673,6 +1654,8 @@ const handleEditProduct = (product, parentGroupId) => {
|
||||
sold_out: !!product.soldOut,
|
||||
max_per_user: product.maxPerUser ?? product.max_per_user ?? 0,
|
||||
max_first_purchase_duration: product.maxFirstPurchaseDuration ?? product.max_first_purchase_duration ?? 0,
|
||||
max_renew_duration: product.maxRenewDuration ?? product.max_renew_duration ?? 0,
|
||||
renew_before_days: product.renewBeforeDays ?? product.renew_before_days ?? 0,
|
||||
send_notice: !!product.sendNotice,
|
||||
renew_price: (product.renewPrice ?? product.renew_price ?? 0) / 100,
|
||||
renew_recommend_rebate: product.renewRecommendRebate ?? product.renew_recommend_rebate ?? 0,
|
||||
@@ -1707,6 +1690,8 @@ const submitProductForm = () => {
|
||||
sold_out: productForm.sold_out === true,
|
||||
max_per_user: Number(productForm.max_per_user) || 0,
|
||||
max_first_purchase_duration: Number(productForm.max_first_purchase_duration) || 0,
|
||||
max_renew_duration: Number(productForm.max_renew_duration) || 0,
|
||||
renew_before_days: Number(productForm.renew_before_days) || 0,
|
||||
send_notice: productForm.send_notice === true,
|
||||
renew_price: Number(productForm.renew_price) || 0,
|
||||
renew_recommend_rebate: Number(productForm.renew_recommend_rebate) || 0,
|
||||
@@ -2140,8 +2125,9 @@ watch(() => route.query.good_id, (newId) => {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.unit-input-row { display: flex; align-items: center; gap: 6px; width: 100%; }
|
||||
.unit-text { font-size: 13px; color: #606266; flex-shrink: 0; white-space: nowrap; }
|
||||
.unit-input-row { display: flex; align-items: center; gap: 8px; width: 100%; min-width: 0; }
|
||||
.unit-input-row :deep(.el-input-number) { width: 100%; min-width: 0; flex: 1; }
|
||||
.unit-text { width: 22px; color: #606266; font-size: 13px; flex-shrink: 0; white-space: nowrap; }
|
||||
|
||||
.recommend-user-selector {
|
||||
display: flex;
|
||||
@@ -2168,6 +2154,41 @@ watch(() => route.query.good_id, (newId) => {
|
||||
--section-gap: 20px;
|
||||
}
|
||||
|
||||
.goods-form :deep(.el-form-item__label) {
|
||||
display: inline-flex;
|
||||
height: 32px;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding-right: 12px;
|
||||
color: #303133;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.goods-form :deep(.el-form-item__content) {
|
||||
min-width: 0;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.form-label-with-help {
|
||||
display: inline-flex;
|
||||
min-width: 0;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.form-label-with-help .el-icon {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
cursor: help;
|
||||
transition: color .2s ease;
|
||||
}
|
||||
|
||||
.form-label-with-help .el-icon:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.product-form-header {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
@@ -2269,6 +2290,10 @@ watch(() => route.query.good_id, (newId) => {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.goods-form .basic-fields :deep(.el-form-item) {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.basic-fields :deep(.el-form-item:last-child) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@@ -2393,6 +2418,11 @@ watch(() => route.query.good_id, (newId) => {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.goods-form .form-grid :deep(.el-form-item) {
|
||||
min-width: 0;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.form-grid .arg-type-item {
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user