From 5b607c8031c79deaff4702584927a2242a0302a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8D=92?= Date: Fri, 7 Nov 2025 16:10:23 +0800 Subject: [PATCH] 1 --- src/views/system/giftcoupon/batch.vue | 848 ++++++++------------------ 1 file changed, 248 insertions(+), 600 deletions(-) diff --git a/src/views/system/giftcoupon/batch.vue b/src/views/system/giftcoupon/batch.vue index 179fdab..c67665d 100644 --- a/src/views/system/giftcoupon/batch.vue +++ b/src/views/system/giftcoupon/batch.vue @@ -4,312 +4,119 @@
批量创建礼金并替换URL - 支持批量创建20张1元面额礼金券,并自动将文本中的URL替换为包含礼金的推广链接 + 一键操作:粘贴文案 → 自动创建礼金 → 输出替换后的文案
- - - - - - -
- 查询商品 -
-
- - 重要:请输入商品链接或SKU ID,支持多行输入多个商品,点击查询后会显示商品列表供选择。 -
-
-
-
+ + + + + + + + + + + + + 自营 + POP + + + + + 已识别 {{ detectedUrls.length }} 个URL + + + - - -
- 查询结果(共 {{ productList.length }} 个商品) - 已选择 {{ selectedProducts.length }} 个商品 -
- 全选 - 清空 + + + + +
+
+ + 输入原始文案 + + + 一键生成 ({{ detectedUrls.length }}个) + +
+ +
+
+ + + +
+
+ + 替换后的文案 + + + 复制结果 + +
+ +
+ + + +
+ {{ progressDetail }} +
+
+
+ +
点击左侧"一键生成"按钮后,替换结果将显示在这里
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 已选商品信息({{ selectedProducts.length }} 个) - - 提交并批量创建 - -
- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - + +
+ - - - - - - - - 文本内容 - - 已检测到 {{ detectedUrls.length }} 个URL - - - -
-
- - 已选择 {{ selectedProducts.length }} 个商品,现在请粘贴您的推广文案(包含京东链接) -
- -
- - 直接粘贴完整文案即可!支持识别 https://item.jd.com、https://u.jd.com、u.jd.com 等所有京东链接格式 -
-
- - 已识别URL数量: {{ detectedUrls.length }} - - - 批量创建并替换 ({{ detectedUrls.length }}个) - -
-
- - - - - - -
- {{ progressDetail }} -
-
- - - -
- 替换结果 - - 复制结果 - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+
@@ -323,22 +130,14 @@ export default { return { content: '', form: { - materialUrl: '', - skuName: '', - owner: 'g', - amount: 1.8, // 默认1.8元 - quantity: 12, // 默认每个礼金数量为12 - queryResult: null, // 保存查询到的商品信息(保留兼容性) - selectedProduct: null // 用户选中的商品(保留兼容性,用于单个商品) + amount: 1.8, + quantity: 12, + owner: 'g' }, - productList: [], // 查询到的商品列表 - selectedProducts: [], // 用户选中的商品列表(多选) rules: { - materialUrl: [{ required: true, message: '请输入商品链接或SKU', trigger: 'blur' }], amount: [{ required: true, message: '请输入礼金金额', trigger: 'blur' }], quantity: [{ required: true, message: '请输入礼金数量', trigger: 'blur' }] }, - queryLoading: false, processing: false, progress: 0, progressText: '', @@ -354,216 +153,6 @@ export default { } }, methods: { - /** 查询商品信息 */ - async queryProductInfo() { - const materialUrl = this.form.materialUrl.trim() - if (!materialUrl) { - this.$modal.msgWarning('请输入商品链接或SKU ID') - return - } - - this.queryLoading = true - this.productList = [] - this.form.selectedProduct = null - this.form.queryResult = null - - try { - const res = await generatePromotionContent({ promotionContent: materialUrl }) - - if (res && res.code === 200) { - try { - let resultStr = res.data || res.msg - let parsed = null - if (typeof resultStr === 'string') { - parsed = JSON.parse(resultStr) - } else { - parsed = resultStr - } - - console.log('解析后的数据:', parsed) - - // 解析商品数组 - let products = [] - if (Array.isArray(parsed) && parsed.length > 0) { - // 格式1:直接是数组 - products = parsed - } else if (parsed && typeof parsed === 'object') { - // 格式2:对象中包含list数组 - if (parsed.list && Array.isArray(parsed.list) && parsed.list.length > 0) { - products = parsed.list - } - // 格式3:对象中包含data数组 - else if (parsed.data && Array.isArray(parsed.data) && parsed.data.length > 0) { - products = parsed.data - } - // 格式4:对象本身包含商品信息(单个商品) - else if (parsed.materialUrl || parsed.owner || parsed.skuName) { - products = [parsed] - } - } - - console.log('解析到的商品列表:', products) - - if (products.length > 0) { - this.productList = products - - // 默认全选所有商品 - this.$nextTick(() => { - this.selectAllProducts() - // 如果只有一个商品,自动滚动到文本输入区域 - if (products.length === 1) { - setTimeout(() => { - window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }) - }, 300) - } - }) - - this.$modal.msgSuccess({ - message: `✅ 查询成功!找到 ${products.length} 个商品,已默认全选。现在请在下方"输入文本"框中粘贴您的推广文案。`, - duration: 5000 - }) - } else { - this.$modal.msgWarning('未找到商品信息,请检查链接是否正确') - } - } catch (e) { - console.error('解析商品信息失败', e) - this.$modal.msgWarning('返回数据格式异常:' + e.message) - } - } else { - this.$modal.msgError('查询商品信息失败:' + (res.msg || '未知错误')) - } - } catch (e) { - console.error('查询商品信息异常', e) - this.$modal.msgError('查询失败:' + (e.message || '未知错误')) - } finally { - this.queryLoading = false - } - }, - - /** 选择商品(单选,保留兼容性) */ - selectProduct(product) { - this.form.selectedProduct = product - this.form.queryResult = product - this.form.skuName = product.skuName || product.title || product.productName || product.cleanSkuName || '' - const ownerValue = product.owner || (product.popId ? 'pop' : 'g') || 'g' - this.form.owner = ownerValue === 'p' ? 'pop' : (ownerValue === 'pop' ? 'pop' : 'g') - - this.$modal.msgSuccess('已选择商品:' + this.form.skuName + '(' + (this.form.owner === 'g' ? '自营' : 'POP') + ')') - }, - - /** 表格多选变化 */ - handleSelectionChange(selection) { - this.selectedProducts = selection - // 如果只选中一个,同步到selectedProduct(兼容性) - if (selection.length === 1) { - this.form.selectedProduct = selection[0] - this.form.queryResult = selection[0] - } else { - this.form.selectedProduct = null - this.form.queryResult = null - } - }, - - /** 全选商品 */ - selectAllProducts() { - this.$nextTick(() => { - this.productList.forEach(row => { - this.$refs.productTable && this.$refs.productTable.toggleRowSelection(row, true) - }) - }) - }, - - /** 清空选择 */ - clearSelection() { - this.$refs.productTable && this.$refs.productTable.clearSelection() - }, - - /** 提交选中的商品并批量创建 */ - async submitSelectedProducts() { - if (this.selectedProducts.length === 0) { - this.$modal.msgWarning('请至少选择一个商品') - return - } - - if (!this.$refs.form) { - return - } - - this.$refs.form.validate(async (valid) => { - if (!valid) return - - if (this.detectedUrls.length === 0) { - this.$modal.msgWarning('文本中未找到URL,无需替换。请在文本框中输入包含京东商品链接的内容。') - return - } - - if (this.detectedUrls.length > 100) { - this.$modal.msgError('检测到的URL数量超过100个,请分批处理') - return - } - - // 确认操作 - try { - await this.$confirm( - `已选择 ${this.selectedProducts.length} 个商品,文本中检测到 ${this.detectedUrls.length} 个URL,将批量创建 ${this.detectedUrls.length} 张 ${this.form.amount} 元礼金券并自动替换文本中的URL为包含礼金的推广链接。是否继续?`, - '确认批量创建', - { - confirmButtonText: '确定创建', - cancelButtonText: '取消', - type: 'warning' - } - ) - } catch { - return - } - - // 为每个选中的商品分别处理(这里简化处理,使用第一个选中的商品) - // 实际业务中可能需要为每个商品创建对应的礼金券 - const selectedProduct = this.selectedProducts[0] - this.form.selectedProduct = selectedProduct - this.form.queryResult = selectedProduct - this.form.skuName = selectedProduct.skuName || selectedProduct.title || selectedProduct.productName || selectedProduct.cleanSkuName || '' - const ownerValue = selectedProduct.owner || (selectedProduct.popId ? 'pop' : 'g') || 'g' - this.form.owner = ownerValue === 'p' ? 'pop' : (ownerValue === 'pop' ? 'pop' : 'g') - - // 调用批量创建和替换 - await this.handleReplace() - }) - }, - - /** 格式化价格 */ - formatPrice(price) { - if (!price) return '0.00' - // 如果价格是分为单位,转换为元 - if (typeof price === 'number' && price > 1000) { - return (price / 100).toFixed(2) - } - return Number(price).toFixed(2) - }, - - /** 格式化佣金金额 */ - formatCommissionAmount(commission, price) { - if (!commission || !price) return '0.00' - // commission可能是百分比字符串或数值 - let commissionPercent = 0 - if (typeof commission === 'string') { - commissionPercent = parseFloat(commission.replace('%', '')) || 0 - } else { - commissionPercent = commission - } - - // price可能是分为单位,需要转换 - let priceValue = price - if (typeof price === 'number' && price > 1000) { - priceValue = price / 100 - } else { - priceValue = parseFloat(price) || 0 - } - - const commissionAmount = (priceValue * commissionPercent / 100) - return commissionAmount.toFixed(2) - }, - /** 检测文本中的URL */ detectUrls(text) { if (!text || text.trim().length === 0) { @@ -585,8 +174,8 @@ export default { this.detectedUrls = urls }, - /** 批量创建并替换 */ - async handleReplace() { + /** 一键处理 */ + async handleProcess() { if (!this.$refs.form) { return } @@ -594,13 +183,8 @@ export default { this.$refs.form.validate(async (valid) => { if (!valid) return - if (!this.form.selectedProduct || !this.form.queryResult) { - this.$modal.msgWarning('请先查询商品信息并选择一个商品') - return - } - if (this.detectedUrls.length === 0) { - this.$modal.msgWarning('文本中未找到URL,无需替换。请在文本框中输入包含京东商品链接的内容。') + this.$modal.msgWarning('文本中未找到URL,请输入包含京东商品链接的文案') return } @@ -612,7 +196,7 @@ export default { // 确认操作 try { await this.$confirm( - `检测到 ${this.detectedUrls.length} 个商品URL,将批量创建 ${this.detectedUrls.length} 张 ${this.form.amount} 元礼金券并自动替换文本中的URL为包含礼金的推广链接。是否继续?`, + `检测到 ${this.detectedUrls.length} 个商品链接,将自动批量创建 ${this.detectedUrls.length} 张 ${this.form.amount} 元礼金券并替换文案中的URL。是否继续?`, '确认批量创建', { confirmButtonText: '确定创建', @@ -627,81 +211,105 @@ export default { this.processing = true this.progress = 0 this.progressText = '准备中...' - this.progressDetail = '' + this.progressDetail = '正在从URL提取商品信息...' this.progressStatus = '' this.result = null try { - // 构建请求参数 - // 注意:batchSize 会自动根据文本中解析出的URL数量设置 - const params = { - content: this.content, - amount: this.form.amount, - quantity: this.form.quantity, - // batchSize 会在后端根据content中解析出的URL数量自动计算,这里不需要传 - owner: this.form.owner || 'g', - skuName: this.form.skuName || '' - } + // 使用第一个URL查询商品信息 + const firstUrl = this.detectedUrls[0] + this.progress = 10 + this.progressText = '正在查询商品信息...' + this.progressDetail = `正在查询商品: ${firstUrl.substring(0, 50)}...` - // 根据查询结果设置skuId或materialUrl - if (this.form.queryResult) { - const queryResult = this.form.queryResult - const isPop = this.form.owner === 'pop' + const queryRes = await generatePromotionContent({ promotionContent: firstUrl }) + + if (queryRes && queryRes.code === 200) { + let parsed = null + let resultStr = queryRes.data || queryRes.msg + if (typeof resultStr === 'string') { + parsed = JSON.parse(resultStr) + } else { + parsed = resultStr + } + + // 提取第一个商品信息 + let product = null + if (Array.isArray(parsed) && parsed.length > 0) { + product = parsed[0] + } else if (parsed && typeof parsed === 'object') { + if (parsed.list && Array.isArray(parsed.list) && parsed.list.length > 0) { + product = parsed.list[0] + } else if (parsed.data && Array.isArray(parsed.data) && parsed.data.length > 0) { + product = parsed.data[0] + } else if (parsed.materialUrl || parsed.skuName) { + product = parsed + } + } + + if (!product) { + this.$modal.msgError('无法从URL中提取商品信息,请检查链接是否正确') + this.processing = false + return + } + + this.progress = 30 + this.progressText = '正在批量创建礼金券...' + this.progressDetail = `准备创建 ${this.detectedUrls.length} 张礼金券,请耐心等待...` + + // 构建请求参数 + const params = { + content: this.content, + amount: this.form.amount, + quantity: this.form.quantity, + owner: this.form.owner || 'g', + skuName: product.skuName || product.title || product.productName || product.cleanSkuName || '' + } + + // 设置skuId或materialUrl + const isPop = this.form.owner === 'pop' if (isPop) { - if (queryResult.materialUrl) { - params.materialUrl = queryResult.materialUrl - } else if ((queryResult.skuId || queryResult.skuid) && /^\d+$/.test(String(queryResult.skuId || queryResult.skuid))) { - params.skuId = String(queryResult.skuId || queryResult.skuid) + if (product.materialUrl) { + params.materialUrl = product.materialUrl + } else if ((product.skuId || product.skuid) && /^\d+$/.test(String(product.skuId || product.skuid))) { + params.skuId = String(product.skuId || product.skuid) } } else { - const skuIdValue = queryResult.skuId || queryResult.skuid + const skuIdValue = product.skuId || product.skuid if (skuIdValue && /^\d+$/.test(String(skuIdValue))) { params.skuId = String(skuIdValue) - } else if (queryResult.materialUrl) { - params.materialUrl = queryResult.materialUrl + } else if (product.materialUrl) { + params.materialUrl = product.materialUrl } } - } - - // 如果没有设置skuId或materialUrl,使用用户输入的 - if (!params.skuId && !params.materialUrl) { - const materialUrl = this.form.materialUrl.trim() - if (materialUrl) { - if (/^\d+$/.test(materialUrl)) { - params.skuId = materialUrl - } else { - params.materialUrl = materialUrl - } - } - } - - console.log('批量替换请求参数:', params) - - // 调用替换接口 - this.progress = 30 - this.progressText = '正在批量创建礼金券...' - this.progressDetail = '这可能需要几分钟时间,请耐心等待' - - const res = await replaceUrlsWithGiftCoupons(params) - - this.progress = 80 - this.progressText = '正在处理结果...' - - if (res && res.code === 200 && res.data) { - this.result = res.data - this.progress = 100 - this.progressStatus = 'success' - this.progressText = '完成!' - this.progressDetail = `成功替换 ${this.result.replacedCount || 0} / ${this.result.totalUrls || 0} 个URL` - this.$modal.msgSuccess(`批量替换完成!成功 ${this.result.replacedCount || 0} / ${this.result.totalUrls || 0} 个`) + console.log('批量替换请求参数:', params) + + // 调用替换接口 + this.progress = 40 + const res = await replaceUrlsWithGiftCoupons(params) + + this.progress = 80 + this.progressText = '正在处理结果...' + + if (res && res.code === 200 && res.data) { + this.result = res.data + this.progress = 100 + this.progressStatus = 'success' + this.progressText = '完成!' + this.progressDetail = `成功替换 ${this.result.replacedCount || 0} / ${this.result.totalUrls || 0} 个URL` + + this.$modal.msgSuccess(`✅ 批量替换完成!成功 ${this.result.replacedCount || 0} / ${this.result.totalUrls || 0} 个`) + } else { + this.progress = 100 + this.progressStatus = 'exception' + this.progressText = '失败' + this.progressDetail = res.msg || '未知错误' + this.$modal.msgError('批量替换失败:' + (res.msg || '未知错误')) + } } else { - this.progress = 100 - this.progressStatus = 'exception' - this.progressText = '失败' - this.progressDetail = res.msg || '未知错误' - this.$modal.msgError('批量替换失败:' + (res.msg || '未知错误')) + this.$modal.msgError('查询商品信息失败:' + (queryRes.msg || '未知错误')) } } catch (e) { console.error('批量替换异常', e) @@ -717,7 +325,7 @@ export default { errorMsg = e.message } - this.$modal.msgError('批量替换失败:' + errorMsg) + this.$modal.msgError('操作失败:' + errorMsg) } finally { this.processing = false } @@ -731,13 +339,6 @@ export default { } }, - /** 文本框获得焦点 */ - handleTextareaFocus() { - if (this.selectedProducts.length === 0) { - this.$modal.msgWarning('请先查询商品并选择要推广的商品') - } - }, - /** 复制到剪贴板 */ copyToClipboard(text) { if (navigator.clipboard && navigator.clipboard.writeText) { @@ -761,7 +362,7 @@ export default { textArea.select() try { document.execCommand('copy') - this.$modal.msgSuccess('复制成功') + this.$modal.msgSuccess('✅ 复制成功!') } catch (err) { this.$modal.msgError('复制失败') } @@ -776,12 +377,59 @@ export default { padding: 20px; } -.el-divider { - margin: 10px 0; +.text-panel { + border: 2px solid #DCDFE6; + border-radius: 8px; + overflow: hidden; } -.el-statistic { - text-align: center; +.panel-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 15px 20px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; +} + +.textarea-input, .textarea-output { + border: none !important; + border-radius: 0 !important; +} + +.textarea-input >>> textarea { + border: none !important; + border-radius: 0 !important; + font-size: 14px; + line-height: 1.8; + padding: 20px; +} + +.textarea-output >>> textarea { + border: none !important; + border-radius: 0 !important; + font-size: 14px; + line-height: 1.8; + padding: 20px; + background: #f5f7fa; +} + +.loading-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 550px; + padding: 40px; + background: #f5f7fa; +} + +.empty-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 550px; + background: #fafafa; } -