diff --git a/src/api/system/jdorder.js b/src/api/system/jdorder.js index d108ecf..46cccd0 100644 --- a/src/api/system/jdorder.js +++ b/src/api/system/jdorder.js @@ -3,7 +3,7 @@ import request from '@/utils/request' // JD订单列表 export function listJDOrders(query) { return request({ - url: '/jarvis/jdorder/list', + url: '/system/jdorder/list', method: 'get', params: query }) @@ -12,7 +12,7 @@ export function listJDOrders(query) { // JD订单详情 export function getJDOrder(id) { return request({ - url: `/jarvis/jdorder/${id}`, + url: `/system/jdorder/${id}`, method: 'get' }) } @@ -119,4 +119,13 @@ export function transferWithGift(data) { method: 'post', data }) +} + +// 导出JD订单列表 +export function exportJDOrders(query) { + return request({ + url: '/system/jdorder/export', + method: 'post', + params: query + }) } \ No newline at end of file diff --git a/src/permission.js b/src/permission.js index b66190b..dedb360 100644 --- a/src/permission.js +++ b/src/permission.js @@ -9,7 +9,7 @@ import { isRelogin } from '@/utils/request' NProgress.configure({ showSpinner: false }) -const whiteList = ['/login', '/register'] +const whiteList = ['/login', '/register','/public/comment'] const isWhiteList = (path) => { return whiteList.some(pattern => isPathMatch(pattern, path)) diff --git a/src/plugins/index.js b/src/plugins/index.js index d000f2d..5860293 100644 --- a/src/plugins/index.js +++ b/src/plugins/index.js @@ -3,6 +3,7 @@ import auth from './auth' import cache from './cache' import modal from './modal' import download from './download' +import request from '@/utils/request' export default { install(Vue) { @@ -16,5 +17,7 @@ export default { Vue.prototype.$modal = modal // 下载文件 Vue.prototype.$download = download + // 全局请求实例(供 this.$axios 使用) + Vue.prototype.$axios = request } } diff --git a/src/router/index.js b/src/router/index.js index 40b621f..c0dd3bb 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -116,6 +116,12 @@ export const constantRoutes = [ } ] }, + // 公开评论独立页(不使用 Layout,无侧边栏) + { + path: '/public/comment', + component: () => import('@/views/public/CommentGenerator'), + hidden: true + }, { path: '/jdorder', component: Layout, @@ -146,22 +152,6 @@ export const constantRoutes = [ } ] }, - // 公共页面(免登录)可直接通过服务端 Anonymous 注解放行接口,这里仍挂在主框架下展示 - { - path: '/public', - component: Layout, - redirect: 'noredirect', - name: 'Public', - meta: { title: '公共工具', icon: 'link' }, - children: [ - { - path: 'comment', - component: () => import('@/views/public/CommentGenerator'), - name: 'CommentGeneratorPublic', - meta: { title: '评论生成(公开)', icon: 'message' } - } - ] - }, { path: '/sloworder', component: Layout, diff --git a/src/views/public/CommentGenerator.vue b/src/views/public/CommentGenerator.vue index fa47405..b5e729d 100644 --- a/src/views/public/CommentGenerator.vue +++ b/src/views/public/CommentGenerator.vue @@ -1,43 +1,165 @@ @@ -45,55 +167,64 @@ export default { name: 'CommentGeneratorPublic', data() { - return { form: { productType: '' }, loading: false, result: null, typeOptions: [], activeLetter: 'ALL' } + return { + form: { productType: '' }, + loading: false, + result: null, + typeOptions: [], + comments: [], + statistics: null, + lastGenerateTime: 0, + cooldownTime: 1000, // 5秒冷却时间 + isButtonDisabled: false + } }, computed: { pretty() { try { return this.result ? JSON.stringify(this.result, null, 2) : '' } catch(e) { return '' } }, - letters() { - return Array.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ') + isGenerateButtonDisabled() { + // 如果正在加载、手动禁用、没有选择产品类型,或者在冷却时间内,则禁用按钮 + return this.loading || + this.isButtonDisabled || + !this.form.productType || + (Date.now() - this.lastGenerateTime < this.cooldownTime && this.lastGenerateTime > 0) }, - groupedByLetter() { - const groups = {} - const items = Array.isArray(this.typeOptions) ? this.typeOptions.slice() : [] - items.forEach(it => { - const ltr = this.getInitial(it) - if (!groups[ltr]) groups[ltr] = [] - groups[ltr].push(it) - }) - Object.keys(groups).forEach(k => { - groups[k].sort((a, b) => { - const an = (a.name || '').toString() - const bn = (b.name || '').toString() - return an.localeCompare(bn) - }) - }) - return groups - }, - filteredGroups() { - if (this.activeLetter === 'ALL') { - const ordered = {} - this.letters.concat('#').forEach(l => { - if (this.groupedByLetter[l] && this.groupedByLetter[l].length) { - ordered[l] = this.groupedByLetter[l] - } - }) - if (this.groupedByLetter['#'] && !ordered['#']) ordered['#'] = this.groupedByLetter['#'] - return ordered - } - const letter = this.activeLetter - const res = {} - if (this.groupedByLetter[letter]) res[letter] = this.groupedByLetter[letter] - return res + remainingCooldownTime() { + if (this.lastGenerateTime === 0) return 0 + const remaining = Math.max(0, this.cooldownTime - (Date.now() - this.lastGenerateTime)) + return Math.ceil(remaining / 1000) + } + }, + mounted() { + this.loadTypes() + // 启动定时器更新冷却时间显示 + this.cooldownTimer = setInterval(() => { + // 检查倒计时是否结束,如果结束则清空lastGenerateTime + if (this.lastGenerateTime > 0) { + const remaining = this.cooldownTime - (Date.now() - this.lastGenerateTime) + if (remaining <= 0) { + this.lastGenerateTime = 0 + } + } + // 强制更新计算属性 + this.$forceUpdate() + }, 1000) + }, + beforeDestroy() { + if (this.cooldownTimer) { + clearInterval(this.cooldownTimer) } }, - mounted() { this.loadTypes() }, methods: { async loadTypes() { try { const res = await this.$axios({ url: '/public/comment/types', method: 'get' }) - if (res && (res.code === 200 || res.msg === '操作成功')) this.typeOptions = res.data || [] + if (res && (res.code === 200 || res.msg === '操作成功')) { + // 后端返回 [{name,value}] 或纯数组,这里统一转成 [{name}] + const arr = Array.isArray(res.data) ? res.data : [] + this.typeOptions = arr.map(it => ({ name: it.name || it })) + } } catch(e) {} }, getInitial(it) { @@ -109,17 +240,81 @@ export default { this.form.productType = it.value }, async generate() { - if (!this.form.productType) { this.$message.error('请选择型号'); return } + // 检查按钮是否被禁用 + if (this.isGenerateButtonDisabled) { + if (this.remainingCooldownTime > 0) { + this.$message.warning(`请等待 ${this.remainingCooldownTime} 秒后再试`) + } else if (!this.form.productType) { + this.$message.error('请选择型号') + } + return + } + + // 记录点击时间 + this.lastGenerateTime = Date.now() this.loading = true + this.isButtonDisabled = false + try { - const res = await this.$axios({ url: '/public/comment/generate', method: 'post', data: { productType: this.form.productType } }) + const res = await this.$axios({ + url: '/public/comment/generate', + method: 'post', + data: { productType: this.form.productType }, + timeout: 30000 // 30秒超时 + }) + this.loading = false + if (res && (res.code === 200 || res.msg === '操作成功')) { this.result = res.data + + // 检查是否有有效数据 + const list = (res.data && res.data.list && Array.isArray(res.data.list)) ? res.data.list : [] + + if (list.length === 0) { + this.$message.warning('接口返回数据为空,请稍后重试') + this.isButtonDisabled = true + // 10秒后重新启用按钮 + setTimeout(() => { + this.isButtonDisabled = false + }, 10000) + return + } + + // 结果渲染 + this.comments = list.map(it => ({ + commentText: (it && it.commentText) ? it.commentText : '', + images: Array.isArray(it && it.images) ? it.images : [] + })) + + // 解析统计信息 + this.statistics = res.data && res.data.statistics ? res.data.statistics : null + + this.$message.success('评论生成成功') } else { this.$message.error(res && res.msg ? res.msg : '生成失败') + this.isButtonDisabled = true + // 5秒后重新启用按钮 + setTimeout(() => { + this.isButtonDisabled = false + }, 5000) } - } catch(e) { this.loading = false; this.$message.error('生成失败') } + } catch(e) { + this.loading = false + console.error('生成评论失败:', e) + + if (e.code === 'ECONNABORTED') { + this.$message.error('请求超时,请检查网络连接') + } else { + this.$message.error('生成失败,请稍后重试') + } + + this.isButtonDisabled = true + // 5秒后重新启用按钮 + setTimeout(() => { + this.isButtonDisabled = false + }, 5000) + } }, copy(text) { if (!text) return @@ -130,54 +325,577 @@ export default { try { document.execCommand('copy'); this.$message.success('已复制') } catch(e) { this.$message.error('复制失败') } document.body.removeChild(ta) } + }, + getUsagePercentage() { + if (!this.statistics || !this.statistics.total || this.statistics.total === 0) { + return 0 + } + const used = this.statistics.used || 0 + const total = this.statistics.total + return Math.round((used / total) * 100) + }, + getButtonText() { + if (this.loading) { + return '生成中...' + } + if (this.remainingCooldownTime > 0) { + return `等待中 (${this.remainingCooldownTime}s)` + } + if (this.isButtonDisabled) { + return '暂时禁用' + } + if (!this.form.productType) { + return '请先选择型号' + } + return '生成评论' } } } diff --git a/src/views/system/jdorder/orderList.vue b/src/views/system/jdorder/orderList.vue index 0f357dd..9e58e31 100644 --- a/src/views/system/jdorder/orderList.vue +++ b/src/views/system/jdorder/orderList.vue @@ -34,38 +34,43 @@ 搜索 重置 + 导出 - - - + + - - + + + + - - - - - + + + + proPriceAmount + + + + + +