Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-dml
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-dml
Commits
0611fee6
提交
0611fee6
authored
6月 29, 2026
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 页面响应式设计
上级
130196c4
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
60 个修改的文件
包含
1162 行增加
和
194 行删除
+1162
-194
package-lock.json
package-lock.json
+0
-0
base.css
src/assets/styles/base.css
+104
-0
ChartCard.vue
src/components/ChartCard.vue
+13
-0
LiveProductCategory.vue
src/components/LiveProductCategory.vue
+3
-1
AppList.vue
src/components/base/AppList.vue
+124
-0
Aside.vue
src/components/layout/Aside.vue
+122
-23
Footer.vue
src/components/layout/Footer.vue
+1
-1
Index.vue
src/components/layout/Index.vue
+0
-4
Main.vue
src/components/layout/Main.vue
+3
-1
Index.vue
src/modules/analyze/event/views/Index.vue
+5
-0
Index.vue
src/modules/analyze/label/views/Index.vue
+5
-0
Index.vue
src/modules/analyze/marketing/views/Index.vue
+44
-10
Index.vue
src/modules/analyze/user/views/Index.vue
+5
-0
StepOne.vue
src/modules/connect/components/StepOne.vue
+6
-0
StudentFollowDialog.vue
src/modules/connect/components/StudentFollowDialog.vue
+5
-0
Index.vue
src/modules/connect/views/Index.vue
+3
-1
View.vue
src/modules/connect/views/View.vue
+16
-0
Index.vue
src/modules/home/views/Index.vue
+23
-0
LabelTypeFormDialog.vue
src/modules/label/components/LabelTypeFormDialog.vue
+5
-0
Index.vue
src/modules/label/views/Index.vue
+17
-0
Index.vue
src/modules/live/order/views/Index.vue
+9
-7
Index.vue
src/modules/live/product/attr/views/Index.vue
+10
-21
Index.vue
src/modules/live/product/category/views/Index.vue
+1
-1
FormBaseInfo.vue
...dules/live/product/management/components/FormBaseInfo.vue
+42
-16
FormCategory.vue
...dules/live/product/management/components/FormCategory.vue
+26
-17
FormGraphicInfo.vue
...es/live/product/management/components/FormGraphicInfo.vue
+11
-1
FormPrice.vue
src/modules/live/product/management/components/FormPrice.vue
+18
-1
FormService.vue
...odules/live/product/management/components/FormService.vue
+2
-2
ImageDesign.vue
...odules/live/product/management/components/ImageDesign.vue
+18
-3
Upload.vue
src/modules/live/product/management/components/Upload.vue
+10
-6
Index.vue
src/modules/live/product/management/views/Index.vue
+10
-17
Update.vue
src/modules/live/product/management/views/Update.vue
+39
-0
FormDialog.vue
src/modules/live/reports/components/FormDialog.vue
+11
-3
Index.vue
src/modules/live/reports/views/Index.vue
+6
-3
FormDialog.vue
src/modules/live/talk/components/FormDialog.vue
+28
-4
Index.vue
src/modules/live/talk/views/Index.vue
+14
-4
Demo.vue
src/modules/live/test/components/Demo.vue
+30
-0
FormDialog.vue
src/modules/live/test/components/FormDialog.vue
+4
-1
Live.vue
src/modules/live/test/components/Live.vue
+92
-20
LivePlayback.vue
src/modules/live/test/components/LivePlayback.vue
+35
-1
RecordView.vue
src/modules/live/test/components/RecordView.vue
+37
-2
useLive.ts
src/modules/live/test/composables/useLive.ts
+25
-2
Index.vue
src/modules/live/test/views/Index.vue
+7
-11
Step5.vue
src/modules/market/my/components/Step5.vue
+5
-0
Index.vue
src/modules/market/my/views/Index.vue
+1
-0
Update.vue
src/modules/market/my/views/Update.vue
+6
-0
Index.vue
src/modules/market/review/views/Index.vue
+3
-0
Score.vue
src/modules/market/review/views/Score.vue
+1
-0
View.vue
src/modules/market/review/views/View.vue
+1
-0
FieldDialog.vue
src/modules/metadata/event/components/FieldDialog.vue
+1
-1
FormDialog.vue
src/modules/metadata/user/components/FormDialog.vue
+1
-1
Steps.vue
src/modules/operations/components/Steps.vue
+42
-0
CompetitionLive.vue
src/modules/score/components/CompetitionLive.vue
+21
-2
CompetitionLive3.vue
src/modules/score/components/CompetitionLive3.vue
+10
-2
CompetitionLiveProd.vue
src/modules/score/components/CompetitionLiveProd.vue
+9
-2
CompetitionOperations.vue
src/modules/score/components/CompetitionOperations.vue
+9
-0
Index.vue
src/modules/score/views/Index.vue
+7
-2
View.vue
src/modules/score/views/View.vue
+7
-0
Image.vue
src/modules/user/views/Image.vue
+36
-0
Index.vue
src/modules/user/views/Index.vue
+13
-0
没有找到文件。
package-lock.json
浏览文件 @
0611fee6
差异被折叠。
点击展开。
src/assets/styles/base.css
浏览文件 @
0611fee6
...
@@ -85,6 +85,13 @@ textarea:focus {
...
@@ -85,6 +85,13 @@ textarea:focus {
margin
:
0
-16px
30px
;
margin
:
0
-16px
30px
;
padding
:
0
16px
;
padding
:
0
16px
;
}
}
/* 移动端弹框宽度 90% */
@media
(
max-width
:
767px
)
{
.el-overlay-dialog
.el-dialog
{
width
:
90%
!important
;
}
}
.info
.el-form-item
{
.info
.el-form-item
{
margin-bottom
:
0
;
margin-bottom
:
0
;
}
}
...
@@ -119,3 +126,100 @@ textarea:focus {
...
@@ -119,3 +126,100 @@ textarea:focus {
padding
:
8px
16px
;
padding
:
8px
16px
;
border
:
1px
solid
#e6e6e6
;
border
:
1px
solid
#e6e6e6
;
}
}
/* ============ 系统级响应式 ============ */
/* 移动端弹框宽度 90% */
@media
(
max-width
:
767px
)
{
.el-overlay-dialog
.el-dialog
{
width
:
90%
!important
;
}
}
@media
(
max-width
:
767px
)
{
/* AppCard 移动端内边距缩减 */
.app-card
{
padding
:
12px
!important
;
}
.app-card
+
.app-card
{
margin-top
:
12px
!important
;
}
.app-card-hd__title
{
font-size
:
16px
;
margin-bottom
:
16px
;
}
/* 全局 el-table 横向滚动 */
.el-table
{
width
:
100%
;
}
.el-table__body-wrapper
{
overflow-x
:
auto
;
-webkit-overflow-scrolling
:
touch
;
}
/* el-pagination 移动端简化 */
.el-pagination
{
flex-wrap
:
wrap
;
justify-content
:
center
;
gap
:
4px
;
font-size
:
12px
;
}
.el-pagination__total
,
.el-pagination__sizes
,
.el-pagination__jump
{
display
:
none
!important
;
}
.el-pager
.number
{
min-width
:
28px
;
height
:
28px
;
line-height
:
28px
;
}
.btn-prev
,
.btn-next
{
height
:
28px
;
min-width
:
28px
;
}
/* el-steps 移动端垂直 */
.el-steps--horizontal
{
flex-direction
:
column
;
}
/* 弹框底部按钮组换行 */
.el-dialog__footer
{
display
:
flex
;
flex-wrap
:
wrap
;
justify-content
:
center
;
gap
:
8px
;
.el-button
{
margin-left
:
0
!important
;
}
}
/* 弹框按钮选中不独占一行,保持自然间距 */
.el-dialog__footer
.el-button
+
.el-button
{
margin-left
:
0
;
}
/* 固定宽度容器防溢出 */
[
style
*=
"width: 200px"
],
[
style
*=
"width: 220px"
],
[
style
*=
"width: 300px"
],
[
style
*=
"width: 340px"
],
[
style
*=
"width: 400px"
],
[
style
*=
"width: 150px"
]
{
max-width
:
100%
!important
;
}
/* hover 显示的元素在触摸设备上常显 */
.connect-item__remove
,
.connect-item__edit
,
.hover-show
{
display
:
block
!important
;
}
[
class
*=
"remove"
]
:hover
,
[
class
*=
"delete"
]
:hover
{
opacity
:
1
;
}
}
src/components/ChartCard.vue
浏览文件 @
0611fee6
...
@@ -107,4 +107,17 @@ const color = ['#af1c40', '#c17933', '#8f0034', '#d45548', '#ab3259', '#dec34c',
...
@@ -107,4 +107,17 @@ const color = ['#af1c40', '#c17933', '#8f0034', '#d45548', '#ab3259', '#dec34c',
height
:
290px
;
height
:
290px
;
}
}
}
}
@media
(
max-width
:
767px
)
{
.chart-hd
{
padding
:
8px
12px
;
height
:
auto
;
flex-wrap
:
wrap
;
gap
:
4px
;
h3
{
font-size
:
14px
;
}
}
.chart-bd
{
margin
:
0
12px
12px
;
.chart
{
height
:
220px
;
}
}
}
</
style
>
</
style
>
src/components/LiveProductCategory.vue
浏览文件 @
0611fee6
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
getCategoryList
}
from
'@/api/base'
import
{
getCategoryList
}
from
'@/api/base'
withDefaults
(
defineProps
<
{
placeholder
?:
string
}
>
(),
{
placeholder
:
'请选择'
})
const
options
=
ref
([])
const
options
=
ref
([])
async
function
fetchList
()
{
async
function
fetchList
()
{
const
res
=
await
getCategoryList
()
const
res
=
await
getCategoryList
()
...
@@ -14,7 +16,7 @@ watchEffect(() => {
...
@@ -14,7 +16,7 @@ watchEffect(() => {
<
template
>
<
template
>
<el-cascader
<el-cascader
clearable
clearable
placeholder=
"请选择
"
:placeholder=
"placeholder
"
style=
"width: 100%"
style=
"width: 100%"
:options=
"options"
:options=
"options"
:props=
"
{
:props=
"
{
...
...
src/components/base/AppList.vue
浏览文件 @
0611fee6
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
Search
,
RefreshLeft
}
from
'@element-plus/icons-vue'
import
{
Search
,
RefreshLeft
}
from
'@element-plus/icons-vue'
import
{
useMediaQuery
}
from
'@vueuse/core'
const
isMobile
=
useMediaQuery
(
'(max-width: 767px)'
)
// 移动端卡片列(过滤序号、操作等 slot 列留给卡片底部渲染)
const
cardColumns
=
computed
(()
=>
props
.
columns
.
filter
((
c
)
=>
c
.
type
!==
'index'
&&
c
.
slots
!==
'table-x'
))
const
hasActionsColumn
=
computed
(()
=>
props
.
columns
.
some
((
c
)
=>
c
.
slots
===
'table-x'
))
interface
IRemoteProps
{
interface
IRemoteProps
{
params
?:
any
params
?:
any
...
@@ -17,6 +24,7 @@ interface Props {
...
@@ -17,6 +24,7 @@ interface Props {
hasPagination
?:
boolean
hasPagination
?:
boolean
limit
?:
number
limit
?:
number
hasLoading
?:
boolean
hasLoading
?:
boolean
mobileCards
?:
boolean
}
}
const
props
=
withDefaults
(
defineProps
<
Props
>
(),
{
const
props
=
withDefaults
(
defineProps
<
Props
>
(),
{
hasPagination
:
true
,
hasPagination
:
true
,
...
@@ -25,6 +33,7 @@ const props = withDefaults(defineProps<Props>(), {
...
@@ -25,6 +33,7 @@ const props = withDefaults(defineProps<Props>(), {
filters
:
()
=>
[],
filters
:
()
=>
[],
columns
:
()
=>
[],
columns
:
()
=>
[],
data
:
()
=>
[],
data
:
()
=>
[],
mobileCards
:
true
,
})
})
const
filterFormRef
=
ref
()
const
filterFormRef
=
ref
()
...
@@ -170,7 +179,9 @@ defineExpose({ refetch, tableRef })
...
@@ -170,7 +179,9 @@ defineExpose({ refetch, tableRef })
<!-- 主体 -->
<!-- 主体 -->
<div
class=
"table-list-bd"
>
<div
class=
"table-list-bd"
>
<slot
name=
"body"
v-bind=
"{ data: dataList }"
>
<slot
name=
"body"
v-bind=
"{ data: dataList }"
>
<!-- 桌面端 / 禁用移动端卡片时:表格 -->
<el-table
<el-table
v-if=
"!isMobile || !mobileCards"
:header-cell-style=
"{ background: '#ededed' }"
:header-cell-style=
"{ background: '#ededed' }"
:data=
"dataList"
:data=
"dataList"
v-loading=
"loading && hasLoading"
v-loading=
"loading && hasLoading"
...
@@ -183,6 +194,27 @@ defineExpose({ refetch, tableRef })
...
@@ -183,6 +194,27 @@ defineExpose({ refetch, tableRef })
</
template
>
</
template
>
</el-table-column>
</el-table-column>
</el-table>
</el-table>
<!-- 移动端:卡片列表 -->
<div
v-if=
"isMobile && mobileCards"
class=
"mobile-card-list"
v-loading=
"loading && hasLoading"
>
<div
class=
"mobile-card"
v-for=
"(row, rowIndex) in dataList"
:key=
"rowIndex"
>
<div
class=
"mobile-card-body"
>
<div
class=
"mobile-card-row"
v-for=
"col in cardColumns"
:key=
"col.prop || col.label"
>
<span
class=
"mobile-card-label"
>
{{ col.label }}
</span>
<span
class=
"mobile-card-colon"
>
:
</span>
<span
class=
"mobile-card-value"
>
<slot
v-if=
"col.slots && $slots[col.slots]"
:name=
"col.slots"
v-bind=
"{ row, $index: rowIndex }"
></slot>
<div
v-html=
"col.computed({ row, $index: rowIndex })"
v-else-if=
"col.computed"
></div>
<
template
v-else
>
{{
row
[
col
.
prop
]
??
'-'
}}
</
template
>
</span>
</div>
</div>
<!-- 操作栏:如果有 slot 列,提取渲染 -->
<div
class=
"mobile-card-ft"
v-if=
"hasActionsColumn"
>
<slot
name=
"table-x"
v-bind=
"{ row, $index: rowIndex }"
></slot>
</div>
</div>
<el-empty
v-if=
"!dataList.length && !loading"
description=
"暂无数据"
/>
</div>
</slot>
</slot>
</div>
</div>
<!-- 底部 -->
<!-- 底部 -->
...
@@ -254,4 +286,96 @@ defineExpose({ refetch, tableRef })
...
@@ -254,4 +286,96 @@ defineExpose({ refetch, tableRef })
}
}
}
}
}
}
// 移动端卡片列表
.mobile-card-list
{
min-height
:
120px
;
}
.mobile-card
{
background
:
#fff
;
border-radius
:
8px
;
border
:
1px
solid
#eee
;
margin-bottom
:
12px
;
overflow
:
hidden
;
display
:
flex
;
flex-direction
:
column
;
}
.mobile-card-body
{
flex
:
1
;
padding
:
14px
16px
;
}
.mobile-card-row
{
display
:
flex
;
padding
:
5px
0
;
border-bottom
:
1px
solid
#f5f5f5
;
line-height
:
1
.6
;
&
:last-child
{
border-bottom
:
none
;
}
}
.mobile-card-label
{
flex-shrink
:
0
;
color
:
#999
;
font-size
:
14px
;
}
.mobile-card-colon
{
color
:
#999
;
font-size
:
14px
;
margin-right
:
6px
;
}
.mobile-card-value
{
flex
:
1
;
font-size
:
14px
;
color
:
#333
;
min-width
:
0
;
word-break
:
break-all
;
}
.mobile-card-ft
{
padding
:
6px
12px
;
display
:
flex
;
flex-wrap
:
wrap
;
gap
:
6px
;
row-gap
:
4px
;
background
:
#fafafa
;
border-top
:
1px
solid
#f0f0f0
;
.el-button
{
padding
:
5px
10px
;
font-size
:
12px
;
min-width
:
44px
;
text-align
:
center
;
+
.el-button
{
margin-left
:
0
;
}
}
}
// 移动端筛选表单
@media
(
max-width
:
767px
)
{
.table-list-hd
.el-form-item__label
{
display
:
none
;
}
.table-list-filter
{
width
:
100%
;
.el-form
,
.el-form--inline
{
width
:
100%
;
}
.el-form-item
{
width
:
100%
;
margin-right
:
0
;
margin-bottom
:
8px
;
}
.el-form-item__content
{
width
:
100%
;
}
.el-input
,
.el-select
,
.el-cascader
{
width
:
100%
!
important
;
}
.filter-buttons
{
width
:
auto
;
}
}
// 移动端分页
.table-list-ft
{
flex-direction
:
column
;
gap
:
8px
;
padding
:
8px
0
;
}
.table-list-pagination
{
.el-pagination
{
display
:
flex
;
flex-wrap
:
wrap
;
justify-content
:
center
;
gap
:
2px
;
}
.el-pagination__total
,
.el-pagination__sizes
,
.el-pagination__jump
{
display
:
none
;
}
.el-pager
{
.number
{
min-width
:
28px
;
height
:
28px
;
line-height
:
28px
;
font-size
:
12px
;
}
}
.btn-prev
,
.btn-next
{
height
:
28px
;
min-width
:
28px
;
}
}
}
</
style
>
</
style
>
src/components/layout/Aside.vue
浏览文件 @
0611fee6
...
@@ -5,12 +5,16 @@ export default { name: 'AppAside' }
...
@@ -5,12 +5,16 @@ export default { name: 'AppAside' }
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
type
{
IMenuItem
}
from
'@/types'
import
type
{
IMenuItem
}
from
'@/types'
import
{
useMenuStore
}
from
'@/stores/menu'
import
{
useMenuStore
}
from
'@/stores/menu'
import
{
ArrowLeft
,
ArrowRight
}
from
'@element-plus/icons-vue'
const
menus
=
useMenuStore
().
menus
const
menus
=
useMenuStore
().
menus
const
route
=
useRoute
()
const
route
=
useRoute
()
const
collapsed
=
ref
(
false
)
const
currentMenu
=
computed
(()
=>
{
const
currentMenu
=
computed
(()
=>
{
return
findMenu
(
route
.
p
ath
,
menus
)
return
findMenu
(
route
.
fullP
ath
,
menus
)
})
})
const
currentSubmenu
=
computed
(()
=>
{
const
currentSubmenu
=
computed
(()
=>
{
...
@@ -21,21 +25,43 @@ function findMenu(path: string, menus: IMenuItem[]) {
...
@@ -21,21 +25,43 @@ function findMenu(path: string, menus: IMenuItem[]) {
return
menus
.
find
((
item
)
=>
{
return
menus
.
find
((
item
)
=>
{
if
(
if
(
item
.
children
&&
item
.
children
&&
item
.
children
.
find
((
item
)
=>
{
item
.
children
.
find
((
child
)
=>
{
const
regExp
=
new
RegExp
(
`^
${
item
.
path
.
replaceAll
(
'?'
,
'
\\
?'
)}
`
)
// 匹配 path + query,不要求 query 参数顺序(如 /material?type=2 应匹配 /material?experiment_id=xxx&type=2)
return
regExp
.
test
(
path
)
const
[
p
,
qs
]
=
child
.
path
.
split
(
'?'
)
if
(
!
path
.
startsWith
(
p
))
return
false
if
(
!
qs
)
return
true
return
qs
.
split
(
'&'
).
every
((
param
)
=>
path
.
includes
(
param
))
})
})
)
{
)
{
return
item
return
item
}
}
const
regExp
=
new
RegExp
(
`^
${
item
.
path
.
replaceAll
(
'?'
,
'
\\
?'
)}
`
)
const
[
p
,
qs
]
=
item
.
path
.
split
(
'?'
)
return
regExp
.
test
(
path
)
if
(
!
path
.
startsWith
(
p
))
return
false
if
(
!
qs
)
return
true
return
qs
.
split
(
'&'
).
every
((
param
)
=>
path
.
includes
(
param
))
})
})
}
}
function
toggleCollapse
()
{
collapsed
.
value
=
!
collapsed
.
value
}
// 处理菜单路径中的 query 参数(如 /material?type=1),与 experiment_id 合并
function
menuLinkTo
(
item
:
{
path
:
string
})
{
const
baseQuery
:
Record
<
string
,
any
>
=
{
experiment_id
:
route
.
query
.
experiment_id
}
const
idx
=
item
.
path
.
indexOf
(
'?'
)
if
(
idx
===
-
1
)
return
{
path
:
item
.
path
,
query
:
baseQuery
}
const
path
=
item
.
path
.
slice
(
0
,
idx
)
const
params
=
new
URLSearchParams
(
item
.
path
.
slice
(
idx
+
1
))
for
(
const
[
key
,
value
]
of
params
)
{
baseQuery
[
key
]
=
value
}
return
{
path
,
query
:
baseQuery
}
}
</
script
>
</
script
>
<
template
>
<
template
>
<aside
class=
"app-aside"
>
<aside
class=
"app-aside"
:class=
"
{ 'is-collapsed': collapsed }"
>
<nav
class=
"menu"
>
<nav
class=
"menu"
>
<ul>
<ul>
<li
<li
...
@@ -45,12 +71,12 @@ function findMenu(path: string, menus: IMenuItem[]) {
...
@@ -45,12 +71,12 @@ function findMenu(path: string, menus: IMenuItem[]) {
v-permission="item.tag">
v-permission="item.tag">
<div
class=
"menu-item"
>
<div
class=
"menu-item"
>
<template
v-if=
"item.children"
>
<template
v-if=
"item.children"
>
<RouterLink
:to=
"
{ path: item.path, query: { experiment_id: $route.query.experiment_id } }
">
<RouterLink
:to=
"
menuLinkTo(item)
"
>
<component
:is=
"item.icon"
class=
"menu-icon"
></component>
<component
:is=
"item.icon"
class=
"menu-icon"
></component>
</RouterLink>
</RouterLink>
</
template
>
</
template
>
<el-tooltip
:content=
"item.name"
placement=
"right"
v-else
>
<el-tooltip
:content=
"item.name"
placement=
"right"
v-else
>
<RouterLink
:to=
"
{ path: item.path, query: { experiment_id: $route.query.experiment_id } }
"
>
<RouterLink
:to=
"
menuLinkTo(item)
"
>
<component
:is=
"item.icon"
class=
"menu-icon"
></component>
<component
:is=
"item.icon"
class=
"menu-icon"
></component>
</RouterLink>
</RouterLink>
</el-tooltip>
</el-tooltip>
...
@@ -63,7 +89,7 @@ function findMenu(path: string, menus: IMenuItem[]) {
...
@@ -63,7 +89,7 @@ function findMenu(path: string, menus: IMenuItem[]) {
:key=
"submenu.path"
:key=
"submenu.path"
:class=
"{ 'is-active': submenu.path === currentSubmenu?.path }"
:class=
"{ 'is-active': submenu.path === currentSubmenu?.path }"
v-permission=
"submenu.tag"
>
v-permission=
"submenu.tag"
>
<RouterLink
:to=
"
{ path: submenu.path, query: { experiment_id: $route.query.experiment_id } }
"
>
<RouterLink
:to=
"
menuLinkTo(submenu)
"
>
<component
:is=
"submenu.icon"
class=
"submenu-icon"
v-if=
"submenu.icon"
></component>
<component
:is=
"submenu.icon"
class=
"submenu-icon"
v-if=
"submenu.icon"
></component>
{{ submenu.name }}
{{ submenu.name }}
</RouterLink>
</RouterLink>
...
@@ -72,7 +98,15 @@ function findMenu(path: string, menus: IMenuItem[]) {
...
@@ -72,7 +98,15 @@ function findMenu(path: string, menus: IMenuItem[]) {
</nav>
</nav>
</li>
</li>
</ul>
</ul>
<!-- 展开时的收起按钮 -->
<div
class=
"menu-toggle"
@
click=
"toggleCollapse"
v-if=
"!collapsed"
>
<el-icon><ArrowLeft
/></el-icon>
</div>
</nav>
</nav>
<!-- 收起后的展开胶囊按钮 -->
<div
class=
"aside-float-btn"
@
click=
"toggleCollapse"
v-if=
"collapsed"
>
<el-icon><ArrowRight
/></el-icon>
</div>
</aside>
</aside>
</template>
</template>
...
@@ -82,15 +116,19 @@ function findMenu(path: string, menus: IMenuItem[]) {
...
@@ -82,15 +116,19 @@ function findMenu(path: string, menus: IMenuItem[]) {
top
:
0
;
top
:
0
;
display
:
flex
;
display
:
flex
;
height
:
100vh
;
height
:
100vh
;
// overflow-x: hidden;
// overflow-y: auto;
box-sizing
:
content-box
;
box-sizing
:
content-box
;
z-index
:
2001
;
z-index
:
2001
;
transition
:
width
0
.25s
ease
;
.menu
{
.menu
{
width
:
60px
;
width
:
60px
;
flex-shrink
:
0
;
height
:
100%
;
height
:
100%
;
background
:
#fff
;
background
:
#fff
;
box-sizing
:
border-box
;
box-sizing
:
border-box
;
position
:
relative
;
z-index
:
1
;
.menu-item
{
.menu-item
{
height
:
44px
;
height
:
44px
;
text-align
:
center
;
text-align
:
center
;
...
@@ -106,19 +144,18 @@ function findMenu(path: string, menus: IMenuItem[]) {
...
@@ -106,19 +144,18 @@ function findMenu(path: string, menus: IMenuItem[]) {
}
}
}
}
}
}
>
ul
>
li
{
>
ul
{
padding
:
8px
;
padding-bottom
:
80px
;
&
.is-active
{
>
li
{
.menu-item
{
padding
:
8px
;
background-color
:
var
(
--
main-color
);
&
.is-active
{
svg
{
.menu-item
{
fill
:
#fff
;
background-color
:
var
(
--
main-color
);
svg
{
fill
:
#fff
;
}
}
}
}
}
}
&
:hover
{
&
:hover
{
.submenu
{
display
:
block
;
}
.submenu
{
display
:
block
;
}
}
}
}
}
}
...
@@ -165,5 +202,67 @@ function findMenu(path: string, menus: IMenuItem[]) {
...
@@ -165,5 +202,67 @@ function findMenu(path: string, menus: IMenuItem[]) {
line-height
:
1
;
line-height
:
1
;
color
:
var
(
--
main-color
);
color
:
var
(
--
main-color
);
}
}
// 底部收起按钮
.menu-toggle
{
position
:
absolute
;
bottom
:
20px
;
left
:
50%
;
transform
:
translateX
(
-50%
);
width
:
28px
;
height
:
56px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
cursor
:
pointer
;
color
:
#999
;
font-size
:
14px
;
background
:
#fff
;
border
:
1px
solid
#e0e0e0
;
border-radius
:
28px
;
box-shadow
:
0
2px
6px
rgba
(
0
,
0
,
0
,
0
.08
);
z-index
:
10
;
&
:hover
{
background
:
var
(
--
main-color
);
color
:
#fff
;
border-color
:
var
(
--
main-color
);
}
}
// 收起状态
&
.is-collapsed
{
width
:
0
;
overflow
:
hidden
;
.menu
{
transform
:
translateX
(
-60px
);
}
}
}
// 悬浮胶囊按钮
.aside-float-btn
{
position
:
fixed
;
left
:
0
;
bottom
:
20px
;
width
:
28px
;
height
:
56px
;
background
:
#fff
;
border
:
1px
solid
#e0e0e0
;
border-left
:
none
;
border-radius
:
0
28px
28px
0
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
cursor
:
pointer
;
z-index
:
2000
;
box-shadow
:
2px
0
6px
rgba
(
0
,
0
,
0
,
0
.08
);
color
:
#666
;
font-size
:
14px
;
transition
:
all
0
.2s
;
&
:hover
{
background
:
var
(
--
main-color
);
color
:
#fff
;
border-color
:
var
(
--
main-color
);
}
}
}
</
style
>
</
style
>
src/components/layout/Footer.vue
浏览文件 @
0611fee6
...
@@ -5,7 +5,7 @@ export default { name: 'AppFooter' }
...
@@ -5,7 +5,7 @@ export default { name: 'AppFooter' }
<
template
>
<
template
>
<footer
class=
"app-footer"
>
<footer
class=
"app-footer"
>
<p>
实验室版本:V2.1.0
</p>
<p>
实验室版本:V2.1.0
</p>
<p>
Copyright © 20
17
Zijing Education. All rights reserved. 清控紫荆(北京)教育科技股份有限公司
</p>
<p>
Copyright © 20
26
Zijing Education. All rights reserved. 清控紫荆(北京)教育科技股份有限公司
</p>
</footer>
</footer>
</
template
>
</
template
>
...
...
src/components/layout/Index.vue
浏览文件 @
0611fee6
...
@@ -5,16 +5,13 @@ export default { name: 'AppLayout' }
...
@@ -5,16 +5,13 @@ export default { name: 'AppLayout' }
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
AppAside
from
'./Aside.vue'
import
AppAside
from
'./Aside.vue'
import
AppMain
from
'./Main.vue'
import
AppMain
from
'./Main.vue'
import
AppFooter
from
'./Footer.vue'
interface
Props
{
interface
Props
{
sidebar
?:
boolean
sidebar
?:
boolean
footer
?:
boolean
}
}
withDefaults
(
defineProps
<
Props
>
(),
{
withDefaults
(
defineProps
<
Props
>
(),
{
sidebar
:
true
,
sidebar
:
true
,
footer
:
true
})
})
</
script
>
</
script
>
...
@@ -23,7 +20,6 @@ withDefaults(defineProps<Props>(), {
...
@@ -23,7 +20,6 @@ withDefaults(defineProps<Props>(), {
<AppAside
v-if=
"sidebar"
></AppAside>
<AppAside
v-if=
"sidebar"
></AppAside>
<div
class=
"app-layout-container"
>
<div
class=
"app-layout-container"
>
<AppMain></AppMain>
<AppMain></AppMain>
<AppFooter
v-if=
"footer"
></AppFooter>
</div>
</div>
</div>
</div>
</
template
>
</
template
>
...
...
src/components/layout/Main.vue
浏览文件 @
0611fee6
...
@@ -4,7 +4,9 @@ const isIframe = computed(() => {
...
@@ -4,7 +4,9 @@ const isIframe = computed(() => {
})
})
const
padding
=
computed
(()
=>
{
const
padding
=
computed
(()
=>
{
return
isIframe
.
value
?
'0 10px'
:
'10px'
if
(
isIframe
.
value
)
return
'0 10px'
if
(
typeof
window
!==
'undefined'
&&
window
.
innerWidth
<
768
)
return
'6px'
return
'10px'
})
})
</
script
>
</
script
>
...
...
src/modules/analyze/event/views/Index.vue
浏览文件 @
0611fee6
...
@@ -242,4 +242,9 @@ const eventTimeOption = computed(() => {
...
@@ -242,4 +242,9 @@ const eventTimeOption = computed(() => {
margin-top
:
20px
;
margin-top
:
20px
;
}
}
}
}
@media
(
max-width
:
767px
)
{
.row
{
flex-direction
:
column
;
}
}
</
style
>
</
style
>
src/modules/analyze/label/views/Index.vue
浏览文件 @
0611fee6
...
@@ -315,4 +315,9 @@ const groupMemberTopOption = computed(() => {
...
@@ -315,4 +315,9 @@ const groupMemberTopOption = computed(() => {
margin-top
:
20px
;
margin-top
:
20px
;
}
}
}
}
@media
(
max-width
:
767px
)
{
.row
{
flex-direction
:
column
;
}
}
</
style
>
</
style
>
src/modules/analyze/marketing/views/Index.vue
浏览文件 @
0611fee6
...
@@ -39,7 +39,12 @@ async function fetchEventAction() {
...
@@ -39,7 +39,12 @@ async function fetchEventAction() {
if
(
!
userValue
.
value
||
!
eventValue
.
value
||
!
startDate
||
!
endDate
)
return
if
(
!
userValue
.
value
||
!
eventValue
.
value
||
!
startDate
||
!
endDate
)
return
loading1
.
value
=
true
loading1
.
value
=
true
try
{
try
{
const
res
=
await
api
.
getEventAction
({
sso_id
:
userValue
.
value
,
start_date
:
startDate
,
end_date
:
endDate
,
event_id
:
eventValue
.
value
})
const
res
=
await
api
.
getEventAction
({
sso_id
:
userValue
.
value
,
start_date
:
startDate
,
end_date
:
endDate
,
event_id
:
eventValue
.
value
,
})
eventAction
.
value
=
res
.
data
eventAction
.
value
=
res
.
data
}
finally
{
}
finally
{
loading1
.
value
=
false
loading1
.
value
=
false
...
@@ -52,14 +57,14 @@ const eventActionOption = computed(() => {
...
@@ -52,14 +57,14 @@ const eventActionOption = computed(() => {
tooltip
:
{
trigger
:
'axis'
},
tooltip
:
{
trigger
:
'axis'
},
legend
:
{
legend
:
{
bottom
:
'10'
,
bottom
:
'10'
,
data
:
[
'行为数量'
,
'用户数量'
]
data
:
[
'行为数量'
,
'用户数量'
]
,
},
},
xAxis
:
{
xAxis
:
{
type
:
'category'
,
type
:
'category'
,
boundaryGap
:
[
'20%'
,
'20%'
],
boundaryGap
:
[
'20%'
,
'20%'
],
data
:
eventAction
.
value
.
event_action_items
.
map
(
item
=>
{
data
:
eventAction
.
value
.
event_action_items
.
map
(
(
item
)
=>
{
return
item
.
group_name
return
item
.
group_name
})
})
,
},
},
yAxis
:
{
type
:
'value'
},
yAxis
:
{
type
:
'value'
},
series
:
[
series
:
[
...
@@ -68,16 +73,16 @@ const eventActionOption = computed(() => {
...
@@ -68,16 +73,16 @@ const eventActionOption = computed(() => {
type
:
'line'
,
type
:
'line'
,
smooth
:
true
,
smooth
:
true
,
label
:
{
show
:
true
,
position
:
'top'
},
label
:
{
show
:
true
,
position
:
'top'
},
data
:
eventAction
.
value
.
event_action_items
.
map
(
item
=>
item
.
total
)
data
:
eventAction
.
value
.
event_action_items
.
map
(
(
item
)
=>
item
.
total
),
},
},
{
{
name
:
'用户数量'
,
name
:
'用户数量'
,
type
:
'line'
,
type
:
'line'
,
smooth
:
true
,
smooth
:
true
,
label
:
{
show
:
true
,
position
:
'top'
},
label
:
{
show
:
true
,
position
:
'top'
},
data
:
eventAction
.
value
.
event_member_items
.
map
(
item
=>
item
.
total
)
data
:
eventAction
.
value
.
event_member_items
.
map
(
(
item
)
=>
item
.
total
),
}
}
,
]
]
,
}
}
})
})
...
@@ -123,7 +128,11 @@ async function fetchUser() {
...
@@ -123,7 +128,11 @@ async function fetchUser() {
if
(
!
userValue
.
value
||
!
userStartDate
.
value
||
!
userEndDate
.
value
)
return
if
(
!
userValue
.
value
||
!
userStartDate
.
value
||
!
userEndDate
.
value
)
return
loading3
.
value
=
true
loading3
.
value
=
true
try
{
try
{
const
res
=
await
api
.
getMemberList
({
sso_id
:
userValue
.
value
,
start_date
:
userStartDate
.
value
,
end_date
:
userEndDate
.
value
})
const
res
=
await
api
.
getMemberList
({
sso_id
:
userValue
.
value
,
start_date
:
userStartDate
.
value
,
end_date
:
userEndDate
.
value
,
})
user
.
value
=
res
.
data
.
items
user
.
value
=
res
.
data
.
items
}
finally
{
}
finally
{
loading3
.
value
=
false
loading3
.
value
=
false
...
@@ -149,7 +158,7 @@ function format(date) {
...
@@ -149,7 +158,7 @@ function format(date) {
</el-form-item>
</el-form-item>
</el-form>
</el-form>
<el-divider
/>
<el-divider
/>
<el-row
:gutter=
"20"
>
<el-row
:gutter=
"20"
class=
"main-row"
>
<el-col
:span=
"16"
>
<el-col
:span=
"16"
>
<ChartCard
title=
"事件行为分析"
:options=
"eventActionOption"
:loading=
"loading1"
>
<ChartCard
title=
"事件行为分析"
:options=
"eventActionOption"
:loading=
"loading1"
>
<template
#
tools
>
<template
#
tools
>
...
@@ -326,3 +335,28 @@ function format(date) {
...
@@ -326,3 +335,28 @@ function format(date) {
color
:
var
(
--
main-color
);
color
:
var
(
--
main-color
);
}
}
</
style
>
</
style
>
<
style
lang=
"scss"
>
@media
(
max-width
:
767px
)
{
.main-row
.el-col
{
max-width
:
100%
!
important
;
width
:
100%
!
important
;
flex
:
0
0
100%
!
important
;
}
.el-form--inline
.el-form-item
{
width
:
100%
;
margin-right
:
0
;
}
.chart-card
.tools
{
flex-wrap
:
wrap
;
gap
:
6px
;
}
.chart-card
.el-date-editor
,
.chart-card
.el-select
{
width
:
100%
!
important
;
}
.el-table
{
min-width
:
600px
;
}
}
</
style
>
src/modules/analyze/user/views/Index.vue
浏览文件 @
0611fee6
...
@@ -236,4 +236,9 @@ const statusOption = computed(() => {
...
@@ -236,4 +236,9 @@ const statusOption = computed(() => {
margin-top
:
20px
;
margin-top
:
20px
;
}
}
}
}
@media
(
max-width
:
767px
)
{
.row
{
flex-direction
:
column
;
}
}
</
style
>
</
style
>
src/modules/connect/components/StepOne.vue
浏览文件 @
0611fee6
...
@@ -63,4 +63,10 @@ function handleChange(item: PlatformItem) {
...
@@ -63,4 +63,10 @@ function handleChange(item: PlatformItem) {
box-shadow
:
2px
2px
10px
0px
rgba
(
0
,
0
,
0
,
0
.2
);
box-shadow
:
2px
2px
10px
0px
rgba
(
0
,
0
,
0
,
0
.2
);
}
}
}
}
@media
(
max-width
:
767px
)
{
.connect-from_icon__box
{
grid-template-columns
:
repeat
(
2
,
1fr
);
row-gap
:
12px
;
}
}
</
style
>
</
style
>
src/modules/connect/components/StudentFollowDialog.vue
浏览文件 @
0611fee6
...
@@ -302,4 +302,9 @@ const sendChat = function () {
...
@@ -302,4 +302,9 @@ const sendChat = function () {
}
}
}
}
}
}
@media
(
max-width
:
767px
)
{
.step1-btn
{
padding
:
20px
0
!
important
;
}
}
</
style
>
</
style
>
src/modules/connect/views/Index.vue
浏览文件 @
0611fee6
...
@@ -170,9 +170,11 @@ const handleStudentFollow = function (experimentId: string, id: string, type: st
...
@@ -170,9 +170,11 @@ const handleStudentFollow = function (experimentId: string, id: string, type: st
grid-template-columns
:
repeat
(
5
,
1fr
);
grid-template-columns
:
repeat
(
5
,
1fr
);
gap
:
20px
;
gap
:
20px
;
padding
:
20px
;
padding
:
20px
;
// background-color: #efefef;
border-radius
:
5px
;
border-radius
:
5px
;
}
}
@media
(
max-width
:
1200px
)
{
.connect-list
{
grid-template-columns
:
repeat
(
4
,
1fr
);
}
}
@media
(
max-width
:
992px
)
{
.connect-list
{
grid-template-columns
:
repeat
(
3
,
1fr
);
}
}
@media
(
max-width
:
640px
)
{
.connect-list
{
grid-template-columns
:
repeat
(
2
,
1fr
);
gap
:
12px
;
padding
:
12px
;
}
}
.connect-add-button
{
.connect-add-button
{
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
...
...
src/modules/connect/views/View.vue
浏览文件 @
0611fee6
...
@@ -679,4 +679,20 @@ const surveyKingDialogVisible = ref<boolean>(false)
...
@@ -679,4 +679,20 @@ const surveyKingDialogVisible = ref<boolean>(false)
.tabs-box
{
.tabs-box
{
margin-bottom
:
20px
;
margin-bottom
:
20px
;
}
}
@media
(
max-width
:
767px
)
{
.view-info
{
flex-direction
:
column
;
align-items
:
center
;
text-align
:
center
;
.view-info_content
{
margin-left
:
0
;
margin-top
:
12px
;
flex-direction
:
column
;
p
{
margin-right
:
0
;
margin-bottom
:
6px
;
}
}
}
.tag
,
.tag-null
{
width
:
100%
;
}
}
</
style
>
</
style
>
src/modules/home/views/Index.vue
浏览文件 @
0611fee6
...
@@ -364,6 +364,7 @@ onMounted(() => {
...
@@ -364,6 +364,7 @@ onMounted(() => {
flex-direction
:
column
;
flex-direction
:
column
;
.row
{
.row
{
flex
:
1
;
flex
:
1
;
gap
:
10px
;
}
}
}
}
.card
{
.card
{
...
@@ -381,6 +382,28 @@ onMounted(() => {
...
@@ -381,6 +382,28 @@ onMounted(() => {
::v-deep
(
.chart-card
)
{
::v-deep
(
.chart-card
)
{
background-color
:
#fff
;
background-color
:
#fff
;
}
}
@media
(
max-width
:
767px
)
{
>
.row
{
flex-direction
:
column
;
}
.row
{
flex-wrap
:
wrap
;
.col
{
width
:
100%
;
.row
{
flex-wrap
:
wrap
;
.card
{
flex
:
0
0
calc
(
50%
-
5px
);
p
{
line-height
:
60px
;
font-size
:
20px
;
}
}
}
}
}
}
}
}
.content-user
{
.content-user
{
background
:
#efefef
;
background
:
#efefef
;
...
...
src/modules/label/components/LabelTypeFormDialog.vue
浏览文件 @
0611fee6
...
@@ -112,4 +112,9 @@ function handleUpdate() {
...
@@ -112,4 +112,9 @@ function handleUpdate() {
box-shadow
:
rgb
(
0
0
0
/
40%
)
0px
2px
6px
0px
;
box-shadow
:
rgb
(
0
0
0
/
40%
)
0px
2px
6px
0px
;
}
}
}
}
@media
(
max-width
:
767px
)
{
.label-type-icon-list
{
grid-template-columns
:
repeat
(
4
,
50px
);
}
}
</
style
>
</
style
>
src/modules/label/views/Index.vue
浏览文件 @
0611fee6
...
@@ -237,4 +237,21 @@ const handleRemoves = async function () {
...
@@ -237,4 +237,21 @@ const handleRemoves = async function () {
overflow-x
:
hidden
;
overflow-x
:
hidden
;
overflow-y
:
auto
;
overflow-y
:
auto
;
}
}
@media
(
max-width
:
767px
)
{
.label-wrap
{
flex-direction
:
column
;
height
:
auto
;
min-height
:
calc
(
100vh
-
130px
);
}
.label-left
{
flex
:
none
;
width
:
100%
;
padding-right
:
0
;
margin-right
:
0
;
border-right
:
none
;
border-bottom
:
1px
solid
rgb
(
187
,
187
,
187
);
padding-bottom
:
12px
;
margin-bottom
:
12px
;
}
}
</
style
>
</
style
>
src/modules/live/order/views/Index.vue
浏览文件 @
0611fee6
...
@@ -23,7 +23,7 @@ const listOptions = computed(() => {
...
@@ -23,7 +23,7 @@ const listOptions = computed(() => {
},
},
filters
:
[
filters
:
[
{
label
:
'直播主题品类'
,
prop
:
'live_commodity_type_id'
,
slots
:
'filter-category'
},
{
label
:
'直播主题品类'
,
prop
:
'live_commodity_type_id'
,
slots
:
'filter-category'
},
{
label
:
'直播主题名称'
,
prop
:
'live_commodity_title'
,
type
:
'input'
},
{
label
:
'直播主题名称'
,
prop
:
'live_commodity_title'
,
type
:
'input'
,
placeholder
:
'请输入直播主题名称'
},
],
],
columns
:
[
columns
:
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
...
@@ -35,18 +35,17 @@ const listOptions = computed(() => {
...
@@ -35,18 +35,17 @@ const listOptions = computed(() => {
try
{
try
{
const
info
=
JSON
.
parse
(
row
.
commodity_info
)
const
info
=
JSON
.
parse
(
row
.
commodity_info
)
const
[
picture
]
=
JSON
.
parse
(
info
.
picture_addreses
)
||
[]
const
[
picture
]
=
JSON
.
parse
(
info
.
picture_addreses
)
||
[]
return
`<div style="display:
flex; align-items: center; gap: 10px;"><img src="
${
picture
.
url
}
" width="100"
/>
${
info
.
title
}
</div>`
return
`<div style="display:
flex;align-items:center;gap:10px"><img src="
${
picture
.
url
}
" width="80" style="border-radius:4px"
/>
${
info
.
title
}
</div>`
}
catch
(
e
)
{
}
catch
{
console
.
log
(
e
)
return
'--'
}
}
return
'--'
},
},
},
},
{
{
label
:
'单价/数量'
,
label
:
'单价/数量'
,
prop
:
'num'
,
prop
:
'num'
,
computed
({
row
})
{
computed
({
row
})
{
return
`¥
${
row
.
price
}
<br/>x
${
row
.
num
}
`
return
`¥
${
row
.
price
}
×
${
row
.
num
}
`
},
},
},
},
{
label
:
'订单编号'
,
prop
:
'id'
},
{
label
:
'订单编号'
,
prop
:
'id'
},
...
@@ -67,7 +66,10 @@ const listOptions = computed(() => {
...
@@ -67,7 +66,10 @@ const listOptions = computed(() => {
<AppCard
title=
"订单管理"
>
<AppCard
title=
"订单管理"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
filter-category
>
<template
#
filter-category
>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
></LiveProductCategory>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
placeholder=
"请选择直播主题品类"
></LiveProductCategory>
</
template
>
</
template
>
</AppList>
</AppList>
</AppCard>
</AppCard>
...
...
src/modules/live/product/attr/views/Index.vue
浏览文件 @
0611fee6
...
@@ -37,26 +37,14 @@ const listOptions = computed(() => {
...
@@ -37,26 +37,14 @@ const listOptions = computed(() => {
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'商品属性名称'
,
prop
:
'name'
},
{
label
:
'商品属性名称'
,
prop
:
'name'
},
{
label
:
'所属商品品类'
,
prop
:
'live_commodity_type_full_name'
},
{
label
:
'所属商品品类'
,
prop
:
'live_commodity_type_full_name'
},
{
{
label
:
'重要性'
,
prop
:
'is_importance'
,
computed
:
({
row
})
=>
getNameByValue
(
row
.
is_importance
,
importType
)
},
label
:
'重要性'
,
{
label
:
'必要性'
,
prop
:
'is_essential'
,
computed
:
({
row
})
=>
getNameByValue
(
row
.
is_essential
,
requiredType
)
},
prop
:
'is_importance'
,
computed
({
row
})
{
return
getNameByValue
(
row
.
is_importance
,
importType
)
},
},
{
label
:
'必要性'
,
prop
:
'is_essential'
,
computed
({
row
})
{
return
getNameByValue
(
row
.
is_essential
,
requiredType
)
},
},
{
{
label
:
'状态'
,
label
:
'状态'
,
prop
:
'status'
,
prop
:
'status'
,
computed
({
row
})
{
computed
:
({
row
})
=>
{
const
color
=
row
.
status
===
'1'
?
'var(--main-success-color)'
:
'var(--main-color)'
const
color
=
row
.
status
===
'1'
?
'var(--main-success-color)'
:
'var(--main-color)'
return
`<span style="color:
${
color
}
">
${
getNameByValue
(
row
.
status
,
statusList
)}
</span>`
return
`<span style="color:
${
color
}
">
${
getNameByValue
(
row
.
status
,
statusList
)}
</span>`
},
},
},
},
{
label
:
'创建人'
,
prop
:
'created_operator'
,
computed
:
({
row
})
=>
getOperatorName
(
row
.
created_operator
)
},
{
label
:
'创建人'
,
prop
:
'created_operator'
,
computed
:
({
row
})
=>
getOperatorName
(
row
.
created_operator
)
},
...
@@ -65,6 +53,7 @@ const listOptions = computed(() => {
...
@@ -65,6 +53,7 @@ const listOptions = computed(() => {
],
],
}
}
})
})
const
action
=
ref
(
null
)
const
action
=
ref
(
null
)
const
formVisible
=
ref
(
false
)
const
formVisible
=
ref
(
false
)
const
currentRow
=
ref
(
null
)
const
currentRow
=
ref
(
null
)
...
@@ -99,11 +88,12 @@ const handleRemove = async (row) => {
...
@@ -99,11 +88,12 @@ const handleRemove = async (row) => {
<
template
>
<
template
>
<AppCard
title=
"商品属性管理"
>
<AppCard
title=
"商品属性管理"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
header-buttons
>
<template
#
header-buttons
><el-button
type=
"primary"
@
click=
"handleAdd"
>
新增商品属性
</el-button></
template
>
<el-button
type=
"primary"
@
click=
"handleAdd"
>
新增商品属性
</el-button>
</
template
>
<
template
#
filter-category
>
<
template
#
filter-category
>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
></LiveProductCategory>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
placeholder=
"请选择商品品类"
></LiveProductCategory>
</
template
>
</
template
>
<
template
#
table-x=
"{ row }"
>
<
template
#
table-x=
"{ row }"
>
<el-button
text
type=
"primary"
@
click=
"handleView(row)"
>
查看
</el-button>
<el-button
text
type=
"primary"
@
click=
"handleView(row)"
>
查看
</el-button>
...
@@ -112,6 +102,5 @@ const handleRemove = async (row) => {
...
@@ -112,6 +102,5 @@ const handleRemove = async (row) => {
</
template
>
</
template
>
</AppList>
</AppList>
</AppCard>
</AppCard>
<!-- 新建/修改 -->
<FormDialog
v-model=
"formVisible"
:action=
"action"
:data=
"currentRow"
@
update=
"handleRefresh"
v-if=
"formVisible"
/>
<FormDialog
v-model=
"formVisible"
:action=
"action"
:data=
"currentRow"
@
update=
"handleRefresh"
v-if=
"formVisible"
/>
</template>
</template>
src/modules/live/product/category/views/Index.vue
浏览文件 @
0611fee6
...
@@ -67,7 +67,7 @@ const handleRemove = async (row) => {
...
@@ -67,7 +67,7 @@ const handleRemove = async (row) => {
<
template
>
<
template
>
<AppCard
title=
"商品品类管理"
>
<AppCard
title=
"商品品类管理"
>
<AppList
v-bind=
"listOptions"
row-key=
"id"
ref=
"appList"
>
<AppList
v-bind=
"listOptions"
row-key=
"id"
ref=
"appList"
:mobile-cards=
"false"
>
<template
#
header-buttons
>
<template
#
header-buttons
>
<el-button
type=
"primary"
@
click=
"handleAdd()"
>
新增类别
</el-button>
<el-button
type=
"primary"
@
click=
"handleAdd()"
>
新增类别
</el-button>
</
template
>
</
template
>
...
...
src/modules/live/product/management/components/FormBaseInfo.vue
浏览文件 @
0611fee6
...
@@ -105,7 +105,7 @@ const unimportanceTotal = computed(() => {
...
@@ -105,7 +105,7 @@ const unimportanceTotal = computed(() => {
<div>
<div>
<el-form-item
label=
"商品标题"
prop=
"title"
:rules=
"[
{ required: true, message: '请输入', trigger: 'blur' }]">
<el-form-item
label=
"商品标题"
prop=
"title"
:rules=
"[
{ required: true, message: '请输入', trigger: 'blur' }]">
<div
class=
"form-tips"
>
标题不规范会有可能引起商品下架,影响您的正常销售,请点击学习商品发布规范认真填写
</div>
<div
class=
"form-tips"
>
标题不规范会有可能引起商品下架,影响您的正常销售,请点击学习商品发布规范认真填写
</div>
<div
style=
"display: flex; width: 100%; align-items: center; gap: 20px
"
>
<div
class=
"form-inline-row
"
>
<el-input
<el-input
placeholder=
"至少输入8个字(16个字符)以上,30个字(60个字符)以下"
placeholder=
"至少输入8个字(16个字符)以上,30个字(60个字符)以下"
size=
"large"
size=
"large"
...
@@ -115,12 +115,11 @@ const unimportanceTotal = computed(() => {
...
@@ -115,12 +115,11 @@ const unimportanceTotal = computed(() => {
</el-form-item>
</el-form-item>
<el-form-item
label=
"导购短标题"
prop=
"shopping_guide_short_title"
>
<el-form-item
label=
"导购短标题"
prop=
"shopping_guide_short_title"
>
<div
class=
"form-tips"
>
短标题可用于商品搜索、首页推荐、物流单等场景,请提炼商品关键信息,客观准确填写
</div>
<div
class=
"form-tips"
>
短标题可用于商品搜索、首页推荐、物流单等场景,请提炼商品关键信息,客观准确填写
</div>
<div
style=
"display: flex; width: 100%; align-items: center; gap: 20px
"
>
<div
class=
"form-inline-row
"
>
<el-input
<el-input
placeholder=
"建议填写简明准确的标题内容,避免重复表达"
placeholder=
"建议填写简明准确的标题内容,避免重复表达"
size=
"large"
size=
"large"
v-model=
"form.shopping_guide_short_title"
v-model=
"form.shopping_guide_short_title"
/>
style=
"flex: 1"
/>
<el-button
type=
"primary"
plain
@
click=
"handleAIGenerate"
:loading=
"descLoading"
>
一键智能推荐
</el-button>
<el-button
type=
"primary"
plain
@
click=
"handleAIGenerate"
:loading=
"descLoading"
>
一键智能推荐
</el-button>
</div>
</div>
</el-form-item>
</el-form-item>
...
@@ -129,14 +128,11 @@ const unimportanceTotal = computed(() => {
...
@@ -129,14 +128,11 @@ const unimportanceTotal = computed(() => {
prop="live_commodity_attrs.importance_attrs">
prop="live_commodity_attrs.importance_attrs">
<div
class=
"form-tips"
>
错误填写属性,会引起商品下架,请认真准确填写。
</div>
<div
class=
"form-tips"
>
错误填写属性,会引起商品下架,请认真准确填写。
</div>
<div
style=
"display: flex; flex-direction: column; gap: 16px"
>
<div
style=
"display: flex; flex-direction: column; gap: 16px"
>
<div
<div
v-for=
"(item, index) in form.live_commodity_attrs.importance_attrs"
:key=
"index"
class=
"attr-row"
>
v-for=
"(item, index) in form.live_commodity_attrs.importance_attrs"
:key=
"index"
style=
"display: flex; align-items: flex-start; gap: 12px"
>
<el-select
<el-select
v-model=
"item.id"
v-model=
"item.id"
placeholder=
"请选择属性"
placeholder=
"请选择属性"
style=
"width: 200px
"
class=
"attr-select
"
@
change=
"(value) => handleAttrSelect(value, item, 'importance_attrs')"
>
@
change=
"(value) => handleAttrSelect(value, item, 'importance_attrs')"
>
<el-option
<el-option
v-for=
"attr in getAvailableAttrs('importance_attrs', item.id)"
v-for=
"attr in getAvailableAttrs('importance_attrs', item.id)"
...
@@ -145,7 +141,7 @@ const unimportanceTotal = computed(() => {
...
@@ -145,7 +141,7 @@ const unimportanceTotal = computed(() => {
:value=
"attr.id"
>
:value=
"attr.id"
>
</el-option>
</el-option>
</el-select>
</el-select>
<el-input
v-model=
"item.value"
placeholder=
"请输入属性值"
style=
"flex: 1; max-width: 300px"
>
</el-input>
<el-input
v-model=
"item.value"
placeholder=
"请输入属性值"
class=
"attr-value"
>
</el-input>
<el-button
type=
"danger"
plain
:icon=
"Delete"
circle
@
click=
"removeAttrItem('importance_attrs', index)"
>
<el-button
type=
"danger"
plain
:icon=
"Delete"
circle
@
click=
"removeAttrItem('importance_attrs', index)"
>
</el-button>
</el-button>
</div>
</div>
...
@@ -156,14 +152,11 @@ const unimportanceTotal = computed(() => {
...
@@ -156,14 +152,11 @@ const unimportanceTotal = computed(() => {
:label=
"`非重要属性 $
{unimportanceTotal}/${attrs.unimportance_attrs.total}`"
:label=
"`非重要属性 $
{unimportanceTotal}/${attrs.unimportance_attrs.total}`"
prop="live_commodity_attrs.unimportance_attrs">
prop="live_commodity_attrs.unimportance_attrs">
<div
style=
"display: flex; flex-direction: column; gap: 16px"
>
<div
style=
"display: flex; flex-direction: column; gap: 16px"
>
<div
<div
v-for=
"(item, index) in form.live_commodity_attrs.unimportance_attrs"
:key=
"index"
class=
"attr-row"
>
v-for=
"(item, index) in form.live_commodity_attrs.unimportance_attrs"
:key=
"index"
style=
"display: flex; align-items: flex-start; gap: 12px"
>
<el-select
<el-select
v-model=
"item.id"
v-model=
"item.id"
placeholder=
"请选择属性"
placeholder=
"请选择属性"
style=
"width: 200px
"
class=
"attr-select
"
@
change=
"(value) => handleAttrSelect(value, item, 'unimportance_attrs')"
>
@
change=
"(value) => handleAttrSelect(value, item, 'unimportance_attrs')"
>
<el-option
<el-option
v-for=
"attr in getAvailableAttrs('unimportance_attrs', item.id)"
v-for=
"attr in getAvailableAttrs('unimportance_attrs', item.id)"
...
@@ -172,7 +165,7 @@ const unimportanceTotal = computed(() => {
...
@@ -172,7 +165,7 @@ const unimportanceTotal = computed(() => {
:value=
"attr.id"
>
:value=
"attr.id"
>
</el-option>
</el-option>
</el-select>
</el-select>
<el-input
v-model=
"item.value"
placeholder=
"请输入属性值"
style=
"flex: 1; max-width: 300px"
>
</el-input>
<el-input
v-model=
"item.value"
placeholder=
"请输入属性值"
class=
"attr-value"
>
</el-input>
<el-button
type=
"danger"
plain
:icon=
"Delete"
circle
@
click=
"removeAttrItem('unimportance_attrs', index)"
>
<el-button
type=
"danger"
plain
:icon=
"Delete"
circle
@
click=
"removeAttrItem('unimportance_attrs', index)"
>
</el-button>
</el-button>
</div>
</div>
...
@@ -181,3 +174,36 @@ const unimportanceTotal = computed(() => {
...
@@ -181,3 +174,36 @@ const unimportanceTotal = computed(() => {
</el-form-item>
</el-form-item>
</div>
</div>
</
template
>
</
template
>
<
style
scoped
>
.form-inline-row
{
display
:
flex
;
width
:
100%
;
align-items
:
center
;
gap
:
12px
;
.el-input
{
flex
:
1
;
}
}
.attr-row
{
display
:
flex
;
align-items
:
flex-start
;
gap
:
12px
;
}
.attr-select
{
width
:
200px
;
flex-shrink
:
0
;
}
.attr-value
{
flex
:
1
;
}
@media
(
max-width
:
767px
)
{
.form-inline-row
{
flex-direction
:
column
;
align-items
:
stretch
;
.el-button
{
width
:
100%
;
}
}
.attr-row
{
flex-direction
:
column
;
align-items
:
stretch
;
}
.attr-select
{
width
:
100%
;
}
.attr-value
{
max-width
:
none
;
}
}
</
style
>
src/modules/live/product/management/components/FormCategory.vue
浏览文件 @
0611fee6
...
@@ -57,23 +57,24 @@ const handleSelect = (item) => {
...
@@ -57,23 +57,24 @@ const handleSelect = (item) => {
<span
@
click=
"form.live_commodity_type_id = item.id"
>
{{
item
.
name
}}
</span>
<span
@
click=
"form.live_commodity_type_id = item.id"
>
{{
item
.
name
}}
</span>
</
template
>
</
template
>
</p>
</p>
<el-cascader-panel
<div
class=
"cascader-wrap"
>
v-model=
"form.live_commodity_type_id"
<el-cascader-panel
filterable
v-model=
"form.live_commodity_type_id"
clearable
filterable
placeholder=
"请输入关键词搜索商品分类"
clearable
size=
"large"
placeholder=
"请输入关键词搜索商品分类"
:options=
"options"
size=
"large"
:props=
"{
:options=
"options"
label: 'name',
:props=
"{
value: 'id',
label: 'name',
emitPath: false,
value: 'id',
expandTrigger: 'hover',
emitPath: false,
checkStrictly: true,
expandTrigger: 'click',
checkOnClickNode: true,
checkStrictly: true,
showPrefix: false,
checkOnClickNode: true,
}"
showPrefix: false,
style=
"width: 100%"
/>
}"
/>
</div>
</el-form-item>
</el-form-item>
</div>
</div>
</template>
</template>
...
@@ -90,4 +91,12 @@ const handleSelect = (item) => {
...
@@ -90,4 +91,12 @@ const handleSelect = (item) => {
}
}
}
}
}
}
.cascader-wrap
{
width
:
100%
;
overflow-x
:
auto
;
-webkit-overflow-scrolling
:
touch
;
.el-cascader-panel
{
display
:
inline-flex
;
}
}
</
style
>
</
style
>
src/modules/live/product/management/components/FormGraphicInfo.vue
浏览文件 @
0611fee6
...
@@ -28,7 +28,7 @@ const handleCopy = () => {
...
@@ -28,7 +28,7 @@ const handleCopy = () => {
<el-form-item
label=
""
>
<el-form-item
label=
""
>
<template
#
label
>
<template
#
label
>
<span>
主图3:4
</span>
<span>
主图3:4
</span>
<el-button
type=
"primary"
plain
size=
"small"
style=
"margin-left: 430px
"
@
click=
"handleCopy"
<el-button
type=
"primary"
plain
size=
"small"
class=
"copy-btn
"
@
click=
"handleCopy"
>
从主图一键填入
</el-button
>
从主图一键填入
</el-button
>
>
</
template
>
</
template
>
...
@@ -68,4 +68,14 @@ const handleCopy = () => {
...
@@ -68,4 +68,14 @@ const handleCopy = () => {
color
:
#999
;
color
:
#999
;
line-height
:
24px
;
line-height
:
24px
;
}
}
.copy-btn
{
margin-left
:
430px
;
}
@media
(
max-width
:
767px
)
{
.copy-btn
{
margin-left
:
0
;
margin-top
:
8px
;
width
:
100%
;
}
}
</
style
>
</
style
>
src/modules/live/product/management/components/FormPrice.vue
浏览文件 @
0611fee6
...
@@ -313,6 +313,7 @@ function batchSetReferencePrice() {
...
@@ -313,6 +313,7 @@ function batchSetReferencePrice() {
</el-button>
</el-button>
</div>
</div>
</div>
</div>
<div
class=
"sku-table"
>
<el-table
:data=
"form.info.sku"
border
:header-cell-style=
"{ backgroundColor: '#f5f7fa' }"
style=
"width: 100%"
:row-key=
"Date.now() + Math.random()"
>
<el-table
:data=
"form.info.sku"
border
:header-cell-style=
"{ backgroundColor: '#f5f7fa' }"
style=
"width: 100%"
:row-key=
"Date.now() + Math.random()"
>
<el-table-column
v-if=
"hasSpecs"
label=
"规格组合"
align=
"center"
width=
"200"
column-key=
"specs"
>
<el-table-column
v-if=
"hasSpecs"
label=
"规格组合"
align=
"center"
width=
"200"
column-key=
"specs"
>
<
template
#
default=
"{ row }"
>
<
template
#
default=
"{ row }"
>
...
@@ -341,6 +342,7 @@ function batchSetReferencePrice() {
...
@@ -341,6 +342,7 @@ function batchSetReferencePrice() {
</template>
</template>
</el-table-column>
</el-table-column>
</el-table>
</el-table>
</div>
</el-form-item>
</el-form-item>
<el-form-item
label=
"参考价"
prop=
"info.reference_price"
v-if=
"false"
>
<el-form-item
label=
"参考价"
prop=
"info.reference_price"
v-if=
"false"
>
<
template
#
label
>
<
template
#
label
>
...
@@ -362,7 +364,7 @@ function batchSetReferencePrice() {
...
@@ -362,7 +364,7 @@ function batchSetReferencePrice() {
</div>
</div>
</template>
</template>
<
style
scoped
>
<
style
lang=
"scss"
scoped
>
.spec-list
{
.spec-list
{
display
:
flex
;
display
:
flex
;
flex-wrap
:
wrap
;
flex-wrap
:
wrap
;
...
@@ -433,5 +435,20 @@ function batchSetReferencePrice() {
...
@@ -433,5 +435,20 @@ function batchSetReferencePrice() {
.batch-set-item
.el-input
{
.batch-set-item
.el-input
{
flex
:
1
;
flex
:
1
;
}
}
// SKU 表格横向滚动
.sku-table
{
overflow-x
:
auto
;
-webkit-overflow-scrolling
:
touch
;
.el-table
{
min-width
:
600px
;
}
}
// 参考价区域
.reference-price-row
{
flex-direction
:
column
;
align-items
:
stretch
!
important
;
}
}
}
</
style
>
</
style
>
src/modules/live/product/management/components/FormService.vue
浏览文件 @
0611fee6
...
@@ -6,12 +6,12 @@ const form = inject('form')
...
@@ -6,12 +6,12 @@ const form = inject('form')
<
template
>
<
template
>
<div>
<div>
<el-form-item
label=
"运费模板"
prop=
"info.shipping_template"
:rules=
"[
{ required: true, message: '请选择' }]">
<el-form-item
label=
"运费模板"
prop=
"info.shipping_template"
:rules=
"[
{ required: true, message: '请选择' }]">
<el-select
v-model=
"form.info.shipping_template"
style=
"width: 300px"
>
<el-select
v-model=
"form.info.shipping_template"
style=
"width: 300px
; max-width: 100%
"
>
<el-option
v-for=
"item in shippingTemplate"
:key=
"item.value"
v-bind=
"item"
></el-option>
<el-option
v-for=
"item in shippingTemplate"
:key=
"item.value"
v-bind=
"item"
></el-option>
</el-select>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item
label=
"售后政策"
prop=
"info.after_sales_policy"
:rules=
"[
{ required: true, message: '请选择' }]">
<el-form-item
label=
"售后政策"
prop=
"info.after_sales_policy"
:rules=
"[
{ required: true, message: '请选择' }]">
<el-select
v-model=
"form.info.after_sales_policy"
style=
"width: 300px"
multiple
>
<el-select
v-model=
"form.info.after_sales_policy"
style=
"width: 300px
; max-width: 100%
"
multiple
>
<el-option
v-for=
"item in afterSalesPolicy"
:key=
"item.value"
v-bind=
"item"
></el-option>
<el-option
v-for=
"item in afterSalesPolicy"
:key=
"item.value"
v-bind=
"item"
></el-option>
</el-select>
</el-select>
</el-form-item>
</el-form-item>
...
...
src/modules/live/product/management/components/ImageDesign.vue
浏览文件 @
0611fee6
...
@@ -2,6 +2,9 @@
...
@@ -2,6 +2,9 @@
import
{
getChuanKitDesignList
}
from
'../api'
import
{
getChuanKitDesignList
}
from
'../api'
import
{
useUserStore
}
from
'@/stores/user'
import
{
useUserStore
}
from
'@/stores/user'
import
{
uploadFileByUrl
}
from
'@/utils/upload'
import
{
uploadFileByUrl
}
from
'@/utils/upload'
import
{
useMediaQuery
}
from
'@vueuse/core'
const
isMobile
=
useMediaQuery
(
'(max-width: 767px)'
)
const
ChuangKitDesign
=
defineAsyncComponent
(()
=>
import
(
'@/components/ChuangKitDesign.vue'
))
const
ChuangKitDesign
=
defineAsyncComponent
(()
=>
import
(
'@/components/ChuangKitDesign.vue'
))
...
@@ -71,7 +74,7 @@ async function handleSubmit() {
...
@@ -71,7 +74,7 @@ async function handleSubmit() {
</
script
>
</
script
>
<
template
>
<
template
>
<el-dialog
title=
"图库选择"
:close-on-click-modal=
"false"
@
closed=
"$emit('update:modelValue', false)"
width=
"860px"
>
<el-dialog
title=
"图库选择"
:close-on-click-modal=
"false"
@
closed=
"$emit('update:modelValue', false)"
:width=
"isMobile ? '95%' : '860px'"
destroy-on-close
>
<div
class=
"image-design"
>
<div
class=
"image-design"
>
<el-button
type=
"primary"
@
click=
"designVisible = true"
v-if=
"false"
>
打开编辑器
</el-button>
<el-button
type=
"primary"
@
click=
"designVisible = true"
v-if=
"false"
>
打开编辑器
</el-button>
<ul>
<ul>
...
@@ -97,10 +100,10 @@ async function handleSubmit() {
...
@@ -97,10 +100,10 @@ async function handleSubmit() {
<
style
lang=
"scss"
>
<
style
lang=
"scss"
>
.image-design
{
.image-design
{
ul
{
ul
{
margin
:
3
0px
auto
;
margin
:
2
0px
auto
;
display
:
flex
;
display
:
flex
;
flex-wrap
:
wrap
;
flex-wrap
:
wrap
;
gap
:
30
px
;
gap
:
16
px
;
}
}
li
{
li
{
width
:
140px
;
width
:
140px
;
...
@@ -117,5 +120,17 @@ async function handleSubmit() {
...
@@ -117,5 +120,17 @@ async function handleSubmit() {
height
:
100%
;
height
:
100%
;
object-fit
:
cover
;
object-fit
:
cover
;
}
}
@media
(
max-width
:
767px
)
{
ul
{
justify-content
:
space-around
;
gap
:
12px
;
}
li
{
width
:
calc
(
33
.33%
-
12px
);
min-width
:
80px
;
border-radius
:
12px
;
}
}
}
}
</
style
>
</
style
>
src/modules/live/product/management/components/Upload.vue
浏览文件 @
0611fee6
...
@@ -92,9 +92,9 @@ const handleRemove = (i) => {
...
@@ -92,9 +92,9 @@ const handleRemove = (i) => {
<div
class=
"upload-wrapper"
>
<div
class=
"upload-wrapper"
>
<template
v-if=
"Array.isArray(props.modelValue)"
>
<template
v-if=
"Array.isArray(props.modelValue)"
>
<div
v-for=
"(item, i) in props.limit"
:key=
"i"
>
<div
v-for=
"(item, i) in props.limit"
:key=
"i"
>
<el-popover
placement=
"top"
width=
"220px"
trigger=
"
hover
"
>
<el-popover
placement=
"top"
width=
"220px"
trigger=
"
click
"
>
<ul
class=
"upload-popover"
>
<ul
class=
"upload-popover"
>
<li
@
click=
"handleOpen(i)"
v-if=
"false"
>
<li
@
click=
"handleOpen(i)"
>
<i
class=
"el-icon"
><UploadFilled
/></i>
本地上传
<i
class=
"el-icon"
><UploadFilled
/></i>
本地上传
</li>
</li>
<li
@
click=
"handleOpenDesign(i)"
v-if=
"!isVideo"
>
<li
@
click=
"handleOpenDesign(i)"
v-if=
"!isVideo"
>
...
@@ -113,7 +113,7 @@ const handleRemove = (i) => {
...
@@ -113,7 +113,7 @@ const handleRemove = (i) => {
<i
class=
"el-icon delete-icon"
@
click
.
stop=
"handleRemove(i)"
><CircleClose
/></i>
<i
class=
"el-icon delete-icon"
@
click
.
stop=
"handleRemove(i)"
><CircleClose
/></i>
</
template
>
</
template
>
<
template
v-else
>
<
template
v-else
>
<div
class=
"upload-item-uploader"
@
click=
"handleOpen(i)"
>
<div
class=
"upload-item-uploader"
>
<div
class=
"upload-item__title"
>
{{
getTitle
(
i
)
}}
</div>
<div
class=
"upload-item__title"
>
{{
getTitle
(
i
)
}}
</div>
<i
class=
"el-icon"
><Plus
/></i>
<i
class=
"el-icon"
><Plus
/></i>
<div
class=
"upload-item__tips"
>
{{
getTips
(
i
)
}}
</div>
<div
class=
"upload-item__tips"
>
{{
getTips
(
i
)
}}
</div>
...
@@ -126,9 +126,9 @@ const handleRemove = (i) => {
...
@@ -126,9 +126,9 @@ const handleRemove = (i) => {
</template>
</template>
<
template
v-else
>
<
template
v-else
>
<el-popover
placement=
"top"
width=
"160px"
trigger=
"
hover
"
>
<el-popover
placement=
"top"
width=
"160px"
trigger=
"
click
"
>
<ul
class=
"upload-popover"
>
<ul
class=
"upload-popover"
>
<li
@
click=
"handleOpen"
v-if=
"false"
>
<li
@
click=
"handleOpen"
>
<i
class=
"el-icon"
><UploadFilled
/></i>
本地上传
<i
class=
"el-icon"
><UploadFilled
/></i>
本地上传
</li>
</li>
<li
@
click=
"handleOpenDesign"
v-if=
"!isVideo"
>
<li
@
click=
"handleOpenDesign"
v-if=
"!isVideo"
>
...
@@ -148,7 +148,7 @@ const handleRemove = (i) => {
...
@@ -148,7 +148,7 @@ const handleRemove = (i) => {
<i
class=
"el-icon delete-icon"
@
click
.
stop=
"handleRemove()"
><CircleClose
/></i>
<i
class=
"el-icon delete-icon"
@
click
.
stop=
"handleRemove()"
><CircleClose
/></i>
</
template
>
</
template
>
<
template
v-else
>
<
template
v-else
>
<div
class=
"upload-item-uploader"
@
click=
"handleOpen"
>
<div
class=
"upload-item-uploader"
>
<div
class=
"upload-item__title"
>
{{
props
.
firstTitle
||
props
.
title
}}
</div>
<div
class=
"upload-item__title"
>
{{
props
.
firstTitle
||
props
.
title
}}
</div>
<i
class=
"el-icon"
><Plus
/></i>
<i
class=
"el-icon"
><Plus
/></i>
<div
class=
"upload-item__tips"
>
{{
props
.
firstTips
||
props
.
tips
}}
</div>
<div
class=
"upload-item__tips"
>
{{
props
.
firstTips
||
props
.
tips
}}
</div>
...
@@ -168,6 +168,10 @@ const handleRemove = (i) => {
...
@@ -168,6 +168,10 @@ const handleRemove = (i) => {
display
:
flex
;
display
:
flex
;
flex-wrap
:
wrap
;
flex-wrap
:
wrap
;
gap
:
20px
;
gap
:
20px
;
@media
(
max-width
:
767px
)
{
gap
:
12px
;
justify-content
:
center
;
}
}
}
.upload-popover
{
.upload-popover
{
display
:
flex
;
display
:
flex
;
...
...
src/modules/live/product/management/views/Index.vue
浏览文件 @
0611fee6
...
@@ -35,7 +35,7 @@ const listOptions = computed(() => {
...
@@ -35,7 +35,7 @@ const listOptions = computed(() => {
},
},
filters
:
[
filters
:
[
{
label
:
'商品品类'
,
prop
:
'live_commodity_type_id'
,
slots
:
'filter-category'
},
{
label
:
'商品品类'
,
prop
:
'live_commodity_type_id'
,
slots
:
'filter-category'
},
{
label
:
'商品名称'
,
prop
:
'title'
,
type
:
'input'
},
{
label
:
'商品名称'
,
prop
:
'title'
,
type
:
'input'
,
placeholder
:
'请输入商品名称'
},
],
],
columns
:
[
columns
:
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
...
@@ -49,6 +49,7 @@ const listOptions = computed(() => {
...
@@ -49,6 +49,7 @@ const listOptions = computed(() => {
}
}
})
})
// 删除
const
handleRemove
=
async
(
row
)
=>
{
const
handleRemove
=
async
(
row
)
=>
{
await
ElMessageBox
.
confirm
(
'此操作将永久删除该数据, 是否继续?'
,
'提示'
)
await
ElMessageBox
.
confirm
(
'此操作将永久删除该数据, 是否继续?'
,
'提示'
)
await
deleteProduct
({
id
:
row
.
id
})
await
deleteProduct
({
id
:
row
.
id
})
...
@@ -61,30 +62,22 @@ const handleRemove = async (row) => {
...
@@ -61,30 +62,22 @@ const handleRemove = async (row) => {
<AppCard
title=
"商品管理"
>
<AppCard
title=
"商品管理"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
header-buttons
>
<template
#
header-buttons
>
<el-button
type=
"primary"
>
<el-button
type=
"primary"
><router-link
to=
"management/add"
>
添加商品
</router-link></el-button>
<router-link
to=
"management/add"
>
添加商品
</router-link>
</el-button>
</
template
>
</
template
>
<
template
#
filter-category
>
<
template
#
filter-category
>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
></LiveProductCategory>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
placeholder=
"请选择商品品类"
></LiveProductCategory>
</
template
>
</
template
>
<
template
#
table-picture=
"{ row }"
>
<
template
#
table-picture=
"{ row }"
>
<el-image
<el-image
fit=
"cover"
preview-teleported
:src=
"row.picture_url"
:previewSrcList=
"row.picture_url_list"
style=
"width:100px;height:100px"
></el-image>
fit=
"cover"
preview-teleported
:src=
"row.picture_url"
:previewSrcList=
"row.picture_url_list"
style=
"width: 100px; height: 100px"
></el-image>
</
template
>
</
template
>
<
template
#
table-x=
"{ row }"
>
<
template
#
table-x=
"{ row }"
>
<el-button
text
type=
"primary"
>
<el-button
text
type=
"primary"
><router-link
:to=
"
{ path: 'management/view', query: { id: row.id } }">查看
</router-link></el-button>
<router-link
:to=
"
{ path: 'management/view', query: { id: row.id } }">查看
</router-link>
<el-button
text
type=
"primary"
><router-link
:to=
"
{ path: 'management/update', query: { id: row.id } }">编辑
</router-link></el-button>
</el-button>
<el-button
text
type=
"primary"
>
<router-link
:to=
"
{ path: 'management/update', query: { id: row.id } }">编辑
</router-link>
</el-button>
<el-button
text
type=
"primary"
@
click=
"handleRemove(row)"
>
删除
</el-button>
<el-button
text
type=
"primary"
@
click=
"handleRemove(row)"
>
删除
</el-button>
</
template
>
</
template
>
</AppList>
</AppList>
</AppCard>
</AppCard>
</template>
</template>
<
style
scoped
>
</
style
>
src/modules/live/product/management/views/Update.vue
浏览文件 @
0611fee6
...
@@ -149,6 +149,26 @@ async function handleUpdate(params) {
...
@@ -149,6 +149,26 @@ async function handleUpdate(params) {
.
el-tabs__nav-wrap
:
:
after
{
.
el-tabs__nav-wrap
:
:
after
{
display
:
none
;
display
:
none
;
}
}
// 移动端 tab 横向滚动
@media
(
max-width
:
767px
)
{
.el-tabs__header
{
width
:
100%
;
}
.el-tabs__nav-wrap
,
.el-tabs__nav-scroll
{
overflow-x
:
auto
;
overflow-y
:
hidden
;
}
.el-tabs__nav
{
display
:
inline-flex
;
flex-wrap
:
nowrap
;
}
.el-tabs__item
{
flex-shrink
:
0
;
font-size
:
13px
;
padding
:
0
8px
;
}
}
}
}
.product
{
.product
{
.el-card
{
.el-card
{
...
@@ -163,5 +183,24 @@ async function handleUpdate(params) {
...
@@ -163,5 +183,24 @@ async function handleUpdate(params) {
line-height
:
22px
;
line-height
:
22px
;
color
:
#92939a
;
color
:
#92939a
;
}
}
@media
(
max-width
:
767px
)
{
.form-tips
{
position
:
static
;
margin-bottom
:
8px
;
}
.el-row
[
style
*=
"margin: 100px"
]
{
margin
:
24px
0
16px
!
important
;
flex-direction
:
column
;
gap
:
8px
;
.el-button
{
width
:
100%
;
margin-left
:
0
!
important
;
}
}
.el-row
[
style
*=
"min-height: 400px"
]
{
min-height
:
auto
!
important
;
}
}
}
}
</
style
>
</
style
>
src/modules/live/reports/components/FormDialog.vue
浏览文件 @
0611fee6
...
@@ -2,6 +2,9 @@
...
@@ -2,6 +2,9 @@
import
{
ElMessage
}
from
'element-plus'
import
{
ElMessage
}
from
'element-plus'
import
{
createReport
,
getReport
,
getTestList
}
from
'../api'
import
{
createReport
,
getReport
,
getTestList
}
from
'../api'
import
AppUpload
from
'@/components/base/AppUpload.vue'
import
AppUpload
from
'@/components/base/AppUpload.vue'
import
{
useMediaQuery
}
from
'@vueuse/core'
const
isMobile
=
useMediaQuery
(
'(max-width: 767px)'
)
const
props
=
defineProps
([
'data'
,
'action'
])
const
props
=
defineProps
([
'data'
,
'action'
])
...
@@ -73,13 +76,18 @@ function handleSuccess(file) {
...
@@ -73,13 +76,18 @@ function handleSuccess(file) {
</
script
>
</
script
>
<
template
>
<
template
>
<el-dialog
:title=
"title"
:close-on-click-modal=
"false"
@
closed=
"$emit('update:modelValue', false)"
width=
"500px"
>
<el-dialog
:title=
"title"
:close-on-click-modal=
"false"
@
closed=
"$emit('update:modelValue', false)"
:width=
"isMobile ? '95%' : '500px'"
destroy-on-close
>
<el-form
<el-form
ref=
"formRef"
ref=
"formRef"
:model=
"form"
:model=
"form"
:rules=
"rules"
:rules=
"rules"
label-position=
"right
"
:label-position=
"isMobile ? 'top' : 'right'
"
label-width=
"110px
"
:label-width=
"isMobile ? undefined : '110px'
"
:disabled=
"action === 'view'"
>
:disabled=
"action === 'view'"
>
<el-form-item
label=
"关联直播"
prop=
"live_practice_id"
>
<el-form-item
label=
"关联直播"
prop=
"live_practice_id"
>
<el-select
v-model=
"form.live_practice_id"
style=
"width: 100%"
placeholder=
"请选择"
filterable
>
<el-select
v-model=
"form.live_practice_id"
style=
"width: 100%"
placeholder=
"请选择"
filterable
>
...
...
src/modules/live/reports/views/Index.vue
浏览文件 @
0611fee6
...
@@ -26,7 +26,7 @@ const listOptions = computed(() => {
...
@@ -26,7 +26,7 @@ const listOptions = computed(() => {
},
},
filters
:
[
filters
:
[
{
label
:
'直播主题品类'
,
prop
:
'live_commodity_type_id'
,
slots
:
'filter-category'
},
{
label
:
'直播主题品类'
,
prop
:
'live_commodity_type_id'
,
slots
:
'filter-category'
},
{
label
:
'直播主题名称'
,
prop
:
'live_commodity_title'
,
type
:
'input'
},
{
label
:
'直播主题名称'
,
prop
:
'live_commodity_title'
,
type
:
'input'
,
placeholder
:
'请输入直播主题名称'
},
],
],
columns
:
[
columns
:
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
...
@@ -58,6 +58,7 @@ const handleView = (row) => {
...
@@ -58,6 +58,7 @@ const handleView = (row) => {
currentRow
.
value
=
row
currentRow
.
value
=
row
formVisible
.
value
=
true
formVisible
.
value
=
true
}
}
// 删除
// 删除
const
handleRemove
=
async
(
row
)
=>
{
const
handleRemove
=
async
(
row
)
=>
{
await
ElMessageBox
.
confirm
(
'此操作将永久删除该数据, 是否继续?'
,
'提示'
)
await
ElMessageBox
.
confirm
(
'此操作将永久删除该数据, 是否继续?'
,
'提示'
)
...
@@ -74,7 +75,7 @@ const handleRemove = async (row) => {
...
@@ -74,7 +75,7 @@ const handleRemove = async (row) => {
<el-button
type=
"primary"
@
click=
"handleAdd"
>
上传总结报告
</el-button>
<el-button
type=
"primary"
@
click=
"handleAdd"
>
上传总结报告
</el-button>
</
template
>
</
template
>
<
template
#
filter-category
>
<
template
#
filter-category
>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
></LiveProductCategory>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
placeholder=
"请选择直播主题品类"
></LiveProductCategory>
</
template
>
</
template
>
<
template
#
table-x=
"{ row }"
>
<
template
#
table-x=
"{ row }"
>
<el-button
text
type=
"primary"
@
click=
"handleView(row)"
>
查看
</el-button>
<el-button
text
type=
"primary"
@
click=
"handleView(row)"
>
查看
</el-button>
...
@@ -82,6 +83,8 @@ const handleRemove = async (row) => {
...
@@ -82,6 +83,8 @@ const handleRemove = async (row) => {
</
template
>
</
template
>
</AppList>
</AppList>
</AppCard>
</AppCard>
<!-- 新建/修改 -->
<FormDialog
v-model=
"formVisible"
:action=
"action"
:data=
"currentRow"
@
update=
"handleRefresh"
v-if=
"formVisible"
/>
<FormDialog
v-model=
"formVisible"
:action=
"action"
:data=
"currentRow"
@
update=
"handleRefresh"
v-if=
"formVisible"
/>
</template>
</template>
<
style
scoped
>
</
style
>
src/modules/live/talk/components/FormDialog.vue
浏览文件 @
0611fee6
...
@@ -5,6 +5,10 @@ import { createTalk, updateTalk, getTalk, getProduct } from '../api'
...
@@ -5,6 +5,10 @@ import { createTalk, updateTalk, getTalk, getProduct } from '../api'
import
{
useChat
}
from
'@/composables/useChat'
import
{
useChat
}
from
'@/composables/useChat'
import
Editor
from
'@tinymce/tinymce-vue'
import
Editor
from
'@tinymce/tinymce-vue'
import
{
useMapStore
}
from
'@/stores/map'
import
{
useMapStore
}
from
'@/stores/map'
import
{
useMediaQuery
}
from
'@vueuse/core'
const
isMobile
=
useMediaQuery
(
'(max-width: 767px)'
)
const
editorHeight
=
computed
(()
=>
(
isMobile
.
value
?
250
:
420
))
const
props
=
defineProps
([
'data'
,
'action'
])
const
props
=
defineProps
([
'data'
,
'action'
])
...
@@ -200,8 +204,13 @@ function handleAIGenerate(index) {
...
@@ -200,8 +204,13 @@ function handleAIGenerate(index) {
</
script
>
</
script
>
<
template
>
<
template
>
<el-dialog
:title=
"title"
:close-on-click-modal=
"false"
@
closed=
"$emit('update:modelValue', false)"
width=
"1000px"
>
<el-dialog
<el-row
justify=
"center"
:gutter=
"40"
>
:title=
"title"
:close-on-click-modal=
"false"
@
closed=
"$emit('update:modelValue', false)"
:width=
"isMobile ? '95%' : '1000px'"
destroy-on-close
>
<el-row
justify=
"center"
:gutter=
"40"
class=
"talk-dialog-row"
>
<el-col
:sm=
"24"
:md=
"12"
>
<el-col
:sm=
"24"
:md=
"12"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
label-position=
"top"
:disabled=
"action === 'view'"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
label-position=
"top"
:disabled=
"action === 'view'"
>
<el-form-item
label=
"直播话术名称"
prop=
"name"
>
<el-form-item
label=
"直播话术名称"
prop=
"name"
>
...
@@ -257,7 +266,7 @@ function handleAIGenerate(index) {
...
@@ -257,7 +266,7 @@ function handleAIGenerate(index) {
</el-form-item>
</el-form-item>
</el-form>
</el-form>
</el-col>
</el-col>
<el-col
:sm=
"24"
:md=
"12"
style=
"border-left: 1px solid #dcdfe6
"
>
<el-col
:sm=
"24"
:md=
"12"
class=
"talk-dialog-right
"
>
<div
style=
"text-align: center; margin-bottom: 20px"
>
<div
style=
"text-align: center; margin-bottom: 20px"
>
<h2
style=
"margin-bottom: 20px"
>
直播话术
</h2>
<h2
style=
"margin-bottom: 20px"
>
直播话术
</h2>
<el-button
<el-button
...
@@ -276,7 +285,7 @@ function handleAIGenerate(index) {
...
@@ -276,7 +285,7 @@ function handleAIGenerate(index) {
quickbars_insert_toolbar: false,
quickbars_insert_toolbar: false,
menubar: false,
menubar: false,
statusbar: false,
statusbar: false,
height:
420
,
height:
editorHeight
,
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:13px }',
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:13px }',
}" />
}" />
</el-col>
</el-col>
...
@@ -307,4 +316,19 @@ function handleAIGenerate(index) {
...
@@ -307,4 +316,19 @@ function handleAIGenerate(index) {
line-height
:
22px
;
line-height
:
22px
;
color
:
#92939a
;
color
:
#92939a
;
}
}
@media
(
max-width
:
767px
)
{
.talk-dialog-row
{
flex-direction
:
column
;
}
.talk-dialog-right
{
border-left
:
none
!important
;
border-bottom
:
1px
solid
#dcdfe6
;
padding-bottom
:
16px
;
margin-bottom
:
16px
;
}
.form-tips
{
position
:
static
;
margin-bottom
:
8px
;
}
}
</
style
>
</
style
>
src/modules/live/talk/views/Index.vue
浏览文件 @
0611fee6
...
@@ -32,8 +32,13 @@ const listOptions = computed(() => {
...
@@ -32,8 +32,13 @@ const listOptions = computed(() => {
},
},
filters
:
[
filters
:
[
{
label
:
'直播主题品类'
,
prop
:
'live_commodity_type_id'
,
slots
:
'filter-category'
},
{
label
:
'直播主题品类'
,
prop
:
'live_commodity_type_id'
,
slots
:
'filter-category'
},
{
label
:
'直播主题名称'
,
prop
:
'live_commodity_title'
,
type
:
'input'
},
{
{
label
:
'话术名称'
,
prop
:
'name'
,
type
:
'input'
},
label
:
'直播主题名称'
,
prop
:
'live_commodity_title'
,
type
:
'input'
,
placeholder
:
'请输入直播主题名称'
,
},
{
label
:
'话术名称'
,
prop
:
'name'
,
type
:
'input'
,
placeholder
:
'请输入话术名称'
},
],
],
columns
:
[
columns
:
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
...
@@ -82,10 +87,13 @@ const handleRemove = async (row) => {
...
@@ -82,10 +87,13 @@ const handleRemove = async (row) => {
<AppCard
title=
"直播话术管理"
>
<AppCard
title=
"直播话术管理"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
header-buttons
>
<template
#
header-buttons
>
<el-button
type=
"primary"
@
click=
"handleAdd"
v-if=
"!listLength"
>
添加话术
</el-button>
<el-button
type=
"primary"
@
click=
"handleAdd"
>
添加话术
</el-button>
</
template
>
</
template
>
<
template
#
filter-category
>
<
template
#
filter-category
>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
></LiveProductCategory>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
placeholder=
"请选择直播主题品类"
></LiveProductCategory>
</
template
>
</
template
>
<
template
#
table-x=
"{ row }"
>
<
template
#
table-x=
"{ row }"
>
<el-button
text
type=
"primary"
@
click=
"handleView(row)"
>
查看
</el-button>
<el-button
text
type=
"primary"
@
click=
"handleView(row)"
>
查看
</el-button>
...
@@ -97,3 +105,5 @@ const handleRemove = async (row) => {
...
@@ -97,3 +105,5 @@ const handleRemove = async (row) => {
<!-- 新建/修改 -->
<!-- 新建/修改 -->
<FormDialog
v-model=
"formVisible"
:action=
"action"
:data=
"currentRow"
@
update=
"handleRefresh"
v-if=
"formVisible"
/>
<FormDialog
v-model=
"formVisible"
:action=
"action"
:data=
"currentRow"
@
update=
"handleRefresh"
v-if=
"formVisible"
/>
</template>
</template>
<
style
scoped
></
style
>
src/modules/live/test/components/Demo.vue
浏览文件 @
0611fee6
...
@@ -263,4 +263,34 @@ const onStatsChange = (stats) => {
...
@@ -263,4 +263,34 @@ const onStatsChange = (stats) => {
overflow-y
:
auto
;
overflow-y
:
auto
;
line-height
:
24px
;
line-height
:
24px
;
}
}
@media
(
max-width
:
767px
)
{
.live-row
{
flex-direction
:
column
;
gap
:
12px
;
height
:
auto
;
}
.live-col
{
width
:
100%
!
important
;
padding
:
12px
;
border-radius
:
0
;
border-left
:
none
;
border-right
:
none
;
}
.live-time
{
height
:
auto
;
font-size
:
42px
;
margin
:
8px
0
;
}
.live-data2
dd
{
font-size
:
32px
;
}
.live-tag
{
margin
:
12px
0
;
padding
:
12px
;
}
.live-talk-content
{
max-height
:
none
;
}
}
</
style
>
</
style
>
src/modules/live/test/components/FormDialog.vue
浏览文件 @
0611fee6
...
@@ -3,6 +3,9 @@ import { ElMessage } from 'element-plus'
...
@@ -3,6 +3,9 @@ import { ElMessage } from 'element-plus'
import
LiveProductSelect
from
'@/components/LiveProductSelect.vue'
import
LiveProductSelect
from
'@/components/LiveProductSelect.vue'
import
{
createTest
,
updateTest
,
getTalkList
}
from
'../api'
import
{
createTest
,
updateTest
,
getTalkList
}
from
'../api'
import
{
useMapStore
}
from
'@/stores/map'
import
{
useMapStore
}
from
'@/stores/map'
import
{
useMediaQuery
}
from
'@vueuse/core'
const
isMobile
=
useMediaQuery
(
'(max-width: 767px)'
)
const
props
=
defineProps
([
'data'
])
const
props
=
defineProps
([
'data'
])
...
@@ -62,7 +65,7 @@ async function handleUpdate() {
...
@@ -62,7 +65,7 @@ async function handleUpdate() {
</
script
>
</
script
>
<
template
>
<
template
>
<el-dialog
:title=
"title"
:close-on-click-modal=
"false"
@
closed=
"$emit('update:modelValue', false)"
>
<el-dialog
:title=
"title"
:close-on-click-modal=
"false"
@
closed=
"$emit('update:modelValue', false)"
:width=
"isMobile ? '90%' : undefined"
>
<el-row
justify=
"center"
>
<el-row
justify=
"center"
>
<el-col
:sm=
"24"
:md=
"16"
>
<el-col
:sm=
"24"
:md=
"16"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
label-position=
"top"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
label-position=
"top"
>
...
...
src/modules/live/test/components/Live.vue
浏览文件 @
0611fee6
...
@@ -80,6 +80,8 @@ const {
...
@@ -80,6 +80,8 @@ const {
endTime
,
endTime
,
duration
,
duration
,
currentTime
:
currentLiveTime
,
currentTime
:
currentLiveTime
,
switchCamera
,
isMobile
,
}
=
useLive
({
}
=
useLive
({
onStart
:
()
=>
{
onStart
:
()
=>
{
console
.
log
(
'开始直播'
)
console
.
log
(
'开始直播'
)
...
@@ -215,29 +217,43 @@ defineExpose({ enabled, start, stop })
...
@@ -215,29 +217,43 @@ defineExpose({ enabled, start, stop })
<img
:src=
"enabled ? '/live/live2.png' : '/live/live1.png'"
alt=
"直播状态"
class=
"live-icon"
/>
<img
:src=
"enabled ? '/live/live2.png' : '/live/live1.png'"
alt=
"直播状态"
class=
"live-icon"
/>
</div>
</div>
<div
class=
"live-bd"
>
<div
class=
"live-bd"
>
<video
muted
autoplay
ref=
"video"
></video>
<video
muted
autoplay
ref=
"video"
playsinline
></video>
<LiveCover
:messages=
"messages"
:stats=
"stats"
:viewers=
"viewers"
v-if=
"enabled"
/>
<LiveCover
:messages=
"messages"
:stats=
"stats"
:viewers=
"viewers"
v-if=
"enabled"
/>
</div>
<!-- 移动端摄像头切换按钮 -->
<div
class=
"live-ft"
>
<el-button
<el-button
type=
"primary"
class=
"camera-switch-btn"
size=
"large"
circle
round
size=
"small"
style=
"width: 80%"
@
click=
"switchCamera"
@
click=
"enabled ? stop() : start()"
v-if=
"isMobile && !enabled && !recordId"
>
v-if=
"!recordId"
>
<svg
xmlns=
"http://www.w3.org/2000/svg"
width=
"16"
height=
"16"
viewBox=
"0 0 24 24"
fill=
"none"
stroke=
"currentColor"
stroke-width=
"2"
stroke-linecap=
"round"
stroke-linejoin=
"round"
>
{{
enabled
?
'结束直播'
:
'开始直播'
}}
<path
d=
"M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"
/>
<circle
cx=
"12"
cy=
"13"
r=
"4"
/>
</svg>
</el-button>
</el-button>
<el-button
</div>
type=
"primary"
<div
class=
"live-ft"
>
size=
"large"
<div
class=
"live-ft-row"
>
round
<el-button
style=
"width: 80%; margin: 10px 0 0 0"
:type=
"enabled ? 'danger' : 'primary'"
:loading=
"uploading"
size=
"large"
@
click=
"handleUpload"
round
v-if=
"isLocalUpload && recordId"
class=
"live-ft-btn"
>
上传
</el-button
@
click=
"enabled ? stop() : start()"
>
v-if=
"!recordId"
>
{{
enabled
?
'结束直播'
:
'开始直播'
}}
</el-button>
<el-button
type=
"primary"
size=
"large"
round
class=
"live-ft-btn"
:loading=
"uploading"
@
click=
"handleUpload"
v-if=
"isLocalUpload && recordId"
>
上传
</el-button
>
</div>
</div>
</div>
</div>
</div>
<el-dialog
title=
"提示"
:model-value=
"dialogVisible"
:showClose=
"false"
width=
"500px"
>
<el-dialog
title=
"提示"
:model-value=
"dialogVisible"
:showClose=
"false"
width=
"500px"
>
...
@@ -271,6 +287,7 @@ defineExpose({ enabled, start, stop })
...
@@ -271,6 +287,7 @@ defineExpose({ enabled, start, stop })
<
style
lang=
"scss"
>
<
style
lang=
"scss"
>
.live
{
.live
{
width
:
375px
;
width
:
375px
;
max-width
:
100%
;
&
-hd
{
&
-hd
{
display
:
flex
;
display
:
flex
;
...
@@ -285,6 +302,7 @@ defineExpose({ enabled, start, stop })
...
@@ -285,6 +302,7 @@ defineExpose({ enabled, start, stop })
&
-bd
{
&
-bd
{
position
:
relative
;
position
:
relative
;
height
:
667px
;
height
:
667px
;
max-height
:
70vh
;
border-radius
:
8px
;
border-radius
:
8px
;
overflow
:
hidden
;
overflow
:
hidden
;
background-color
:
#000
;
background-color
:
#000
;
...
@@ -298,6 +316,60 @@ defineExpose({ enabled, start, stop })
...
@@ -298,6 +316,60 @@ defineExpose({ enabled, start, stop })
&
-ft
{
&
-ft
{
margin-top
:
10px
;
margin-top
:
10px
;
text-align
:
center
;
text-align
:
center
;
&
-row
{
display
:
flex
;
justify-content
:
center
;
gap
:
10px
;
}
&
-btn
{
min-width
:
160px
;
}
}
// 摄像头切换按钮
.camera-switch-btn
{
position
:
absolute
;
top
:
10px
;
right
:
10px
;
z-index
:
130
;
background
:
rgba
(
0
,
0
,
0
,
0
.4
);
color
:
#fff
;
border
:
1px
solid
rgba
(
255
,
255
,
255
,
0
.3
);
&
:hover
{
background
:
rgba
(
0
,
0
,
0
,
0
.6
);
}
}
// 移动端适配
@media
(
max-width
:
768px
)
{
width
:
100%
;
&
-bd
{
height
:
50vh
;
max-height
:
50vh
;
border-radius
:
0
;
}
&
-hd
{
padding
:
0
4px
;
font-size
:
14px
;
}
&
-ft
{
&
-btn
{
width
:
80%
;
min-width
:
auto
;
}
}
}
@media
(
max-width
:
480px
)
{
&
-bd
{
height
:
40vh
;
max-height
:
40vh
;
}
}
}
}
}
.modal-content
{
.modal-content
{
...
...
src/modules/live/test/components/LivePlayback.vue
浏览文件 @
0611fee6
...
@@ -110,7 +110,7 @@ const handleInput = (value) => {
...
@@ -110,7 +110,7 @@ const handleInput = (value) => {
</defs>
</defs>
</svg>
</svg>
</div>
</div>
<div
class=
"live-slider"
v-show=
"hover
"
>
<div
class=
"live-slider"
:class=
"
{ 'is-visible': hover }
">
<el-slider
<el-slider
v-model=
"currentTime"
v-model=
"currentTime"
:step=
"0.1"
:step=
"0.1"
...
@@ -127,6 +127,7 @@ const handleInput = (value) => {
...
@@ -127,6 +127,7 @@ const handleInput = (value) => {
<
style
lang=
"scss"
>
<
style
lang=
"scss"
>
.live
{
.live
{
width
:
375px
;
width
:
375px
;
max-width
:
100%
;
&
-hd
{
&
-hd
{
display
:
flex
;
display
:
flex
;
...
@@ -141,6 +142,7 @@ const handleInput = (value) => {
...
@@ -141,6 +142,7 @@ const handleInput = (value) => {
&
-bd
{
&
-bd
{
position
:
relative
;
position
:
relative
;
height
:
667px
;
height
:
667px
;
max-height
:
70vh
;
border-radius
:
8px
;
border-radius
:
8px
;
overflow
:
hidden
;
overflow
:
hidden
;
background-color
:
#000
;
background-color
:
#000
;
...
@@ -155,6 +157,38 @@ const handleInput = (value) => {
...
@@ -155,6 +157,38 @@ const handleInput = (value) => {
margin-top
:
10px
;
margin-top
:
10px
;
text-align
:
center
;
text-align
:
center
;
}
}
@media
(
max-width
:
768px
)
{
width
:
100%
;
&
-bd
{
height
:
50vh
;
max-height
:
50vh
;
border-radius
:
0
;
}
&
-hd
{
padding
:
0
4px
;
font-size
:
14px
;
}
.live-play-button
{
display
:
flex
;
}
.live-slider
{
display
:
block
;
}
.live-slider.is-visible
{
display
:
block
;
}
}
@media
(
max-width
:
480px
)
{
&
-bd
{
height
:
40vh
;
max-height
:
40vh
;
}
}
}
}
.live-play-button
{
.live-play-button
{
position
:
absolute
;
position
:
absolute
;
...
...
src/modules/live/test/components/RecordView.vue
浏览文件 @
0611fee6
...
@@ -4,6 +4,7 @@ import Demo from '../components/Demo.vue'
...
@@ -4,6 +4,7 @@ import Demo from '../components/Demo.vue'
import
ImprovementPlan
from
'../components/ImprovementPlan.vue'
import
ImprovementPlan
from
'../components/ImprovementPlan.vue'
import
RecordViewText
from
'./RecordViewText.vue'
import
RecordViewText
from
'./RecordViewText.vue'
import
{
useLiveRecord
}
from
'../composables/useLiveRecord'
import
{
useLiveRecord
}
from
'../composables/useLiveRecord'
import
{
useMediaQuery
}
from
'@vueuse/core'
const
props
=
defineProps
({
const
props
=
defineProps
({
isView
:
{
type
:
Boolean
,
default
:
true
},
isView
:
{
type
:
Boolean
,
default
:
true
},
...
@@ -12,6 +13,8 @@ const props = defineProps({
...
@@ -12,6 +13,8 @@ const props = defineProps({
const
{
liveRecord
:
detail
,
handleAIScore
,
isLoading
}
=
useLiveRecord
({
id
:
props
.
recordId
,
immediate
:
true
})
const
{
liveRecord
:
detail
,
handleAIScore
,
isLoading
}
=
useLiveRecord
({
id
:
props
.
recordId
,
immediate
:
true
})
const
isMobile
=
useMediaQuery
(
'(max-width: 767px)'
)
const
timelines
=
computed
(()
=>
{
const
timelines
=
computed
(()
=>
{
return
detail
.
value
?
JSON
.
parse
(
detail
.
value
.
subtitle
)?.
Result
?.
Sentences
||
[]
:
[]
return
detail
.
value
?
JSON
.
parse
(
detail
.
value
.
subtitle
)?.
Result
?.
Sentences
||
[]
:
[]
})
})
...
@@ -225,8 +228,8 @@ function formatDuration(seconds) {
...
@@ -225,8 +228,8 @@ function formatDuration(seconds) {
</el-step>
</el-step>
</el-steps>
</el-steps>
</AppCard>
</AppCard>
<el-dialog
v-model=
"dialogVisible"
title=
"直播回放"
width=
"1200px"
>
<el-dialog
v-model=
"dialogVisible"
title=
"直播回放"
:width=
"isMobile ? '95%' : '1200px'"
destroy-on-close
>
<div
style=
"height: 740px
"
>
<div
:style=
"{ height: isMobile ? 'auto' : '740px', maxHeight: isMobile ? '80vh' : 'none', overflowY: isMobile ? 'auto' : 'hidden' }
"
>
<Demo
:id=
"id"
:recordId=
"recordId"
:isView=
"true"
/>
<Demo
:id=
"id"
:recordId=
"recordId"
:isView=
"true"
/>
</div>
</div>
</el-dialog>
</el-dialog>
...
@@ -272,6 +275,38 @@ function formatDuration(seconds) {
...
@@ -272,6 +275,38 @@ function formatDuration(seconds) {
width
:
200px
;
width
:
200px
;
}
}
}
}
@media
(
max-width
:
767px
)
{
flex-direction
:
column
;
.live-info-header
{
border-right
:
none
;
border-bottom
:
1px
solid
#e5e5e5
;
padding-right
:
0
;
padding-bottom
:
12px
;
h2
{
font-size
:
20px
;
}
h6
{
font-size
:
16px
;
}
}
.live-info-item
{
div
{
width
:
calc
(
50%
-
12px
);
min-width
:
120px
;
}
}
}
@media
(
max-width
:
480px
)
{
.live-info-item
{
div
{
width
:
100%
;
}
}
}
}
}
.live-title
{
.live-title
{
font-size
:
14px
;
font-size
:
14px
;
...
...
src/modules/live/test/composables/useLive.ts
浏览文件 @
0611fee6
...
@@ -36,10 +36,25 @@ export function useLive({ enabledUserMedia = true, onStart, onRecord, onStop }:
...
@@ -36,10 +36,25 @@ export function useLive({ enabledUserMedia = true, onStart, onRecord, onStop }:
const
currentCamera
=
computed
(()
=>
cameras
.
value
[
0
]?.
deviceId
)
const
currentCamera
=
computed
(()
=>
cameras
.
value
[
0
]?.
deviceId
)
const
currentMicrophone
=
computed
(()
=>
microphones
.
value
[
0
]?.
deviceId
)
const
currentMicrophone
=
computed
(()
=>
microphones
.
value
[
0
]?.
deviceId
)
// 移动端摄像头切换
const
facingMode
=
ref
<
'user'
|
'environment'
>
(
'user'
)
const
isFrontCamera
=
computed
(()
=>
facingMode
.
value
===
'user'
)
// 检测移动端
const
isMobile
=
/Android|iPhone|iPad|iPod/i
.
test
(
navigator
.
userAgent
)
||
window
.
innerWidth
<
768
// 响应式媒体约束:移动端使用 facingMode,桌面端使用 deviceId
const
constraints
=
computed
(()
=>
{
if
(
isMobile
)
{
return
{
video
:
{
facingMode
:
{
ideal
:
facingMode
.
value
}
},
audio
:
true
}
}
return
{
video
:
{
deviceId
:
currentCamera
.
value
as
any
},
audio
:
{
deviceId
:
currentMicrophone
.
value
as
any
}
}
})
// 创建媒体流
// 创建媒体流
const
{
stream
}
=
useUserMedia
({
const
{
stream
}
=
useUserMedia
({
enabled
:
enabledUserMedia
,
enabled
:
enabledUserMedia
,
constraints
:
{
video
:
{
deviceId
:
currentCamera
as
any
},
audio
:
{
deviceId
:
currentMicrophone
as
any
}
}
,
constraints
:
constraints
as
any
,
})
})
// 录像设置
// 录像设置
...
@@ -102,5 +117,13 @@ export function useLive({ enabledUserMedia = true, onStart, onRecord, onStop }:
...
@@ -102,5 +117,13 @@ export function useLive({ enabledUserMedia = true, onStart, onRecord, onStop }:
if
(
mediaRecorder
)
mediaRecorder
.
stop
()
if
(
mediaRecorder
)
mediaRecorder
.
stop
()
}
}
return
{
stream
,
start
,
stop
,
startTime
,
endTime
,
duration
,
currentTime
}
// 切换摄像头(移动端前置/后置)
const
switchCamera
=
()
=>
{
if
(
mediaRecorder
?.
state
===
'recording'
)
return
facingMode
.
value
=
facingMode
.
value
===
'user'
?
'environment'
:
'user'
// 流自动更新后重新初始化 MediaRecorder
nextTick
(()
=>
initializeMediaRecorder
())
}
return
{
stream
,
start
,
stop
,
startTime
,
endTime
,
duration
,
currentTime
,
switchCamera
,
facingMode
,
isFrontCamera
,
isMobile
}
}
}
src/modules/live/test/views/Index.vue
浏览文件 @
0611fee6
...
@@ -34,7 +34,7 @@ const listOptions = computed(() => {
...
@@ -34,7 +34,7 @@ const listOptions = computed(() => {
},
},
filters
:
[
filters
:
[
{
label
:
'直播主题品类'
,
prop
:
'live_commodity_type_id'
,
slots
:
'filter-category'
},
{
label
:
'直播主题品类'
,
prop
:
'live_commodity_type_id'
,
slots
:
'filter-category'
},
{
label
:
'直播主题标题'
,
prop
:
'live_commodity_title'
,
type
:
'input'
},
{
label
:
'直播主题标题'
,
prop
:
'live_commodity_title'
,
type
:
'input'
,
placeholder
:
'请输入直播主题标题'
},
],
],
columns
:
[
columns
:
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
...
@@ -42,13 +42,7 @@ const listOptions = computed(() => {
...
@@ -42,13 +42,7 @@ const listOptions = computed(() => {
{
label
:
'直播主题标题'
,
prop
:
'live_commodity_title'
},
{
label
:
'直播主题标题'
,
prop
:
'live_commodity_title'
},
{
label
:
'直播话术'
,
prop
:
'live_commodity_speeches_name'
},
{
label
:
'直播话术'
,
prop
:
'live_commodity_speeches_name'
},
{
label
:
'所属直播主题品类'
,
prop
:
'live_commodity_type_full_name'
},
{
label
:
'所属直播主题品类'
,
prop
:
'live_commodity_type_full_name'
},
{
{
label
:
'上传方式'
,
prop
:
'upload_way'
,
computed
:
({
row
})
=>
getNameByValue
(
row
.
upload_way
,
liveUploadWay
)
},
label
:
'上传方式'
,
prop
:
'upload_way'
,
computed
({
row
})
{
return
getNameByValue
(
row
.
upload_way
,
liveUploadWay
)
},
},
{
label
:
'创建人'
,
prop
:
'created_operator'
,
computed
:
({
row
})
=>
getOperatorName
(
row
.
created_operator
)
},
{
label
:
'创建人'
,
prop
:
'created_operator'
,
computed
:
({
row
})
=>
getOperatorName
(
row
.
created_operator
)
},
{
label
:
'更新时间'
,
prop
:
'updated_time'
},
{
label
:
'更新时间'
,
prop
:
'updated_time'
},
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
200
},
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
200
},
...
@@ -60,6 +54,7 @@ const formVisible = ref(false)
...
@@ -60,6 +54,7 @@ const formVisible = ref(false)
const
recordVisible
=
ref
(
false
)
const
recordVisible
=
ref
(
false
)
const
currentRow
=
ref
(
null
)
const
currentRow
=
ref
(
null
)
// 查看
const
handelView
=
(
row
)
=>
{
const
handelView
=
(
row
)
=>
{
recordVisible
.
value
=
true
recordVisible
.
value
=
true
currentRow
.
value
=
row
currentRow
.
value
=
row
...
@@ -88,7 +83,10 @@ const handleStart = async (row) => {
...
@@ -88,7 +83,10 @@ const handleStart = async (row) => {
<el-button
type=
"primary"
@
click=
"formVisible = true"
>
添加直播
</el-button>
<el-button
type=
"primary"
@
click=
"formVisible = true"
>
添加直播
</el-button>
</
template
>
</
template
>
<
template
#
filter-category
>
<
template
#
filter-category
>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
></LiveProductCategory>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
placeholder=
"请选择直播主题品类"
></LiveProductCategory>
</
template
>
</
template
>
<
template
#
table-x=
"{ row }"
>
<
template
#
table-x=
"{ row }"
>
<el-button
text
type=
"primary"
@
click=
"handleStart(row)"
v-if=
"row.practice_count == 0"
>
开始直播
</el-button>
<el-button
text
type=
"primary"
@
click=
"handleStart(row)"
v-if=
"row.practice_count == 0"
>
开始直播
</el-button>
...
@@ -97,8 +95,6 @@ const handleStart = async (row) => {
...
@@ -97,8 +95,6 @@ const handleStart = async (row) => {
</
template
>
</
template
>
</AppList>
</AppList>
</AppCard>
</AppCard>
<!-- 新建/修改 -->
<FormDialog
v-model=
"formVisible"
@
update=
"handleRefresh"
v-if=
"formVisible"
/>
<FormDialog
v-model=
"formVisible"
@
update=
"handleRefresh"
v-if=
"formVisible"
/>
<!-- 查看 -->
<RecordDialog
v-model=
"recordVisible"
:data=
"currentRow"
v-if=
"recordVisible"
></RecordDialog>
<RecordDialog
v-model=
"recordVisible"
:data=
"currentRow"
v-if=
"recordVisible"
></RecordDialog>
</template>
</template>
src/modules/market/my/components/Step5.vue
浏览文件 @
0611fee6
...
@@ -135,4 +135,9 @@ async function handleNext() {
...
@@ -135,4 +135,9 @@ async function handleNext() {
align-items
:
center
;
align-items
:
center
;
justify-content
:
space-between
;
justify-content
:
space-between
;
}
}
@media
(
max-width
:
767px
)
{
.remove
{
display
:
block
!
important
;
}
}
</
style
>
</
style
>
src/modules/market/my/views/Index.vue
浏览文件 @
0611fee6
...
@@ -77,4 +77,5 @@ const handleView = row => {
...
@@ -77,4 +77,5 @@ const handleView = row => {
display
:
flex
;
display
:
flex
;
justify-content
:
space-between
;
justify-content
:
space-between
;
}
}
@media
(
max-width
:
767px
)
{
.info
{
flex-direction
:
column
;
gap
:
8px
;
}
}
</
style
>
</
style
>
src/modules/market/my/views/Update.vue
浏览文件 @
0611fee6
...
@@ -114,4 +114,10 @@ async function handleNext(data, isCheck = false) {
...
@@ -114,4 +114,10 @@ async function handleNext(data, isCheck = false) {
margin
:
0
;
margin
:
0
;
}
}
}
}
@media
(
max-width
:
767px
)
{
.el-row
[
style
*=
"padding: 60px"
]
{
padding
:
24px
0
!
important
;
gap
:
20px
!
important
;
}
}
</
style
>
</
style
>
src/modules/market/review/views/Index.vue
浏览文件 @
0611fee6
...
@@ -139,4 +139,7 @@ function isComplete(is: boolean) {
...
@@ -139,4 +139,7 @@ function isComplete(is: boolean) {
display
:
flex
;
display
:
flex
;
justify-content
:
space-between
;
justify-content
:
space-between
;
}
}
@media
(
max-width
:
767px
)
{
.info
{
flex-direction
:
column
;
gap
:
8px
;
}
}
</
style
>
</
style
>
src/modules/market/review/views/Score.vue
浏览文件 @
0611fee6
...
@@ -112,4 +112,5 @@ const handleSubmit = function () {
...
@@ -112,4 +112,5 @@ const handleSubmit = function () {
display
:
flex
;
display
:
flex
;
justify-content
:
space-between
;
justify-content
:
space-between
;
}
}
@media
(
max-width
:
767px
)
{
.info
{
flex-direction
:
column
;
gap
:
8px
;
}
}
</
style
>
</
style
>
src/modules/market/review/views/View.vue
浏览文件 @
0611fee6
...
@@ -50,4 +50,5 @@ const data = $computed(() => {
...
@@ -50,4 +50,5 @@ const data = $computed(() => {
display
:
flex
;
display
:
flex
;
justify-content
:
space-between
;
justify-content
:
space-between
;
}
}
@media
(
max-width
:
767px
)
{
.info
{
flex-direction
:
column
;
gap
:
8px
;
}
}
</
style
>
</
style
>
src/modules/metadata/event/components/FieldDialog.vue
浏览文件 @
0611fee6
...
@@ -171,7 +171,7 @@ const popoverText = function (row: any) {
...
@@ -171,7 +171,7 @@ const popoverText = function (row: any) {
</el-table-column>
</el-table-column>
<el-table-column
width=
"30"
>
<el-table-column
width=
"30"
>
<
template
#
default=
"{ row }"
>
<
template
#
default=
"{ row }"
>
<el-popover
placement=
"top-start"
:width=
"300"
trigger=
"
hover
"
:title=
"row.type_name"
>
<el-popover
placement=
"top-start"
:width=
"300"
trigger=
"
click
"
:title=
"row.type_name"
>
<template
#
reference
>
<template
#
reference
>
<div
style=
"display: flex; justify-content: center; cursor: pointer"
>
<div
style=
"display: flex; justify-content: center; cursor: pointer"
>
<el-icon
size=
"20"
><QuestionFilled
/></el-icon>
<el-icon
size=
"20"
><QuestionFilled
/></el-icon>
...
...
src/modules/metadata/user/components/FormDialog.vue
浏览文件 @
0611fee6
...
@@ -169,7 +169,7 @@ const popoverText = function (type: any) {
...
@@ -169,7 +169,7 @@ const popoverText = function (type: any) {
v-else
v-else
v-model=
"form.format"
v-model=
"form.format"
:placeholder=
"formatPlaceholder"
/>
:placeholder=
"formatPlaceholder"
/>
<el-popover
placement=
"top-start"
:width=
"300"
trigger=
"
hover
"
:title=
"form.type_name"
>
<el-popover
placement=
"top-start"
:width=
"300"
trigger=
"
click
"
:title=
"form.type_name"
>
<template
#
reference
>
<template
#
reference
>
<div
style=
"display: flex; justify-content: center; cursor: pointer"
>
<div
style=
"display: flex; justify-content: center; cursor: pointer"
>
<el-icon
size=
"20"
><QuestionFilled
/></el-icon>
<el-icon
size=
"20"
><QuestionFilled
/></el-icon>
...
...
src/modules/operations/components/Steps.vue
浏览文件 @
0611fee6
...
@@ -161,4 +161,46 @@ const handleDelete = (url) => {
...
@@ -161,4 +161,46 @@ const handleDelete = (url) => {
color
:
#000
;
color
:
#000
;
line-height
:
30px
;
line-height
:
30px
;
}
}
@media
(
max-width
:
767px
)
{
li
.el-icon
{
display
:
block
!
important
;
}
.operations-tabs
:deep
(
.el-tabs__header
)
{
width
:
100%
;
overflow-x
:
auto
;
}
.operations-tabs
:deep
(
.el-tabs__nav-wrap
),
.operations-tabs
:deep
(
.el-tabs__nav-scroll
)
{
overflow-x
:
auto
;
overflow-y
:
hidden
;
}
.operations-tabs
:deep
(
.el-tabs__nav
)
{
display
:
inline-flex
;
flex-wrap
:
nowrap
;
}
.operations-tabs
:deep
(
.el-tabs__item
)
{
flex-shrink
:
0
;
font-size
:
13px
;
padding
:
0
8px
;
}
:deep
(
.el-card__body
)
>
div
[
style
*=
"padding: 40px"
]
{
padding
:
16px
!
important
;
min-height
:
auto
!
important
;
}
.image-list
{
gap
:
12px
;
li
{
width
:
calc
(
50%
-
6px
);
height
:
160px
;
}
}
.el-row
{
flex-wrap
:
wrap
;
justify-content
:
center
;
gap
:
8px
;
.el-button
{
margin-left
:
0
!
important
;
}
}
}
</
style
>
</
style
>
src/modules/score/components/CompetitionLive.vue
浏览文件 @
0611fee6
...
@@ -244,7 +244,7 @@ const handleNext = () => {
...
@@ -244,7 +244,7 @@ const handleNext = () => {
<div
class=
"table-expand-box"
>
<div
class=
"table-expand-box"
>
<el-form
label-position=
"top"
>
<el-form
label-position=
"top"
>
<el-row>
<el-row>
<el-col
:
span
=
"12"
>
<el-col
:
xs=
"24"
:sm
=
"12"
>
<el-form-item
label=
"主图"
>
<el-form-item
label=
"主图"
>
<el-image
<el-image
:src=
"item.url"
:src=
"item.url"
...
@@ -266,7 +266,7 @@ const handleNext = () => {
...
@@ -266,7 +266,7 @@ const handleNext = () => {
style=
"width: 100px; height: 134px; margin-right: 10px"
></el-image>
style=
"width: 100px; height: 134px; margin-right: 10px"
></el-image>
</el-form-item>
</el-form-item>
</el-col>
</el-col>
<el-col
:
span
=
"12"
>
<el-col
:
xs=
"24"
:sm
=
"12"
>
<el-form-item
label=
"主图视频"
>
<el-form-item
label=
"主图视频"
>
<video
<video
:src=
"row.video_url"
:src=
"row.video_url"
...
@@ -385,6 +385,25 @@ const handleNext = () => {
...
@@ -385,6 +385,25 @@ const handleNext = () => {
:deep
(
.el-tabs__nav-wrap
::after
)
{
:deep
(
.el-tabs__nav-wrap
::after
)
{
display
:
none
;
display
:
none
;
}
}
@media
(
max-width
:
767px
)
{
:deep
(
.el-tabs__header
)
{
width
:
100%
;
}
:deep
(
.el-tabs__nav-wrap
),
:deep
(
.el-tabs__nav-scroll
)
{
overflow-x
:
auto
;
overflow-y
:
hidden
;
}
:deep
(
.el-tabs__nav
)
{
display
:
inline-flex
;
flex-wrap
:
nowrap
;
}
:deep
(
.el-tabs__item
)
{
flex-shrink
:
0
;
font-size
:
13px
;
padding
:
0
8px
;
}
}
}
}
.score-header
{
.score-header
{
display
:
flex
;
display
:
flex
;
...
...
src/modules/score/components/CompetitionLive3.vue
浏览文件 @
0611fee6
...
@@ -279,7 +279,7 @@ const disableTabPanel = (type) => {
...
@@ -279,7 +279,7 @@ const disableTabPanel = (type) => {
<div
class=
"table-expand-box"
>
<div
class=
"table-expand-box"
>
<el-form
label-position=
"top"
>
<el-form
label-position=
"top"
>
<el-row>
<el-row>
<el-col
:
span
=
"12"
>
<el-col
:
xs=
"24"
:sm
=
"12"
>
<el-form-item
label=
"主图"
>
<el-form-item
label=
"主图"
>
<el-image
<el-image
:src=
"item.url"
:src=
"item.url"
...
@@ -301,7 +301,7 @@ const disableTabPanel = (type) => {
...
@@ -301,7 +301,7 @@ const disableTabPanel = (type) => {
style=
"width: 100px; height: 134px; margin-right: 10px"
></el-image>
style=
"width: 100px; height: 134px; margin-right: 10px"
></el-image>
</el-form-item>
</el-form-item>
</el-col>
</el-col>
<el-col
:
span
=
"12"
>
<el-col
:
xs=
"24"
:sm
=
"12"
>
<el-form-item
label=
"主图视频"
>
<el-form-item
label=
"主图视频"
>
<video
<video
:src=
"row.video_url"
:src=
"row.video_url"
...
@@ -397,6 +397,14 @@ const disableTabPanel = (type) => {
...
@@ -397,6 +397,14 @@ const disableTabPanel = (type) => {
:deep
(
.el-tabs__nav-wrap
::after
)
{
:deep
(
.el-tabs__nav-wrap
::after
)
{
display
:
none
;
display
:
none
;
}
}
@media
(
max-width
:
767px
)
{
:deep
(
.el-tabs__header
)
{
width
:
100%
;
}
:deep
(
.el-tabs__nav-wrap
),
:deep
(
.el-tabs__nav-scroll
)
{
overflow-x
:
auto
;
overflow-y
:
hidden
;
}
:deep
(
.el-tabs__nav
)
{
display
:
inline-flex
;
flex-wrap
:
nowrap
;
}
:deep
(
.el-tabs__item
)
{
flex-shrink
:
0
;
font-size
:
13px
;
padding
:
0
8px
;
}
}
}
}
.score-header
{
.score-header
{
...
...
src/modules/score/components/CompetitionLiveProd.vue
浏览文件 @
0611fee6
...
@@ -245,7 +245,7 @@ const handleNext = () => {
...
@@ -245,7 +245,7 @@ const handleNext = () => {
<div
class=
"table-expand-box"
>
<div
class=
"table-expand-box"
>
<el-form
label-position=
"top"
>
<el-form
label-position=
"top"
>
<el-row>
<el-row>
<el-col
:
span
=
"12"
>
<el-col
:
xs=
"24"
:sm
=
"12"
>
<el-form-item
label=
"主图"
>
<el-form-item
label=
"主图"
>
<el-image
<el-image
:src=
"item.url"
:src=
"item.url"
...
@@ -267,7 +267,7 @@ const handleNext = () => {
...
@@ -267,7 +267,7 @@ const handleNext = () => {
style=
"width: 100px; height: 134px; margin-right: 10px"
></el-image>
style=
"width: 100px; height: 134px; margin-right: 10px"
></el-image>
</el-form-item>
</el-form-item>
</el-col>
</el-col>
<el-col
:
span
=
"12"
>
<el-col
:
xs=
"24"
:sm
=
"12"
>
<el-form-item
label=
"主图视频"
>
<el-form-item
label=
"主图视频"
>
<video
<video
:src=
"row.video_url"
:src=
"row.video_url"
...
@@ -386,6 +386,13 @@ const handleNext = () => {
...
@@ -386,6 +386,13 @@ const handleNext = () => {
:deep
(
.el-tabs__nav-wrap
::after
)
{
:deep
(
.el-tabs__nav-wrap
::after
)
{
display
:
none
;
display
:
none
;
}
}
@media
(
max-width
:
767px
)
{
:deep
(
.el-tabs__header
)
{
width
:
100%
;
}
:deep
(
.el-tabs__nav-wrap
),
:deep
(
.el-tabs__nav-scroll
)
{
overflow-x
:
auto
;
overflow-y
:
hidden
;
}
:deep
(
.el-tabs__nav
)
{
display
:
inline-flex
;
flex-wrap
:
nowrap
;
}
:deep
(
.el-tabs__item
)
{
flex-shrink
:
0
;
font-size
:
13px
;
padding
:
0
8px
;
}
}
}
}
.score-header
{
.score-header
{
display
:
flex
;
display
:
flex
;
...
...
src/modules/score/components/CompetitionOperations.vue
浏览文件 @
0611fee6
...
@@ -204,6 +204,15 @@ const handleNext = () => {
...
@@ -204,6 +204,15 @@ const handleNext = () => {
}
}
}
}
}
}
@media
(
max-width
:
767px
)
{
.image-list
{
gap
:
12px
;
li
{
width
:
calc
(
50%
-
6px
);
height
:
160px
;
}
}
}
.video-player
{
.video-player
{
max-height
:
400px
;
max-height
:
400px
;
}
}
...
...
src/modules/score/views/Index.vue
浏览文件 @
0611fee6
...
@@ -24,11 +24,12 @@ const listOptions = computed(() => {
...
@@ -24,11 +24,12 @@ const listOptions = computed(() => {
return
{
return
{
remote
:
{
httpRequest
:
getScoreList
,
params
:
listParams
},
remote
:
{
httpRequest
:
getScoreList
,
params
:
listParams
},
filters
:
[
filters
:
[
{
label
:
'姓名'
,
prop
:
'name'
,
type
:
'input'
},
{
label
:
'姓名'
,
prop
:
'name'
,
type
:
'input'
,
placeholder
:
'请输入姓名'
},
{
{
label
:
'状态'
,
label
:
'状态'
,
prop
:
'check_status'
,
prop
:
'check_status'
,
type
:
'select'
,
type
:
'select'
,
placeholder
:
'请选择状态'
,
options
:
[
options
:
[
{
label
:
'暂未评分'
,
value
:
'0'
},
{
label
:
'暂未评分'
,
value
:
'0'
},
{
label
:
'评分中'
,
value
:
'1'
},
{
label
:
'评分中'
,
value
:
'1'
},
...
@@ -101,8 +102,12 @@ useIntervalFn(() => {
...
@@ -101,8 +102,12 @@ useIntervalFn(() => {
</
template
>
</
template
>
<
template
#
filter-category
>
<
template
#
filter-category
>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
></LiveProductCategory>
<LiveProductCategory
v-model=
"listParams.live_commodity_type_id"
@
change=
"handleRefresh"
placeholder=
"请选择直播主题品类"
></LiveProductCategory>
</
template
>
</
template
>
<
template
#
table-x=
"{ row }"
>
<
template
#
table-x=
"{ row }"
>
<el-button
text
type=
"primary"
v-if=
"row.check_status != '1'"
>
<el-button
text
type=
"primary"
v-if=
"row.check_status != '1'"
>
<router-link
:to=
"
{ path: 'score/view', query: { ...$route.query, id: row.id } }">评分
</router-link>
<router-link
:to=
"
{ path: 'score/view', query: { ...$route.query, id: row.id } }">评分
</router-link>
...
...
src/modules/score/views/View.vue
浏览文件 @
0611fee6
...
@@ -197,6 +197,13 @@ useEventListener(window, 'pagehide', () => {
...
@@ -197,6 +197,13 @@ useEventListener(window, 'pagehide', () => {
:deep
(
.el-tabs__nav-wrap
::after
)
{
:deep
(
.el-tabs__nav-wrap
::after
)
{
display
:
none
;
display
:
none
;
}
}
@media
(
max-width
:
767px
)
{
:deep
(
.el-tabs__header
)
{
width
:
100%
;
}
:deep
(
.el-tabs__nav-wrap
),
:deep
(
.el-tabs__nav-scroll
)
{
overflow-x
:
auto
;
overflow-y
:
hidden
;
}
:deep
(
.el-tabs__nav
)
{
display
:
inline-flex
;
flex-wrap
:
nowrap
;
}
:deep
(
.el-tabs__item
)
{
flex-shrink
:
0
;
font-size
:
13px
;
padding
:
0
8px
;
}
}
}
}
.score-header
{
.score-header
{
display
:
flex
;
display
:
flex
;
...
...
src/modules/user/views/Image.vue
浏览文件 @
0611fee6
...
@@ -311,6 +311,42 @@ watch(currentConnection, () => {
...
@@ -311,6 +311,42 @@ watch(currentConnection, () => {
}
}
}
}
}
}
@media
(
max-width
:
767px
)
{
.info-box
{
flex-direction
:
column
;
align-items
:
stretch
;
.info-name
{
flex-direction
:
column
;
min-width
:
auto
!
important
;
margin-bottom
:
12px
;
}
h1
{
font-size
:
22px
;
margin
:
10px
0
0
0
;
}
.line
{
display
:
none
;
}
.info-box
>
div
{
flex-direction
:
column
;
gap
:
8px
;
}
}
.card-box
{
flex-direction
:
column
;
height
:
auto
;
.card
{
height
:
auto
;
min-height
:
300px
;
margin-bottom
:
10px
;
.demo-tabs
{
height
:
auto
;
min-height
:
200px
;
}
}
}
}
.event-box
{
.event-box
{
border-bottom
:
1px
solid
#ccc
;
border-bottom
:
1px
solid
#ccc
;
padding
:
20px
0
5px
;
padding
:
20px
0
5px
;
...
...
src/modules/user/views/Index.vue
浏览文件 @
0611fee6
...
@@ -328,3 +328,16 @@ const handleClear = async () => {
...
@@ -328,3 +328,16 @@ const handleClear = async () => {
<!-- 用户事件数据 -->
<!-- 用户事件数据 -->
<ViewGenerateEventData
v-model=
"generateEventVisible"
v-if=
"generateEventVisible"
></ViewGenerateEventData>
<ViewGenerateEventData
v-model=
"generateEventVisible"
v-if=
"generateEventVisible"
></ViewGenerateEventData>
</template>
</template>
<
style
scoped
>
@media
(
max-width
:
767px
)
{
.el-row
[
style
*=
"space-between"
]
{
flex-direction
:
column
;
gap
:
8px
;
}
.el-space
{
flex-wrap
:
wrap
;
gap
:
6px
;
}
}
</
style
>
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论