提交 2c83c129 authored 作者: 王鹏飞's avatar 王鹏飞

bug fixes

上级 6a3cdb5f
......@@ -11,7 +11,7 @@ if (!form.info.specs) {
// 初始化sku列表
if (!form.info.sku) {
form.info.sku = [{ price: '', stock: 0 }]
form.info.sku = [{ price: '', stock: 0, reference_price: '' }]
}
// 确保在没有规格时至少有一个SKU
......@@ -22,7 +22,7 @@ onMounted(() => {
function ensureSkuExists() {
const hasValidSpecs = form.info.specs && form.info.specs.some((spec) => spec.name && spec.name.trim())
if (!hasValidSpecs && (!form.info.sku || form.info.sku.length === 0)) {
form.info.sku = [{ price: '', stock: 0 }]
form.info.sku = [{ price: '', stock: 0, reference_price: '' }]
}
}
......@@ -79,12 +79,13 @@ function generateSkuList() {
// 如果没有有效规格,确保至少有一个SKU
if (validSpecs.length === 0) {
if (!form.info.sku || form.info.sku.length === 0) {
form.info.sku = [{ price: '', stock: 0 }]
form.info.sku = [{ price: '', stock: 0, reference_price: '' }]
} else if (form.info.sku.length === 1 && !form.info.sku[0].specs) {
// 保持单个SKU,但不添加specs字段
form.info.sku[0] = {
price: form.info.sku[0].price || '',
stock: form.info.sku[0].stock || 0,
reference_price: form.info.sku[0].reference_price || '',
}
} else {
// 如果之前有多个SKU(有规格时),现在没有规格了,只保留第一个或创建一个新的
......@@ -93,6 +94,7 @@ function generateSkuList() {
{
price: firstSku?.price || '',
stock: firstSku?.stock || 0,
reference_price: firstSku?.reference_price || '',
},
]
}
......@@ -107,11 +109,12 @@ function generateSkuList() {
// 如果任何规格没有有效值,确保至少有一个SKU
if (specValuesArrays.some((arr) => arr.length === 0)) {
if (!form.info.sku || form.info.sku.length === 0) {
form.info.sku = [{ price: '', stock: 0 }]
form.info.sku = [{ price: '', stock: 0, reference_price: '' }]
} else if (form.info.sku.length === 1 && !form.info.sku[0].specs) {
form.info.sku[0] = {
price: form.info.sku[0].price || '',
stock: form.info.sku[0].stock || 0,
reference_price: form.info.sku[0].reference_price || '',
}
}
return
......@@ -120,12 +123,16 @@ function generateSkuList() {
// 生成笛卡尔积
const combinations = cartesianProduct(specValuesArrays)
// 生成SKU列表,保留已存在的价格和库存数据
// 生成SKU列表,保留已存在的价格、库存和参考价数据
const existingSkuMap = new Map()
form.info.sku.forEach((sku) => {
// 如果有specs字段,使用specs作为key;否则使用空数组作为key
const key = JSON.stringify(sku.specs || [])
existingSkuMap.set(key, { price: sku.price || '', stock: sku.stock || 0 })
existingSkuMap.set(key, {
price: sku.price || '',
stock: sku.stock || 0,
reference_price: sku.reference_price || '',
})
})
form.info.sku = combinations.map((combo) => {
......@@ -135,6 +142,7 @@ function generateSkuList() {
specs: combo,
price: existing?.price || '',
stock: existing?.stock || 0,
reference_price: existing?.reference_price || '',
}
})
}
......@@ -164,6 +172,7 @@ watch(hasSpecs, (newVal) => {
// 批量设置相关
const batchPrice = ref('')
const batchStock = ref('')
const batchReferencePrice = ref('')
// 批量设置价格
function batchSetPrice() {
......@@ -188,6 +197,17 @@ function batchSetStock() {
})
batchStock.value = ''
}
// 批量设置参考价
function batchSetReferencePrice() {
if (batchReferencePrice.value === '' || batchReferencePrice.value === null || batchReferencePrice.value === undefined)
return
const referencePrice = batchReferencePrice.value
form.info.sku.forEach((sku) => {
sku.reference_price = referencePrice
})
batchReferencePrice.value = ''
}
</script>
<template>
......@@ -278,6 +298,14 @@ function batchSetStock() {
</el-input>
<el-button type="primary" plain @click="batchSetStock" style="margin-left: 8px"> 批量设置库存 </el-button>
</div>
<div class="batch-set-item">
<el-input v-model="batchReferencePrice" placeholder="批量设置参考价" type="number" style="width: 200px">
<template #prefix>¥</template>
</el-input>
<el-button type="primary" plain @click="batchSetReferencePrice" style="margin-left: 8px">
批量设置参考价
</el-button>
</div>
</div>
<el-table :data="form.info.sku" border :header-cell-style="{ backgroundColor: '#f5f7fa' }" style="width: 100%">
<el-table-column v-if="hasSpecs" label="规格组合" align="center" width="200">
......@@ -292,6 +320,13 @@ function batchSetStock() {
</el-input>
</template>
</el-table-column>
<el-table-column prop="reference_price" label="参考价" align="center">
<template #default="{ row }">
<el-input v-model="row.reference_price" placeholder="请输入参考价" type="number">
<template #prefix>¥</template>
</el-input>
</template>
</el-table-column>
<el-table-column prop="stock" label="库存" align="center">
<template #default="{ row }">
<el-input v-model.number="row.stock" placeholder="请输入库存" type="number">
......@@ -301,7 +336,7 @@ function batchSetStock() {
</el-table-column>
</el-table>
</el-form-item>
<el-form-item label="参考价" prop="info.reference_price">
<el-form-item label="参考价" prop="info.reference_price" v-if="false">
<template #label>
<span>参考价</span>
<el-popover :width="200" trigger="hover" placement="right">
......
<script setup>
import { ElMessage } from 'element-plus'
import { Document } from '@element-plus/icons-vue'
import { createReport, getReport, getTestList } from '../api'
import AppUpload from '@/components/base/AppUpload.vue'
......@@ -17,6 +16,7 @@ const form = reactive({
live_practice_id: '',
report_name: '',
report_url: '',
file: [],
})
watchEffect(() => {
if (props.data) Object.assign(form, props.data)
......@@ -36,7 +36,9 @@ onMounted(() => {
async function fetchInfo() {
const res = await getReport({ id: props.data.id })
Object.assign(form, res.data.detail)
Object.assign(form, res.data.detail, {
file: [{ name: res.data.detail.report_name || '', url: res.data.detail.report_url || '' }],
})
}
watchEffect(() => {
if (props.action !== 'add') fetchInfo()
......@@ -65,9 +67,8 @@ async function handleUpdate() {
}
function handleSuccess(file) {
if (!form.report_name) {
form.report_name = file.name
}
form.report_name = file.name
form.report_url = file.raw?.url
}
</script>
......@@ -91,16 +92,10 @@ function handleSuccess(file) {
</el-form-item>
<el-form-item label="总结报告文件" prop="report_url">
<div style="width: 100%">
<AppUpload v-model="form.report_url" accept=".doc,.docx,.pdf" @success="handleSuccess">
<AppUpload v-model="form.file" accept=".doc,.docx,.ppt,.pptx" :limit="1" @success="handleSuccess">
<el-button type="primary" plain round>本地上传</el-button>
<template #tip>报告文件只能上传一个,支持格式包含:doc docx pdf,大小不超过50M</template>
<template #tip>报告文件只能上传一个,支持格式包含:ppt docx,大小不超过50M</template>
</AppUpload>
<div class="upload-preview" v-if="form.report_url">
<a :href="form.report_url" target="_blank">
<el-icon><Document /></el-icon>
<span>{{ form.report_name || form.report_url }}</span>
</a>
</div>
</div>
</el-form-item>
</el-form>
......@@ -114,16 +109,3 @@ function handleSuccess(file) {
</template>
</el-dialog>
</template>
<style lang="scss" scoped>
.upload-preview {
a {
display: flex;
align-items: center;
white-space: nowrap;
gap: 5px;
overflow: hidden;
text-overflow: ellipsis;
}
}
</style>
......@@ -194,7 +194,11 @@ const handleNext = () => {
v-model:comment="scoreDetails.commodity_type.comment"
@save="$emit('save')"
@next="handleNext">
<AppList v-bind="categoryTableOptions" row-key="id" :data="detail.live_data.commodity_types" />
<AppList
v-bind="categoryTableOptions"
row-key="id"
:data="detail.live_data.commodity_types"
default-expand-all />
</ScoreCard>
</el-tab-pane>
<el-tab-pane label="商品属性管理" :name="2" lazy>
......@@ -216,7 +220,7 @@ const handleNext = () => {
v-model:comment="scoreDetails.commodity.comment"
@save="$emit('save')"
@next="handleNext">
<AppList v-bind="productTableOptions" :data="productList" :default-expand-all="productList.length === 1">
<AppList v-bind="productTableOptions" :data="productList" default-expand-all>
<template #table-expand="{ row }">
<div class="table-expand-box">
<el-form label-position="top">
......@@ -273,10 +277,7 @@ const handleNext = () => {
v-model:comment="scoreDetails.speech.comment"
@save="$emit('save')"
@next="handleNext">
<AppList
v-bind="talkTableOptions"
:data="detail.live_data.speeches"
:default-expand-all="detail.live_data.speeches.length === 1">
<AppList v-bind="talkTableOptions" :data="detail.live_data.speeches" default-expand-all>
<template #table-expand="{ row }">
<div class="table-expand-box">
<el-form label-position="top">
......
......@@ -216,6 +216,7 @@ function handleAIGenerate(index) {
plain
size="small"
@click="handleAIGenerate(1)"
:disabled="isLoading"
:loading="isLoading && aiActive === 1"
>AI一键生成</el-button
>
......@@ -233,6 +234,7 @@ function handleAIGenerate(index) {
plain
size="small"
@click="handleAIGenerate(2)"
:disabled="isLoading"
:loading="isLoading && aiActive === 2"
>AI一键生成</el-button
>
......@@ -253,7 +255,12 @@ function handleAIGenerate(index) {
<el-col :sm="24" :md="12" style="border-left: 1px solid #dcdfe6">
<div style="text-align: center; margin-bottom: 20px">
<h2 style="margin-bottom: 20px">直播话术</h2>
<el-button type="primary" size="large" @click="handleAIGenerate(3)" :loading="isLoading && aiActive === 3">
<el-button
type="primary"
size="large"
@click="handleAIGenerate(3)"
:disabled="isLoading"
:loading="isLoading && aiActive === 3">
{{ messages.length ? '再次生成直播话术' : 'AI生成直播话术' }}
</el-button>
</div>
......@@ -272,7 +279,13 @@ function handleAIGenerate(index) {
<template #footer>
<el-row justify="center">
<el-button round auto-insert-space @click="$emit('update:modelValue', false)">关闭</el-button>
<el-button type="primary" round auto-insert-space @click="handleSubmit" v-if="action !== 'view'"
<el-button
type="primary"
round
auto-insert-space
:disabled="isLoading"
@click="handleSubmit"
v-if="action !== 'view'"
>保存</el-button
>
</el-row>
......
......@@ -72,7 +72,7 @@ export function updateImprovementPlan(data: { id: string; improvement_plan: stri
return httpRequest.post('/api/lab/v1/experiment/live-practice/submit-improvement-plan', data)
}
// AI 打分
export function aiScore(data: { id: string }) {
return httpRequest.post('/api/lab/v1/experiment/live-practice/score-live-practice-record', data)
// 更新直播记录的AI分析结果
export function updateRecord(data: { id: string; ai_analyze: string }) {
return httpRequest.post('/api/lab/v1/experiment/live-practice/update-live-practice-record', data)
}
......@@ -22,7 +22,7 @@ const props = defineProps({
onStatsChange: { type: Function, default: () => {} },
})
const { messages, viewers, stats, currentTime, start: startChat } = useLiveChat()
const { messages, viewers, stats, currentTime, start: startChat, stop: stopChat } = useLiveChat()
watch(
() => [stats, viewers],
() => {
......@@ -96,6 +96,7 @@ const {
console.log('结束直播')
if (enabled.value) return
props.onStop && props.onStop(blob)
stopChat()
handleUpdateRecord({ live_video_size: blob.size.toString() })
// 保存录像到本地
if (props.isLocalUpload) {
......
......@@ -120,12 +120,13 @@ export function useLiveChat(options: UseLiveChatOptions = {}) {
// 随机事件生成
const generateRandomEvents = () => {
const rand = Math.random()
if (rand < 0.9) randomJoin()
if (rand < 0.8) randomJoin()
if (rand < 0.4) randomLeave()
if (rand < 0.7) randomGift()
if (rand < 0.8) randomLike()
}
let timer: number | null = null
// 开始
const start = () => {
// 初始化观众
......@@ -133,7 +134,11 @@ export function useLiveChat(options: UseLiveChatOptions = {}) {
randomJoin()
}
// 开始定时更新
setInterval(generateRandomEvents, updateInterval)
timer = setInterval(generateRandomEvents, updateInterval)
}
const stop = () => {
if (timer) clearInterval(timer)
timer = null
}
if (autoStart) start()
......@@ -161,5 +166,5 @@ export function useLiveChat(options: UseLiveChatOptions = {}) {
{ immediate: true }
)
return { viewers, messages, stats, currentTime, start, reset }
return { viewers, messages, stats, currentTime, start, stop, reset }
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论