Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-dml
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-dml
Commits
2c83c129
提交
2c83c129
authored
11月 14, 2025
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
bug fixes
上级
6a3cdb5f
全部展开
显示空白字符变更
内嵌
并排
正在显示
8 个修改的文件
包含
84 行增加
和
47 行删除
+84
-47
FormPrice.vue
src/modules/live/product/management/components/FormPrice.vue
+42
-7
FormDialog.vue
src/modules/live/reports/components/FormDialog.vue
+7
-25
CompetitionLive.vue
src/modules/live/score/components/CompetitionLive.vue
+7
-6
FormDialog.vue
src/modules/live/talk/components/FormDialog.vue
+15
-2
api.ts
src/modules/live/test/api.ts
+3
-3
Live.vue
src/modules/live/test/components/Live.vue
+2
-1
RecordView.vue
src/modules/live/test/components/RecordView.vue
+0
-0
useLiveChat.ts
src/modules/live/test/composables/useLiveChat.ts
+8
-3
没有找到文件。
src/modules/live/product/management/components/FormPrice.vue
浏览文件 @
2c83c129
...
...
@@ -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"
>
...
...
src/modules/live/reports/components/FormDialog.vue
浏览文件 @
2c83c129
<
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_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
>
src/modules/live/score/components/CompetitionLive.vue
浏览文件 @
2c83c129
...
...
@@ -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"
>
...
...
src/modules/live/talk/components/FormDialog.vue
浏览文件 @
2c83c129
...
...
@@ -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>
...
...
src/modules/live/test/api.ts
浏览文件 @
2c83c129
...
...
@@ -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/
scor
e-live-practice-record'
,
data
)
//
更新直播记录的AI分析结果
export
function
updateRecord
(
data
:
{
id
:
string
;
ai_analyze
:
string
})
{
return
httpRequest
.
post
(
'/api/lab/v1/experiment/live-practice/
updat
e-live-practice-record'
,
data
)
}
src/modules/live/test/components/Live.vue
浏览文件 @
2c83c129
...
...
@@ -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
)
{
...
...
src/modules/live/test/components/RecordView.vue
浏览文件 @
2c83c129
差异被折叠。
点击展开。
src/modules/live/test/composables/useLiveChat.ts
浏览文件 @
2c83c129
...
...
@@ -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
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论