|
|
@@ -1,5 +1,13 @@
|
|
|
<template>
|
|
|
<view class="app-content">
|
|
|
+ <!-- 加载状态 -->
|
|
|
+ <view v-if="loading" class="loading-overlay">
|
|
|
+ <view class="loading-content">
|
|
|
+ <view class="loading-spinner"></view>
|
|
|
+ <text class="loading-text">加载中...</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
<form @submit="commitForm">
|
|
|
<view class="module-com input-line-wrap">
|
|
|
|
|
|
@@ -19,9 +27,9 @@
|
|
|
<view class="tui-title">封面</view>
|
|
|
<view class="tui-input">
|
|
|
<block v-if="coverImgData.length > 0">
|
|
|
- <button class="admin-button-com" :class="[(form.cover == item) ? '' : 'default']"
|
|
|
+ <button class="admin-button-com" :class="[(form.shortCover == item) ? '' : 'default']"
|
|
|
v-for="(item, index) in coverImgData" :key="index"
|
|
|
- @click="selCoverFn(item)" >第{{ item }}张</button>
|
|
|
+ @click="selCoverFn(index)" >第{{ index + 1 }}张</button>
|
|
|
</block>
|
|
|
<view v-else class="no-img-tip">请先上传图片</view>
|
|
|
<view v-if="coverImgData.length > 0" class="use-img">选择上面的图片作为封面</view>
|
|
|
@@ -40,7 +48,7 @@
|
|
|
|
|
|
<tui-list-cell class="line-cell" :hover="false">
|
|
|
<view class="tui-title required">名称</view>
|
|
|
- <input v-model="form.name" placeholder-class="phcolor" class="tui-input" name="name" placeholder="请输入" maxlength="50" type="text" @focus="clearNameInput" />
|
|
|
+ <input v-model="form.name" placeholder-class="phcolor" class="tui-input" name="name" placeholder="请输入商品名称" maxlength="50" type="text" @focus="clearNameInput" />
|
|
|
</tui-list-cell>
|
|
|
|
|
|
<tui-list-cell class="line-cell" :hover="false">
|
|
|
@@ -53,12 +61,12 @@
|
|
|
|
|
|
<tui-list-cell v-if="form.priceType === '1'" class="line-cell" :hover="false">
|
|
|
<view class="tui-title required">价格</view>
|
|
|
- <input v-model="form.price" placeholder-class="phcolor" class="tui-input" name="price" placeholder="请输入" maxlength="50" type="digit" />
|
|
|
+ <input v-model="form.price" placeholder-class="phcolor" class="tui-input" name="price" placeholder="请输入价格" maxlength="10" type="digit" />
|
|
|
</tui-list-cell>
|
|
|
|
|
|
<tui-list-cell class="line-cell" :hover="false">
|
|
|
<view class="tui-title">已售数量</view>
|
|
|
- <input v-model="form.sold" placeholder-class="phcolor" class="tui-input" name="sold" placeholder="客户端展示:已售数量+实售数量" maxlength="50" type="number" />
|
|
|
+ <input v-model="form.sold" placeholder-class="phcolor" class="tui-input" name="sold" placeholder="客户端展示:已售数量+实售数量" maxlength="10" type="number" />
|
|
|
</tui-list-cell>
|
|
|
<!-- <tui-list-cell class="line-cell" :hover="true" :arrow="true">
|
|
|
<view class="tui-title required">品种</view>
|
|
|
@@ -76,12 +84,12 @@
|
|
|
|
|
|
<tui-list-cell v-if="form.stockSet === '1'" class="line-cell" :hover="false">
|
|
|
<view class="tui-title">库存</view>
|
|
|
- <input v-model="form.stock" placeholder-class="phcolor" @focus="form.stock=''" class="tui-input" name="stock" placeholder="请输入库存数量" maxlength="50" type="number" />
|
|
|
+ <input v-model="form.stock" placeholder-class="phcolor" @focus="onStockFocus" @blur="onStockBlur" class="tui-input" name="stock" placeholder="请输入库存数量" maxlength="10" type="number" />
|
|
|
</tui-list-cell>
|
|
|
|
|
|
<tui-list-cell class="line-cell" :hover="false">
|
|
|
<view class="tui-title">用花支数</view>
|
|
|
- <input v-model="form.flowerNum" placeholder-class="phcolor" class="tui-input" name="flowerNum" placeholder="用于判断花束大小" maxlength="50" type="number" />
|
|
|
+ <input v-model="form.flowerNum" placeholder-class="phcolor" @focus="onFlowerNumFocus" @blur="onFlowerNumBlur" class="tui-input" name="flowerNum" placeholder="用于判断花束大小" maxlength="5" type="number" />
|
|
|
</tui-list-cell>
|
|
|
|
|
|
<tui-list-cell class="line-cell" :hover="false">
|
|
|
@@ -125,8 +133,8 @@
|
|
|
</view> -->
|
|
|
|
|
|
<view class="app-footer">
|
|
|
- <button class="admin-button-com middle default" @click="goBack">取消</button>
|
|
|
- <button class="admin-button-com middle blue" formType="submit">保存</button>
|
|
|
+ <button class="admin-button-com middle default" @click="goBack" :disabled="loading">取消</button>
|
|
|
+ <button class="admin-button-com middle blue" formType="submit" :disabled="loading">{{ loading ? '保存中...' : '保存' }}</button>
|
|
|
</view>
|
|
|
|
|
|
</form>
|
|
|
@@ -140,15 +148,17 @@ import { getClass } from "@/api/category";
|
|
|
import { addGoodsData, getGoodsDetail } from "@/api/goods"
|
|
|
import htzImageUpload from '@/components/htz-image-upload/htz-image-upload.vue'
|
|
|
import productMins from "@/mixins/product";
|
|
|
+import inputRestore from "@/mixins/inputRestore";
|
|
|
export default {
|
|
|
name: "add",
|
|
|
components: { TuiListCell, AppUploader,htzImageUpload },
|
|
|
- mixins: [productMins],
|
|
|
+ mixins: [productMins, inputRestore],
|
|
|
data() {
|
|
|
return {
|
|
|
headers:{token:''},
|
|
|
status: 1,
|
|
|
selectJobType: "addGoodsSelectItem",
|
|
|
+ loading: false, // 新增加载状态
|
|
|
form: {
|
|
|
name: "",
|
|
|
price: "",
|
|
|
@@ -165,6 +175,7 @@ export default {
|
|
|
briefContent: "",
|
|
|
status: 1,
|
|
|
cover: '1',
|
|
|
+ shortCover: "", // 添加shortCover字段,与detail.vue保持一致
|
|
|
setItemNum: 0,
|
|
|
},
|
|
|
categoryData:[],
|
|
|
@@ -180,10 +191,10 @@ export default {
|
|
|
computed: {
|
|
|
// 根据上传的图片数量动态生成封面选项
|
|
|
coverImgData() {
|
|
|
- if (this.currentImgData.length === 0) {
|
|
|
+ if (this.form.shopImg.length === 0) {
|
|
|
return [];
|
|
|
}
|
|
|
- return Array.from({length: this.currentImgData.length}, (_, index) => index + 1);
|
|
|
+ return this.form.shopImg;
|
|
|
}
|
|
|
},
|
|
|
watch:{
|
|
|
@@ -201,12 +212,20 @@ export default {
|
|
|
imgDeleteFn(res){
|
|
|
const index = res.index
|
|
|
this.form.shopImg.splice(index,1)
|
|
|
- // 如果删除的图片是当前选中的封面,或封面索引超出范围,重置封面选择
|
|
|
- if (this.form.cover > this.currentImgData.length || this.form.cover == (index + 1)) {
|
|
|
- this.form.cover = this.currentImgData.length > 0 ? '1' : '';
|
|
|
- } else if (this.form.cover > (index + 1)) {
|
|
|
- // 如果删除的是前面的图片,封面索引需要减1
|
|
|
- this.form.cover = (parseInt(this.form.cover) - 1).toString();
|
|
|
+
|
|
|
+ // 处理封面图片的临界情况,与detail.vue保持一致
|
|
|
+ if (this.form.shopImg.length === 0) {
|
|
|
+ // 没有图片了,清空封面
|
|
|
+ this.form.cover = '';
|
|
|
+ this.form.shortCover = '';
|
|
|
+ } else {
|
|
|
+ // 检查当前封面是否还在图片列表中
|
|
|
+ const currentCoverIndex = this.form.shopImg.findIndex(img => img === this.form.shortCover);
|
|
|
+ if (currentCoverIndex === -1) {
|
|
|
+ // 当前封面不在列表中,设置为第一张图片
|
|
|
+ this.form.cover = this.form.shopImg[0];
|
|
|
+ this.form.shortCover = this.form.shopImg[0];
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
imgUploadSuccess(res) {
|
|
|
@@ -216,20 +235,28 @@ export default {
|
|
|
this.form.shopImg.push(_res.data.shortUrl)
|
|
|
// 如果是第一张图片,自动设置为封面
|
|
|
if (this.currentImgData.length === 1) {
|
|
|
- this.form.cover = '1';
|
|
|
+ this.form.cover = _res.data.shortUrl;
|
|
|
+ this.form.shortCover = _res.data.shortUrl;
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
init() {
|
|
|
+ this.loading = true;
|
|
|
getClass({flower:1}).then(res => {
|
|
|
if(res.code && res.code == 1){
|
|
|
this.categoryData = res.data
|
|
|
}
|
|
|
+ }).catch(err => {
|
|
|
+ console.error('获取分类失败:', err);
|
|
|
+ this.$msg('获取分类信息失败');
|
|
|
+ }).finally(() => {
|
|
|
+ this.loading = false;
|
|
|
})
|
|
|
},
|
|
|
// 封面选择
|
|
|
- selCoverFn(item) {
|
|
|
- this.form.cover = item
|
|
|
+ selCoverFn(index) {
|
|
|
+ this.form.cover = this.form.shopImg[index];
|
|
|
+ this.form.shortCover = this.form.shopImg[index];
|
|
|
},
|
|
|
// 分类选择
|
|
|
selCategoryFn(item) {
|
|
|
@@ -255,7 +282,7 @@ export default {
|
|
|
this.form.priceType = type;
|
|
|
if (type === '0') {
|
|
|
this.form.price = "0";
|
|
|
- } else {
|
|
|
+ } else if (type === '1' && this.form.price === "0") {
|
|
|
this.form.price = "";
|
|
|
}
|
|
|
},
|
|
|
@@ -263,9 +290,11 @@ export default {
|
|
|
setstockSet(status) {
|
|
|
this.form.stockSet = status;
|
|
|
if (status === '1') {
|
|
|
- this.form.stock = "";
|
|
|
- }
|
|
|
- if (status === '0') {
|
|
|
+ // 如果当前库存是默认的大数值,清空让用户输入
|
|
|
+ if (this.form.stock >= 9999) {
|
|
|
+ this.form.stock = "";
|
|
|
+ }
|
|
|
+ } else if (status === '0') {
|
|
|
this.form.stock = 9999;
|
|
|
}
|
|
|
},
|
|
|
@@ -300,13 +329,30 @@ export default {
|
|
|
}
|
|
|
|
|
|
// 如果没有选择封面,默认使用第一张图片
|
|
|
- if (!this.form.cover) {
|
|
|
+ if (!this.form.shortCover && this.form.shopImg.length > 0) {
|
|
|
this.form.cover = this.form.shopImg[0];
|
|
|
+ this.form.shortCover = this.form.shopImg[0];
|
|
|
}
|
|
|
|
|
|
that.$util.confirmModal({content:'确认添加?'},() => {
|
|
|
+ this.loading = true; // 开始加载
|
|
|
uni.showLoading({mask:true})
|
|
|
let formData = JSON.parse(JSON.stringify(this.form));
|
|
|
+
|
|
|
+ // 修复封面处理逻辑,与detail.vue保持一致
|
|
|
+ if (this.form.shopImg.length > 0) {
|
|
|
+ // 找到当前封面在图片列表中的索引
|
|
|
+ const coverIndex = this.form.shopImg.findIndex(img => img === this.form.shortCover);
|
|
|
+ if (coverIndex !== -1) {
|
|
|
+ formData.cover = this.form.shopImg[coverIndex];
|
|
|
+ } else {
|
|
|
+ // 如果找不到封面,使用第一张图片
|
|
|
+ formData.cover = this.form.shopImg[0];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ formData.cover = '';
|
|
|
+ }
|
|
|
+
|
|
|
addGoodsData({ status: this.status, ...formData }).then(res => {
|
|
|
uni.hideLoading()
|
|
|
this.$msg("添加成功")
|
|
|
@@ -326,7 +372,7 @@ export default {
|
|
|
priceType: parseInt(formData.priceType),
|
|
|
stock: formData.stockSet === '1' ? parseInt(formData.stock || 0) : 9999,
|
|
|
actualSold: 0,
|
|
|
- smallCover: this.currentImgData[parseInt(formData.cover) - 1] || this.currentImgData[0] || '',
|
|
|
+ smallCover: this.currentImgData.length > 0 ? this.currentImgData[this.form.shopImg.findIndex(img => img === this.form.shortCover)] || this.currentImgData[0] : '',
|
|
|
...res.data
|
|
|
};
|
|
|
// 将新商品添加到列表第一项
|
|
|
@@ -341,10 +387,20 @@ export default {
|
|
|
setTimeout(function(){
|
|
|
uni.navigateBack({})
|
|
|
},1500)
|
|
|
+ }).catch(err => {
|
|
|
+ uni.hideLoading()
|
|
|
+ this.$msg(err.msg || '添加失败')
|
|
|
+ }).finally(() => {
|
|
|
+ this.loading = false; // 结束加载
|
|
|
})
|
|
|
})
|
|
|
},
|
|
|
commitForm(e) {
|
|
|
+ // 防止重复提交
|
|
|
+ if (this.loading) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
let rules = [
|
|
|
{
|
|
|
name: "name",
|
|
|
@@ -368,6 +424,33 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // 验证库存数量
|
|
|
+ if (this.form.stockSet === '1' && this.form.stock !== "") {
|
|
|
+ const stockNum = parseFloat(this.form.stock);
|
|
|
+ if (isNaN(stockNum) || stockNum < 0) {
|
|
|
+ this.$msg('库存数量必须是大于等于0的数字!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证已售数量
|
|
|
+ if (this.form.sold !== "") {
|
|
|
+ const soldNum = parseFloat(this.form.sold);
|
|
|
+ if (isNaN(soldNum) || soldNum < 0) {
|
|
|
+ this.$msg('已售数量必须是大于等于0的数字!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证花支数
|
|
|
+ if (this.form.flowerNum !== "" && this.form.flowerNum !== 0) {
|
|
|
+ const flowerNum = parseFloat(this.form.flowerNum);
|
|
|
+ if (isNaN(flowerNum) || flowerNum < 0) {
|
|
|
+ this.$msg('花支数必须是大于0的数字!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
let formData = e.detail.value;
|
|
|
let checkRes = form.validation(formData, rules);
|
|
|
if (!checkRes) {
|
|
|
@@ -377,6 +460,22 @@ export default {
|
|
|
} else {
|
|
|
this.$msg(checkRes);
|
|
|
}
|
|
|
+ },
|
|
|
+ // 库存输入框聚焦
|
|
|
+ onStockFocus() {
|
|
|
+ this.onInputFocus('stock');
|
|
|
+ },
|
|
|
+ // 库存输入框失焦
|
|
|
+ onStockBlur() {
|
|
|
+ this.onInputBlur('stock');
|
|
|
+ },
|
|
|
+ // 花支数输入框聚焦
|
|
|
+ onFlowerNumFocus() {
|
|
|
+ this.onInputFocus('flowerNum');
|
|
|
+ },
|
|
|
+ // 花支数输入框失焦
|
|
|
+ onFlowerNumBlur() {
|
|
|
+ this.onInputBlur('flowerNum');
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
@@ -386,6 +485,50 @@ export default {
|
|
|
min-height: calc(100vh - 100upx);
|
|
|
padding-bottom: 100upx;
|
|
|
}
|
|
|
+
|
|
|
+/* 加载状态样式 */
|
|
|
+.loading-overlay {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background-color: rgba(0, 0, 0, 0.5);
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ z-index: 9999;
|
|
|
+}
|
|
|
+
|
|
|
+.loading-content {
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 20upx;
|
|
|
+ padding: 40upx;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.loading-spinner {
|
|
|
+ width: 60upx;
|
|
|
+ height: 60upx;
|
|
|
+ border: 4upx solid #f3f3f3;
|
|
|
+ border-top: 4upx solid #09C567;
|
|
|
+ border-radius: 50%;
|
|
|
+ animation: spin 1s linear infinite;
|
|
|
+ margin-bottom: 20upx;
|
|
|
+}
|
|
|
+
|
|
|
+.loading-text {
|
|
|
+ font-size: 28upx;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes spin {
|
|
|
+ 0% { transform: rotate(0deg); }
|
|
|
+ 100% { transform: rotate(360deg); }
|
|
|
+}
|
|
|
+
|
|
|
.module-com {
|
|
|
margin-bottom: 20upx;
|
|
|
background-color: #fff;
|
|
|
@@ -467,6 +610,12 @@ export default {
|
|
|
width: 46%;
|
|
|
padding-top:30upx;
|
|
|
padding-bottom:30upx;
|
|
|
+
|
|
|
+ &:disabled {
|
|
|
+ opacity: 0.6;
|
|
|
+ background-color: #ccc !important;
|
|
|
+ color: #999 !important;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
.commodity-view {
|