Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
live-management-web
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
haojie
live-management-web
Commits
a065d056
Commit
a065d056
authored
Sep 06, 2023
by
haojie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
新增中控台
parent
eec1262b
Show whitespace changes
Inline
Side-by-side
Showing
32 changed files
with
1426 additions
and
98 deletions
+1426
-98
src/assets/svg/ctrl/delete.svg
+6
-0
src/components/ConfirmDialog.vue
+3
-0
src/components/CustomTabPanel/index.tsx
+5
-1
src/components/CustomTabs/index.tsx
+1
-1
src/components/Customizable/index.less
+9
-2
src/components/Dialog.vue
+7
-3
src/components/Loading/FirstCircle.vue
+15
-5
src/components/Select.vue
+2
-0
src/components/cardOne.vue
+3
-0
src/components/textarea.vue
+2
-2
src/componentsUsiness/dialogConfirmFooter.vue
+53
-0
src/componentsUsiness/formItem.vue
+34
-0
src/pages/ImageCustomization/components/MyDigitalPerson.vue
+10
-20
src/pages/ImageCustomization/components/Record.vue
+9
-19
src/pages/ImageCustomization/index.vue
+24
-5
src/pages/InteractiveResponse/components/addGroupDialog.vue
+86
-0
src/pages/InteractiveResponse/components/addReplyDialog.vue
+359
-0
src/pages/InteractiveResponse/components/human.vue
+60
-9
src/pages/InteractiveResponse/components/quickReply.vue
+348
-5
src/pages/InteractiveResponse/components/randomPlayDialog.vue
+195
-0
src/pages/InteractiveResponse/index.vue
+33
-2
src/pages/OnlyVideoLive/useScript.ts
+24
-13
src/pages/VocalCustomization/components/MyDigitalPerson.vue
+1
-1
src/pages/VocalCustomization/index.vue
+3
-1
src/pages/createAction/components/createSuccess/index.less
+1
-1
src/pages/createAction/index.less
+8
-2
src/pages/createAction/index.tsx
+1
-1
src/pages/home/components/myDigtalPeople.vue
+1
-3
src/style/ui.less
+11
-0
src/utils/api/userApi.ts
+88
-0
src/utils/cache.ts
+22
-0
src/utils/request.ts
+2
-2
No files found.
src/assets/svg/ctrl/delete.svg
0 → 100644
View file @
a065d056
<svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
""
xmlns=
"http://www.w3.org/2000/svg"
>
<path
d=
"M2.69544 10C2.51747 10 2.33947 9.93208 2.20367 9.79632C1.93211 9.52472 1.93211 9.08441 2.20367 8.81282L8.81282 2.2037C9.08439 1.9321 9.52471 1.9321 9.79633 2.2037C10.0679 2.47527 10.0679 2.91561 9.79633 3.1872L3.18718 9.79632C3.05138 9.93212 2.8734 10 2.69541 10H2.69544Z"
fill=
""
/>
<path
d=
"M9.3046 9.99996C9.12662 9.99996 8.94863 9.93205 8.81283 9.79629L2.20367 3.18719C1.93211 2.91562 1.93211 2.47526 2.20367 2.20369C2.47523 1.93212 2.91559 1.93209 3.18717 2.20369L9.79633 8.81278C10.0679 9.08438 10.0679 9.52469 9.79633 9.79628C9.66056 9.93208 9.48258 10 9.30458 10L9.3046 9.99996Z"
fill=
""
/>
</svg>
\ No newline at end of file
src/components/ConfirmDialog.vue
View file @
a065d056
...
@@ -7,6 +7,7 @@
...
@@ -7,6 +7,7 @@
class=
"c-dialog-confirm-default"
class=
"c-dialog-confirm-default"
:placement=
"placement"
:placement=
"placement"
:closeOnOverlayClick=
"closeOnOverlayClick"
:closeOnOverlayClick=
"closeOnOverlayClick"
:zIndex=
"zIndex"
>
>
<template
#
body
>
<template
#
body
>
<div
class=
"custom-confirm-dialog-body"
>
<div
class=
"custom-confirm-dialog-body"
>
...
@@ -40,6 +41,7 @@ const props = withDefaults(
...
@@ -40,6 +41,7 @@ const props = withDefaults(
className
?:
string
;
className
?:
string
;
title
?:
string
;
title
?:
string
;
closeOnOverlayClick
?:
boolean
;
closeOnOverlayClick
?:
boolean
;
zIndex
?:
number
;
}
>
(),
}
>
(),
{
{
footer
:
null
,
footer
:
null
,
...
@@ -48,6 +50,7 @@ const props = withDefaults(
...
@@ -48,6 +50,7 @@ const props = withDefaults(
className
:
''
,
className
:
''
,
title
:
''
,
title
:
''
,
closeOnOverlayClick
:
true
,
closeOnOverlayClick
:
true
,
zIndex
:
2500
,
},
},
);
);
const
emit
=
defineEmits
([
'update:modelValue'
,
'confirm'
]);
const
emit
=
defineEmits
([
'update:modelValue'
,
'confirm'
]);
...
...
src/components/CustomTabPanel/index.tsx
View file @
a065d056
...
@@ -9,7 +9,11 @@ export default defineComponent({
...
@@ -9,7 +9,11 @@ export default defineComponent({
setup
(
props
,
{
emit
,
slots
})
{
setup
(
props
,
{
emit
,
slots
})
{
let
currentTab
:
{
value
:
string
}
=
inject
(
'currentTab'
);
let
currentTab
:
{
value
:
string
}
=
inject
(
'currentTab'
);
return
()
=>
{
return
()
=>
{
return
<
div
v
-
show=
{
currentTab
.
value
===
props
.
name
}
>
{
slots
.
default
?.()
}
</
div
>;
return
(
<
div
class=
"custom-tab-panel"
v
-
show=
{
currentTab
.
value
===
props
.
name
}
>
{
slots
.
default
?.()
}
</
div
>
);
};
};
},
},
});
});
src/components/CustomTabs/index.tsx
View file @
a065d056
...
@@ -169,7 +169,7 @@ export default defineComponent({
...
@@ -169,7 +169,7 @@ export default defineComponent({
''
''
)
}
)
}
</
div
>
</
div
>
<
div
class=
"c-tabs-content"
>
{
slots
.
default
?.()
}
</
div
>
<
div
class=
{
[
'c-tabs-content'
,
'narrow-scrollbar'
]
}
>
{
slots
.
default
?.()
}
</
div
>
</
div
>
</
div
>
);
);
},
},
...
...
src/components/Customizable/index.less
View file @
a065d056
@import '@/style/variables.less';
@import '@/style/variables.less';
.custom-izable-page {
.custom-izable-page {
height: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
.header {
.header {
margin
: 20px 0;
padding
: 20px 0;
.da();
.da();
font-size: @size-24;
font-size: @size-24;
font-weight: 700;
font-weight: 700;
...
@@ -52,6 +56,9 @@
...
@@ -52,6 +56,9 @@
}
}
}
}
.izable-page-tabs {
.izable-page-tabs {
margin-top: 50px;
padding-top: 50px;
flex: 1;
box-sizing: border-box;
overflow: hidden;
}
}
}
}
src/components/Dialog.vue
View file @
a065d056
...
@@ -6,21 +6,23 @@
...
@@ -6,21 +6,23 @@
class=
"c-dialog-default"
class=
"c-dialog-default"
:destroyOnClose=
"destroyOnClose"
:destroyOnClose=
"destroyOnClose"
:placement=
"placement"
:placement=
"placement"
:zIndex=
"zIndex"
@
close=
"onClose"
@
close=
"onClose"
>
>
<slot></slot>
<slot></slot>
<template
#
header
>
<div
class=
"header-default"
>
<div
class=
"header-default"
>
<slot
name=
"header"
></slot>
<slot
name=
"header"
></slot>
</div>
</div>
<slot
name=
"body"
></slot>
<template
v-if=
"footer"
>
<slot
name=
"footer"
>
</slot>
</
template
>
</
template
>
<slot
name=
"body"
></slot>
<
template
#
footer
>
<
template
#
footer
>
<slot
name=
"footer"
>
<div
class=
"footer-default"
v-if=
"footer === null"
>
<div
class=
"footer-default"
v-if=
"footer === null"
>
<Button
@
click=
"visible = false"
class=
"footer-cancel footer-public-btn"
>
取消
</Button>
<Button
@
click=
"visible = false"
class=
"footer-cancel footer-public-btn"
>
取消
</Button>
<Button
@
click=
"onConfirm"
class=
"footer-confrim footer-public-btn"
>
确定
</Button>
<Button
@
click=
"onConfirm"
class=
"footer-confrim footer-public-btn"
>
确定
</Button>
</div>
</div>
</slot>
</
template
>
</
template
>
</t-dialog>
</t-dialog>
</template>
</template>
...
@@ -37,12 +39,14 @@ const props = withDefaults(
...
@@ -37,12 +39,14 @@ const props = withDefaults(
placement
?:
string
;
placement
?:
string
;
destroyOnClose
?:
boolean
;
destroyOnClose
?:
boolean
;
className
?:
string
;
className
?:
string
;
zIndex
?:
number
;
}
>
(),
}
>
(),
{
{
footer
:
null
,
footer
:
null
,
placement
:
'center'
,
placement
:
'center'
,
destroyOnClose
:
false
,
destroyOnClose
:
false
,
className
:
''
,
className
:
''
,
zIndex
:
2500
,
},
},
);
);
const
emit
=
defineEmits
([
'update:modelValue'
,
'confirm'
,
'close'
]);
const
emit
=
defineEmits
([
'update:modelValue'
,
'confirm'
,
'close'
]);
...
...
src/components/Loading/FirstCircle.vue
View file @
a065d056
<
template
>
<
template
>
<div
class=
"custom-loading
"
>
<div
:class=
"['custom-loading', mask ? 'custom-loading-mask' : '']
"
>
<div
class=
"spinner"
></div>
<div
class=
"spinner"
></div>
</div>
</div>
</
template
>
</
template
>
<
style
>
<
script
lang=
"ts"
setup
>
const
props
=
withDefaults
(
defineProps
<
{
mask
?:
boolean
;
}
>
(),
{
mask
:
false
,
},
);
</
script
>
<
style
lang=
"less"
>
.custom-loading
{
.custom-loading
{
display
:
flex
;
display
:
flex
;
justify-content
:
center
;
justify-content
:
center
;
align-items
:
center
;
align-items
:
center
;
height
:
100px
;
height
:
100px
;
}
.spinner
{
.spinner
{
width
:
40px
;
width
:
40px
;
height
:
40px
;
height
:
40px
;
border-radius
:
50%
;
border-radius
:
50%
;
border
:
4px
solid
#ccc
;
border
:
4px
solid
#ccc
;
border-top-color
:
#888
;
border-top-color
:
#888
;
animation
:
spin
1s
infinite
linear
;
animation
:
spin
1s
infinite
linear
;
}
}
}
@keyframes
spin
{
@keyframes
spin
{
...
...
src/components/Select.vue
View file @
a065d056
...
@@ -12,7 +12,9 @@
...
@@ -12,7 +12,9 @@
overlayClassName: [className, 'custom-select-popup'],
overlayClassName: [className, 'custom-select-popup'],
}"
}"
>
>
<slot>
<t-option
v-for=
"item in options"
:key=
"item.value"
:value=
"item.value"
:label=
"item.label"
></t-option>
<t-option
v-for=
"item in options"
:key=
"item.value"
:value=
"item.value"
:label=
"item.label"
></t-option>
</slot>
</TSelect>
</TSelect>
</div>
</div>
</
template
>
</
template
>
...
...
src/components/cardOne.vue
View file @
a065d056
...
@@ -111,6 +111,9 @@ watch(
...
@@ -111,6 +111,9 @@ watch(
border-top-right-radius
:
8px
;
border-top-right-radius
:
8px
;
}
}
}
}
.custom-change-name-box
{
margin-top
:
6px
;
}
.hover
{
.hover
{
position
:
absolute
;
position
:
absolute
;
top
:
0
;
top
:
0
;
...
...
src/components/textarea.vue
View file @
a065d056
...
@@ -81,13 +81,13 @@ watch(
...
@@ -81,13 +81,13 @@ watch(
.custom-textarea-box
{
.custom-textarea-box
{
width
:
100%
;
width
:
100%
;
background
:
#181818
;
background
:
#181818
;
//
border
:
@
main-border
;
border
:
1px
solid
transparent
;
color
:
white
;
color
:
white
;
resize
:
none
;
resize
:
none
;
border-radius
:
8px
;
border-radius
:
8px
;
transition
:
border
0.2s
;
transition
:
border
0.2s
;
&:focus-within
{
&:focus-within
{
border
-color
:
#00f9f9
;
border
:
1px
solid
#00f9f9
;
transition
:
all
0.2s
;
transition
:
all
0.2s
;
}
}
.custom-t-textarea
{
.custom-t-textarea
{
...
...
src/componentsUsiness/dialogConfirmFooter.vue
0 → 100644
View file @
a065d056
<
template
>
<div
class=
"dialog-confirm-footer"
>
<template
v-if=
"saveConfirm"
>
<Button
theme=
"opacity"
class=
"save-confirm-button"
@
click=
"onSaveConfirm"
>
{{
saveConfirm
}}
</Button>
</
template
>
<
template
v-if=
"save"
>
<Button
class=
"save-button"
theme=
"green"
@
click=
"onSave"
>
{{
save
}}
</Button>
</
template
>
</div>
</template>
<
script
lang=
"ts"
setup
>
import
Button
from
'@/components/Button.vue'
;
const
props
=
withDefaults
(
defineProps
<
{
saveConfirm
?:
string
;
save
?:
string
;
}
>
(),
{
saveConfirm
:
''
,
save
:
''
,
},
);
const
emit
=
defineEmits
([
'saveConfirm'
,
'save'
]);
// 保存并继续
const
onSaveConfirm
=
()
=>
{
emit
(
'saveConfirm'
);
};
// 保存
const
onSave
=
()
=>
{
emit
(
'save'
);
};
</
script
>
<
style
lang=
"less"
>
@import
'@/style/variables.less'
;
.dialog-confirm-footer
{
background
:
#303030
;
height
:
60px
;
width
:
100%
;
padding
:
14px
;
display
:
flex
;
justify-content
:
flex-end
;
align-items
:
flex-start
;
.save-confirm-button,
.save-button
{
font-size
:
@
size-14
;
font-weight
:
700
;
}
}
</
style
>
src/componentsUsiness/formItem.vue
0 → 100644
View file @
a065d056
<
template
>
<div
:class=
"['custom-usiness-form-item', className]"
>
<div
class=
"label"
>
{{
label
}}
:
</div>
<slot
/>
</div>
</
template
>
<
script
lang=
"ts"
setup
>
const
props
=
withDefaults
(
defineProps
<
{
label
:
string
;
className
?:
string
;
}
>
(),
{
className
:
''
,
},
);
</
script
>
<
style
lang=
"less"
>
@import
'@/style/variables.less'
;
.custom-usiness-form-item
{
display
:
flex
;
.label
{
margin-right
:
6px
;
white-space
:
nowrap
;
font-size
:
@
size-15
;
color
:
white
;
}
}
.custom-usiness-form-item
+
.custom-usiness-form-item
{
margin-top
:
20px
;
}
</
style
>
src/pages/ImageCustomization/components/MyDigitalPerson.vue
View file @
a065d056
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
<div
class=
"image-custom-my-person-box"
>
<div
class=
"image-custom-my-person-box"
>
<Loading
v-show=
"loading"
></Loading>
<Loading
v-show=
"loading"
></Loading>
<div
class=
"my-person-items"
>
<div
class=
"my-person-items"
>
<template
v-for=
"item in
personList.
list"
:key=
"item.id"
>
<template
v-for=
"item in list"
:key=
"item.id"
>
<template
v-if=
"item.audit_status == LIVE_AUDIT_STATUS.LIVE_AUDIT_STATUS_FINISH"
>
<template
v-if=
"item.audit_status == LIVE_AUDIT_STATUS.LIVE_AUDIT_STATUS_FINISH"
>
<CardOne
:id=
"item.id"
:img=
"item.cover_url"
:name=
"item.name"
:edit=
"true"
>
<CardOne
:id=
"item.id"
:img=
"item.cover_url"
:name=
"item.name"
:edit=
"true"
>
<template
#
hover
>
<template
#
hover
>
...
@@ -53,15 +53,17 @@ import ConfirmDialog from '@/components/ConfirmDialog.vue';
...
@@ -53,15 +53,17 @@ import ConfirmDialog from '@/components/ConfirmDialog.vue';
import
Button
from
'@/components/Button.vue'
;
import
Button
from
'@/components/Button.vue'
;
import
Loading
from
'@/components/loading.vue'
;
import
Loading
from
'@/components/loading.vue'
;
import
CardOne
from
'@/components/cardOne.vue'
;
import
CardOne
from
'@/components/cardOne.vue'
;
import
{
onMounted
,
reactive
,
ref
}
from
'vue'
;
import
{
ref
}
from
'vue'
;
import
{
getDigitalPeopleList
}
from
'@/service/Common'
;
import
{
LIVE_AUDIT_STATUS
}
from
'@/service/Live'
;
import
{
LIVE_AUDIT_STATUS
}
from
'@/service/Live'
;
import
{
jumpToCreateLivePage
}
from
'@/router/jump'
;
import
{
jumpToCreateLivePage
}
from
'@/router/jump'
;
const
personList
=
reactive
({
const
props
=
withDefaults
(
list
:
[],
defineProps
<
{
});
list
:
any
[];
const
loading
=
ref
(
false
);
loading
:
boolean
;
}
>
(),
{},
);
const
confirmDialog
=
ref
(
false
);
const
confirmDialog
=
ref
(
false
);
const
deleteId
=
ref
();
const
deleteId
=
ref
();
...
@@ -76,13 +78,6 @@ const confirm = () => {
...
@@ -76,13 +78,6 @@ const confirm = () => {
//
//
};
};
// 获取我的数字人列表
const
getList
=
async
()
=>
{
loading
.
value
=
true
;
let
res
=
await
getDigitalPeopleList
();
personList
.
list
=
res
.
myList
;
loading
.
value
=
false
;
};
const
startLive
=
(
item
:
any
)
=>
{
const
startLive
=
(
item
:
any
)
=>
{
jumpToCreateLivePage
(
jumpToCreateLivePage
(
{
{
...
@@ -92,20 +87,15 @@ const startLive = (item: any) => {
...
@@ -92,20 +87,15 @@ const startLive = (item: any) => {
true
,
true
,
);
);
};
};
onMounted
(()
=>
{
getList
();
});
</
script
>
</
script
>
<
style
lang=
"less"
>
<
style
lang=
"less"
>
@import
'@/style/variables'
;
@import
'@/style/variables'
;
.image-custom-my-person-box
{
.image-custom-my-person-box
{
padding
:
30px
4
0px
;
padding
:
30px
3
0px
;
border-radius
:
4px
4px
0px
0px
;
border-radius
:
4px
4px
0px
0px
;
background
:
#303030
;
background
:
#303030
;
box-shadow
:
0px
0px
8px
0px
rgba
(
0
,
0
,
0
,
0.04
);
box-shadow
:
0px
0px
8px
0px
rgba
(
0
,
0
,
0
,
0.04
);
min-height
:
284px
;
position
:
relative
;
position
:
relative
;
.my-person-items
{
.my-person-items
{
display
:
flex
;
display
:
flex
;
...
...
src/pages/ImageCustomization/components/Record.vue
View file @
a065d056
<
template
>
<
template
>
<div
class=
"image-custom-record"
>
<div
class=
"image-custom-record"
>
<div
class=
"record-items"
v-for=
"item in
recordList.
list"
:key=
"item.id"
>
<div
class=
"record-items"
v-for=
"item in list"
:key=
"item.id"
>
<div
class=
"left"
>
<div
class=
"left"
>
<img
:src=
"item.cover_url"
alt=
""
/>
<img
:src=
"item.cover_url"
alt=
""
/>
</div>
</div>
...
@@ -20,26 +20,16 @@
...
@@ -20,26 +20,16 @@
</
template
>
</
template
>
<
script
lang=
"tsx"
setup
>
<
script
lang=
"tsx"
setup
>
import
{
onMounted
,
reactive
,
ref
}
from
'vue'
;
import
{
ref
}
from
'vue'
;
import
{
getDigitalPeopleList
}
from
'@/service/Common'
;
import
CustomizationStatus
from
'@/components/CustomizationStatus'
;
import
CustomizationStatus
from
'@/components/CustomizationStatus'
;
const
recordList
=
reactive
({
const
props
=
withDefaults
(
list
:
[],
defineProps
<
{
});
list
:
any
[];
const
loading
=
ref
(
false
);
loading
:
boolean
;
}
>
(),
// 获取我的数字人列表
{},
const
getList
=
async
()
=>
{
);
loading
.
value
=
true
;
let
res
=
await
getDigitalPeopleList
();
recordList
.
list
=
res
.
myList
;
loading
.
value
=
false
;
};
onMounted
(()
=>
{
getList
();
});
</
script
>
</
script
>
<
style
lang=
"less"
>
<
style
lang=
"less"
>
...
...
src/pages/ImageCustomization/index.vue
View file @
a065d056
...
@@ -8,12 +8,12 @@
...
@@ -8,12 +8,12 @@
:dialogInfo=
"dialogInfo"
:dialogInfo=
"dialogInfo"
:label=
"'形象定制'"
:label=
"'形象定制'"
>
>
<CustomTabs
v-model=
"currentTab"
theme=
"dark2"
>
<CustomTabs
v-model=
"currentTab"
theme=
"dark2"
class=
"custom-tabs-flex"
>
<CustomTabPanel
name=
"1"
label=
"我的数字人"
>
<CustomTabPanel
name=
"1"
label=
"我的数字人"
>
<MyDigitalPerson></MyDigitalPerson>
<MyDigitalPerson
:list=
"personList.list"
:loading=
"loading"
></MyDigitalPerson>
</CustomTabPanel>
</CustomTabPanel>
<CustomTabPanel
name=
"2"
label=
"生成记录"
>
<CustomTabPanel
name=
"2"
label=
"生成记录"
>
<Record></Record>
<Record
:list=
"personList.list"
:loading=
"loading"
></Record>
</CustomTabPanel>
</CustomTabPanel>
</CustomTabs>
</CustomTabs>
</Customizable>
</Customizable>
...
@@ -33,17 +33,25 @@ import CustomTabs from '@/components/CustomTabs';
...
@@ -33,17 +33,25 @@ import CustomTabs from '@/components/CustomTabs';
import
CustomTabPanel
from
'@/components/CustomTabPanel'
;
import
CustomTabPanel
from
'@/components/CustomTabPanel'
;
import
Customizable
from
'@/components/Customizable'
;
import
Customizable
from
'@/components/Customizable'
;
import
PersonSvg
from
'@/assets/svg/custom/person.svg'
;
import
PersonSvg
from
'@/assets/svg/custom/person.svg'
;
import
{
onMounted
,
ref
}
from
'vue'
;
import
{
onMounted
,
ref
,
reactive
}
from
'vue'
;
import
{
customizedImageSubmission
}
from
'@/utils/api/userApi'
;
import
{
customizedImageSubmission
}
from
'@/utils/api/userApi'
;
import
{
show_message
}
from
'@/utils/tool'
;
import
{
show_message
}
from
'@/utils/tool'
;
import
routerConfig
from
'@/router/tool'
;
import
routerConfig
from
'@/router/tool'
;
import
{
useStore
}
from
'vuex'
;
import
{
useStore
}
from
'vuex'
;
import
{
jumpPageAddNavigation
}
from
'@/router/jump'
;
import
{
jumpPageAddNavigation
}
from
'@/router/jump'
;
import
{
getDigitalPeopleList
}
from
'@/service/Common'
;
const
{
addNavigation
}
=
jumpPageAddNavigation
();
const
{
addNavigation
}
=
jumpPageAddNavigation
();
const
store
=
useStore
();
const
store
=
useStore
();
const
currentTab
=
ref
(
'1'
);
const
currentTab
=
ref
(
'1'
);
// 子组件loading
const
loading
=
ref
(
false
);
const
personList
=
reactive
({
list
:
[],
});
const
imgs
=
{
const
imgs
=
{
success
:
new
URL
(
'../../assets/svg/upload/success2.svg'
,
import
.
meta
.
url
).
href
,
success
:
new
URL
(
'../../assets/svg/upload/success2.svg'
,
import
.
meta
.
url
).
href
,
...
@@ -67,12 +75,21 @@ const uploadInfo = {
...
@@ -67,12 +75,21 @@ const uploadInfo = {
successButtonLabel
:
'替换视频'
,
successButtonLabel
:
'替换视频'
,
};
};
// 获取我的数字人列表
const
getList
=
async
()
=>
{
loading
.
value
=
true
;
let
res
=
await
getDigitalPeopleList
();
personList
.
list
=
res
.
myList
;
loading
.
value
=
false
;
};
const
submit
=
async
(
params
:
any
)
=>
{
const
submit
=
async
(
params
:
any
)
=>
{
try
{
try
{
//
let
res
:
any
=
await
customizedImageSubmission
(
params
);
let
res
:
any
=
await
customizedImageSubmission
(
params
);
if
(
res
.
code
==
0
)
{
if
(
res
.
code
==
0
)
{
show_message
(
'提交成功'
,
'success'
);
show_message
(
'提交成功'
,
'success'
);
// 更新记录
getList
();
return
true
;
return
true
;
}
}
}
catch
(
e
)
{
}
catch
(
e
)
{
...
@@ -82,6 +99,8 @@ const submit = async (params: any) => {
...
@@ -82,6 +99,8 @@ const submit = async (params: any) => {
onMounted
(()
=>
{
onMounted
(()
=>
{
addNavigation
(
routerConfig
.
ImageCustomization
.
path
);
addNavigation
(
routerConfig
.
ImageCustomization
.
path
);
// 获取数字人列表
getList
();
});
});
</
script
>
</
script
>
...
...
src/pages/InteractiveResponse/components/addGroupDialog.vue
0 → 100644
View file @
a065d056
<
template
>
<Dialog
v-model=
"visible"
:zIndex=
"3000"
className=
"add-group-dialog"
@
confirm=
"confirm"
>
<template
#
body
>
<FormItem
label=
"分组名"
className=
"create-group-form-item"
>
<Input
v-model=
"groupValue"
align=
"left"
placeholder=
"请输入分组名"
></Input>
</FormItem>
</
template
>
<Loading
:mask=
"true"
v-show=
"loading"
></Loading>
</Dialog>
</template>
<
script
lang=
"ts"
setup
>
import
Dialog
from
'@/components/Dialog.vue'
;
import
{
computed
,
ref
}
from
'vue'
;
import
FormItem
from
'@/componentsUsiness/formItem.vue'
;
import
Input
from
'@/components/input/index.vue'
;
import
Loading
from
'@/components/loading.vue'
;
import
{
createEplyGroup
}
from
'@/utils/api/userApi'
;
import
{
show_message
}
from
'@/utils/tool'
;
const
props
=
withDefaults
(
defineProps
<
{
modelValue
:
boolean
;
}
>
(),
{},
);
const
emit
=
defineEmits
([
'update:modelValue'
,
'change'
]);
const
loading
=
ref
(
false
);
const
visible
=
computed
({
get
()
{
return
props
.
modelValue
;
},
set
(
value
)
{
emit
(
'update:modelValue'
,
value
);
},
});
// 分组的值
const
groupValue
=
ref
(
''
);
// 提交
const
confirm
=
async
()
=>
{
if
(
!
groupValue
.
value
)
{
show_message
(
'请输入分组名'
);
return
;
}
try
{
loading
.
value
=
true
;
const
res
:
any
=
await
createEplyGroup
({
name
:
groupValue
.
value
,
});
if
(
res
.
code
==
0
)
{
show_message
(
'创建成功'
,
'success'
);
visible
.
value
=
false
;
// 通知更新
emit
(
'change'
);
}
loading
.
value
=
false
;
}
catch
(
e
)
{
loading
.
value
=
false
;
console
.
log
(
e
);
}
};
</
script
>
<
style
lang=
"less"
>
.add-group-dialog
{
.t-dialog
{
position
:
relative
;
}
.t-dialog__body
{
margin
:
30px
0
20px
0
;
.create-group-form-item
{
align-items
:
center
;
.custom-input-global
{
flex
:
1
;
}
}
}
.t-dialog__footer
{
.footer-default
{
text-align
:
center
;
}
}
}
</
style
>
src/pages/InteractiveResponse/components/addReplyDialog.vue
0 → 100644
View file @
a065d056
<
template
>
<Dialog
v-model=
"visible"
className=
"add-reply-dialog"
:footer=
"true"
:destroyOnClose=
"false"
@
close=
"onClose"
>
<template
#
header
>
{{
isCreate
?
'新增内容'
:
'编辑内容'
}}
</
template
>
<
template
#
body
>
<FormItem
label=
"分组"
className=
"custom-group-form-item"
>
<div
class=
"add-reply-group"
>
<Select
:options=
"options"
v-model=
"currentOption"
:autoWidth=
"false"
>
<t-option
v-for=
"item in options"
:key=
"item.value"
:value=
"item.value"
:label=
"item.label"
>
<div
class=
"add-reply-select-option"
>
<span>
{{
item
.
label
}}
</span>
<div
class=
"reply-select-option-icon"
@
click
.
stop=
"deleteGroup(item)"
>
<DeleteSvg></DeleteSvg>
</div>
</div>
</t-option>
</Select>
<template
v-if=
"isCreate"
>
<Button
theme=
"dark"
@
click=
"addGroup"
class=
"add-reply-group-button"
>
<img
:src=
"imgs.add"
alt=
""
/>
新增
</Button
>
</
template
>
</div>
</FormItem>
<FormItem
label=
"标题"
>
<Textarea
v-model=
"questionValue"
placeholder=
"请输入标题"
class=
"question-textarea"
></Textarea>
</FormItem>
<FormItem
label=
"回复"
>
<Textarea
v-model=
"eplyValue"
placeholder=
"请输入回复"
></Textarea>
</FormItem>
</template>
<
template
#
footer
>
<DialogConfirmFooter
:saveConfirm=
"isCreate ? '保存并继续' : ''"
save=
"保存"
@
save=
"onSave"
@
saveConfirm=
"saveConfirm"
></DialogConfirmFooter>
</
template
>
<AddGroupDialog
v-model=
"groupVisible"
@
change=
"getGroupList"
></AddGroupDialog>
<ConfirmDialog
v-model=
"confirmDialogVisible"
title=
"确定要删除掉分组吗?"
:zIndex=
"6000"
@
confirm=
"confirmDelete"
></ConfirmDialog>
<Loading
:mask=
"true"
v-show=
"loading"
></Loading>
</Dialog>
</template>
<
script
lang=
"ts"
setup
>
import
{
computed
,
onMounted
,
ref
,
watch
}
from
'vue'
;
import
{
Option
as
TOption
}
from
'tdesign-vue-next'
;
import
Button
from
'@/components/Button.vue'
;
import
Dialog
from
'@/components/Dialog.vue'
;
import
FormItem
from
'@/componentsUsiness/formItem.vue'
;
import
Textarea
from
'@/components/textarea.vue'
;
import
Select
from
'@/components/Select.vue'
;
import
DialogConfirmFooter
from
'@/componentsUsiness/dialogConfirmFooter.vue'
;
import
{
show_message
}
from
'@/utils/tool'
;
import
AddGroupDialog
from
'./addGroupDialog.vue'
;
import
{
createEplyContent
,
deleteEplyGroup
,
getEplyGroup
,
updateLiveReply
}
from
'@/utils/api/userApi'
;
import
DeleteSvg
from
'@/assets/svg/ctrl/delete.svg'
;
import
ConfirmDialog
from
'@/components/ConfirmDialog.vue'
;
import
Loading
from
'@/components/loading.vue'
;
const
props
=
withDefaults
(
defineProps
<
{
modelValue
:
boolean
;
isCreate
?:
boolean
;
groupList
:
Function
;
info
:
any
;
}
>
(),
{
isCreate
:
true
,
},
);
const
emit
=
defineEmits
([
'update:modelValue'
,
'change'
]);
const
imgs
=
{
add
:
new
URL
(
'@/assets/svg/ctrl/add.svg'
,
import
.
meta
.
url
).
href
,
};
const
loading
=
ref
(
false
);
// 弹窗状态
const
visible
=
computed
({
get
()
{
return
props
.
modelValue
;
},
set
(
value
)
{
emit
(
'update:modelValue'
,
value
);
},
});
// 新增分组弹窗
const
groupVisible
=
ref
(
false
);
// 确认删除弹窗
const
confirmDialogVisible
=
ref
(
false
);
// 要删除的行
const
deleteGroupRow
=
ref
({});
// 问题
const
questionValue
=
ref
(
''
);
// 回复
const
eplyValue
=
ref
(
''
);
// 当前选择的分组
const
currentOption
=
ref
(
''
);
// 分组列表
const
options
=
ref
([]);
// 弹窗关闭事件
const
onClose
=
()
=>
{
//
};
// 打开新增分组弹窗
const
addGroup
=
()
=>
{
groupVisible
.
value
=
true
;
};
// 确认删除分组
const
confirmDelete
=
async
()
=>
{
try
{
loading
.
value
=
true
;
const
res
:
any
=
await
deleteEplyGroup
(
deleteGroupRow
.
value
.
value
);
if
(
res
.
code
==
0
)
{
show_message
(
'删除成功'
,
'success'
);
getGroupList
();
}
loading
.
value
=
false
;
}
catch
(
e
)
{
console
.
log
(
e
);
loading
.
value
=
false
;
}
};
// 删除分组
const
deleteGroup
=
(
item
:
any
)
=>
{
// 打开确认弹窗
confirmDialogVisible
.
value
=
true
;
deleteGroupRow
.
value
=
item
;
};
// 获取请求参数
const
getParams
=
()
=>
{
return
{
title
:
questionValue
.
value
,
groups_id
:
currentOption
.
value
,
content
:
eplyValue
.
value
,
};
};
// 提交后台
const
submit
=
async
()
=>
{
try
{
loading
.
value
=
true
;
const
res
:
any
=
await
createEplyContent
(
getParams
());
if
(
res
.
code
==
0
)
{
show_message
(
'创建成功'
,
'success'
);
emit
(
'change'
);
}
loading
.
value
=
false
;
}
catch
(
e
)
{
console
.
log
(
e
);
loading
.
value
=
false
;
}
};
// 更新回复内容
const
editSubmit
=
async
()
=>
{
try
{
loading
.
value
=
true
;
const
res
:
any
=
await
updateLiveReply
(
props
.
info
.
id
,
getParams
());
if
(
res
.
code
==
0
)
{
show_message
(
'更新成功'
,
'success'
);
// 通知更新
emit
(
'change'
);
}
loading
.
value
=
false
;
}
catch
(
e
)
{
loading
.
value
=
false
;
console
.
log
(
e
);
}
};
// 提交前校验
const
beforeformCheck
=
()
=>
{
if
(
!
currentOption
.
value
)
{
show_message
(
'分组必选'
);
return
;
}
if
(
!
questionValue
.
value
)
{
show_message
(
'标题必填'
);
return
;
}
if
(
!
eplyValue
.
value
)
{
show_message
(
'内容必填'
);
return
;
}
return
true
;
};
const
clearData
=
()
=>
{
currentOption
.
value
=
''
;
questionValue
.
value
=
''
;
eplyValue
.
value
=
''
;
};
// 保存并继续
const
saveConfirm
=
async
()
=>
{
const
status
=
beforeformCheck
();
if
(
!
status
)
{
return
;
}
// 提交内容
await
submit
();
// 清空输入的内容
clearData
();
};
// 保存
const
onSave
=
async
()
=>
{
const
status
=
beforeformCheck
();
if
(
!
status
)
{
return
;
}
if
(
props
.
isCreate
)
{
// 提交内容
await
submit
();
}
else
{
// 编辑
await
editSubmit
();
}
// 关闭弹窗
visible
.
value
=
false
;
};
// 获取分组列表
const
getGroupList
=
async
()
=>
{
try
{
const
res
:
any
=
await
getEplyGroup
();
if
(
res
.
code
==
0
&&
res
.
data
&&
res
.
data
.
length
)
{
options
.
value
=
res
.
data
.
map
((
item
:
any
)
=>
{
return
{
label
:
item
.
name
,
value
:
item
.
id
,
};
});
// 提交给父组件
props
.
groupList
(
options
.
value
);
}
else
{
options
.
value
=
[];
props
.
groupList
([]);
console
.
log
(
res
.
data
,
'getGroupList'
);
}
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
watch
(
()
=>
props
.
info
,
(
v
)
=>
{
if
(
v
&&
Object
.
keys
(
v
).
length
)
{
// 设置值
currentOption
.
value
=
v
.
groups_id
;
questionValue
.
value
=
v
.
title
;
eplyValue
.
value
=
v
.
content
;
}
else
{
clearData
();
}
},
);
onMounted
(()
=>
{
getGroupList
();
});
</
script
>
<
style
lang=
"less"
>
@import
'@/style/variables.less'
;
@add-reply-padding
:
0
32px
;
.add-reply-select-option
{
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
.reply-select-option-icon
{
width
:
20px
;
height
:
20px
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
svg
{
fill
:
#b5b5b5
;
transition
:
fill
0.2s
;
}
&
:hover
{
svg
{
fill
:
white
;
transition
:
fill
0.2s
;
}
}
}
}
.add-reply-dialog
{
.t-dialog
{
padding
:
0
;
position
:
relative
;
.t-dialog__header
{
padding
:
22px
32px
0
32px
;
}
.t-dialog__body
{
margin
:
24px
0
;
padding
:
@
add-reply-padding
;
.question-textarea
{
.t-textarea
{
height
:
60px
;
.t-textarea__inner
{
height
:
100%
!important
;
min-height
:
100%
!important
;
}
}
}
.custom-group-form-item
{
margin-top
:
2px
;
}
.add-reply-group
{
display
:
flex
;
align-items
:
center
;
width
:
100%
;
.custom-select-box
{
flex
:
1
;
.t-select__wrap
{
height
:
32px
;
.t-input
{
width
:
100%
;
}
}
}
.add-reply-group-button
{
color
:
#b4b4b4
;
font-size
:
@
size-14
;
margin-left
:
12px
;
.t-button__text
{
display
:
flex
;
align-items
:
center
;
img
{
margin-right
:
6px
;
}
}
}
}
}
}
}
</
style
>
src/pages/InteractiveResponse/components/human.vue
View file @
a065d056
...
@@ -48,7 +48,7 @@ import Loading from '@/components/loading.vue';
...
@@ -48,7 +48,7 @@ import Loading from '@/components/loading.vue';
import
Button
from
'@/components/Button.vue'
;
import
Button
from
'@/components/Button.vue'
;
import
Textarea
from
'@/components/textarea.vue'
;
import
Textarea
from
'@/components/textarea.vue'
;
import
{
show_message
}
from
'@/utils/tool'
;
import
{
show_message
}
from
'@/utils/tool'
;
import
{
onBeforeUnmount
,
onMounted
,
reactive
,
ref
}
from
'vue'
;
import
{
computed
,
watch
,
onBeforeUnmount
,
onMounted
,
reactive
,
ref
}
from
'vue'
;
import
{
getTonesList
}
from
'@/service/Common'
;
import
{
getTonesList
}
from
'@/service/Common'
;
import
{
liveInteractionReply
,
closeLiveTask
,
getHumanReplyCallback
}
from
'@/utils/api/userApi'
;
import
{
liveInteractionReply
,
closeLiveTask
,
getHumanReplyCallback
}
from
'@/utils/api/userApi'
;
import
{
useRoute
,
useRouter
}
from
'vue-router'
;
import
{
useRoute
,
useRouter
}
from
'vue-router'
;
...
@@ -56,8 +56,17 @@ import routerConfig from '@/router/tool';
...
@@ -56,8 +56,17 @@ import routerConfig from '@/router/tool';
import
{
useStore
}
from
'vuex'
;
import
{
useStore
}
from
'vuex'
;
import
{
callPyjsInWindow
}
from
'@/utils/pyqt'
;
import
{
callPyjsInWindow
}
from
'@/utils/pyqt'
;
import
SelectTone
from
'@/componentsUsiness/selectTone.vue'
;
import
SelectTone
from
'@/componentsUsiness/selectTone.vue'
;
const
props
=
withDefaults
(
const
emit
=
defineEmits
([
'createAudio'
]);
defineProps
<
{
modelValue
:
boolean
;
sendNum
:
number
;
message
:
string
;
soundColor
:
string
|
number
;
textTones
:
string
|
number
;
}
>
(),
{},
);
const
emit
=
defineEmits
([
'createAudio'
,
'update:modelValue'
,
'update:soundColor'
,
'update:textTones'
]);
const
store
=
useStore
();
const
store
=
useStore
();
const
router
=
useRouter
();
const
router
=
useRouter
();
const
route
=
useRoute
();
const
route
=
useRoute
();
...
@@ -69,12 +78,33 @@ const lists = reactive({
...
@@ -69,12 +78,33 @@ const lists = reactive({
soundColor
:
[],
soundColor
:
[],
});
});
const
loading
=
ref
(
false
);
const
loading
=
computed
({
get
()
{
return
props
.
modelValue
;
},
set
(
value
)
{
emit
(
'update:modelValue'
,
value
);
},
});
const
textTonesValue
=
ref
(
''
);
const
textTonesValue
=
computed
({
get
()
{
return
props
.
textTones
;
},
set
(
value
)
{
emit
(
'update:textTones'
,
value
);
},
});
const
soundColorVisible
=
ref
(
false
);
const
soundColorVisible
=
ref
(
false
);
const
soundColorValue
=
ref
(
''
);
const
soundColorValue
=
computed
({
get
()
{
return
props
.
soundColor
;
},
set
(
value
)
{
emit
(
'update:soundColor'
,
value
);
},
});
const
soundColorInfo
=
ref
({});
const
soundColorInfo
=
ref
({});
const
textareaValue
=
ref
(
''
);
const
textareaValue
=
ref
(
''
);
...
@@ -145,7 +175,7 @@ const closeInterval = () => {
...
@@ -145,7 +175,7 @@ const closeInterval = () => {
interval
=
null
;
interval
=
null
;
};
};
const
submit
=
async
()
=>
{
const
submit
=
async
(
content
:
string
=
''
)
=>
{
if
(
loading
.
value
)
{
if
(
loading
.
value
)
{
show_message
(
'请等待上一条回复完成'
);
show_message
(
'请等待上一条回复完成'
);
return
;
return
;
...
@@ -158,13 +188,20 @@ const submit = async () => {
...
@@ -158,13 +188,20 @@ const submit = async () => {
show_message
(
'音调必选'
);
show_message
(
'音调必选'
);
return
;
return
;
}
}
try
{
loading
.
value
=
true
;
let
params
=
{
let
params
=
{
phonetic_timbres_id
:
soundColorValue
.
value
,
phonetic_timbres_id
:
soundColorValue
.
value
,
reply_content
:
textareaValue
.
value
,
reply_content
:
textareaValue
.
value
,
tone_id
:
textTonesValue
.
value
,
tone_id
:
textTonesValue
.
value
,
};
};
if
(
content
)
{
params
.
reply_content
=
content
;
}
else
if
(
!
textareaValue
.
value
)
{
show_message
(
'回复内容必填'
);
return
;
}
try
{
loading
.
value
=
true
;
let
res
:
any
=
await
liveInteractionReply
(
route
.
query
.
id
,
params
);
let
res
:
any
=
await
liveInteractionReply
(
route
.
query
.
id
,
params
);
if
(
res
.
code
==
0
)
{
if
(
res
.
code
==
0
)
{
// 开启轮询
// 开启轮询
...
@@ -193,6 +230,17 @@ const onJump = () => {
...
@@ -193,6 +230,17 @@ const onJump = () => {
}
}
};
};
watch
(
()
=>
props
.
sendNum
,
(
v
)
=>
{
// 发送消息
if
(
!
props
.
message
)
{
return
;
}
submit
(
props
.
message
);
},
);
onMounted
(
async
()
=>
{
onMounted
(
async
()
=>
{
let
res
=
await
getTonesList
(
true
);
let
res
=
await
getTonesList
(
true
);
lists
.
tones
=
res
.
tones
;
lists
.
tones
=
res
.
tones
;
...
@@ -246,6 +294,9 @@ onBeforeUnmount(() => {
...
@@ -246,6 +294,9 @@ onBeforeUnmount(() => {
margin-top
:
12px
;
margin-top
:
12px
;
.custom-textarea-box
{
.custom-textarea-box
{
height
:
100%
;
height
:
100%
;
&:focus-within
{
border-color
:
transparent
;
}
.t-textarea
{
.t-textarea
{
height
:
100%
;
height
:
100%
;
.t-textarea__inner
{
.t-textarea__inner
{
...
...
src/pages/InteractiveResponse/components/quickReply.vue
View file @
a065d056
...
@@ -3,27 +3,283 @@
...
@@ -3,27 +3,283 @@
<div
class=
"header"
>
<div
class=
"header"
>
<div
class=
"label"
>
中控台
</div>
<div
class=
"label"
>
中控台
</div>
<div
class=
"header-buttons"
>
<div
class=
"header-buttons"
>
<Button
theme=
"dark"
>
<Button
theme=
"dark"
@
click=
"setRandomPlay"
>
<img
:src=
"imgs.andom"
alt=
""
class=
"quick-reply-button__image"
/>
<img
:src=
"imgs.andom"
alt=
""
class=
"quick-reply-button__image"
/>
随机播放
</Button
随机播放
</Button
>
>
<Button
theme=
"dark"
>
<Button
theme=
"dark"
@
click=
"addEply"
>
<img
:src=
"imgs.add"
alt=
""
class=
"quick-reply-button__image"
/>
<img
:src=
"imgs.add"
alt=
""
class=
"quick-reply-button__image"
/>
添加回复
</Button
添加回复
</Button
>
>
</div>
</div>
</div>
</div>
<div
class=
"content"
></div>
<div
class=
"content narrow-scrollbar"
ref=
"replyListRef"
>
<div
class=
"quick-reply-select-group"
>
<Select
:options=
"options"
@
change=
"groupChange"
v-model=
"currentOption"
:autoWidth=
"false"
placeholder=
"选择分组"
></Select>
</div>
<div
class=
"quick-reply-list"
>
<div
v-for=
"item in replyList"
:key=
"item.id"
class=
"quick-reply-row"
>
<div
class=
"title"
>
{{
item
.
title
}}
</div>
<div
class=
"value"
>
{{
item
.
content
}}
</div>
<div
class=
"send"
>
<Button
theme=
"dark"
@
click=
"sendMessage(item.content)"
>
发送
</Button>
</div>
<Popup
v-model=
"item.popup"
className=
"quick-reply-row-popup"
>
<div
class=
"dot"
>
<div></div>
<div></div>
<div></div>
</div>
<template
#
content
>
<div
class=
"quick-reply-row-popup-button"
@
click=
"onEdit(item)"
>
<img
:src=
"imgs.edit"
alt=
""
/>
编辑
</div>
<div
class=
"quick-reply-row-popup-button"
@
click=
"onDelete(item)"
>
<img
:src=
"imgs.deleteSvg"
alt=
""
/>
删除
</div>
</
template
>
</Popup>
</div>
<Loading
:mask=
"true"
v-show=
"loading"
></Loading>
</div>
</div>
<AddReplyDialog
v-model=
"eplyDialogVisible"
:isCreate=
"isCreate"
:groupList=
"getGroupList"
:info=
"editInfo"
@
change=
"replyChange"
></AddReplyDialog>
<ConfirmDialog
v-model=
"confirmDialogVisible"
title=
"确定删除吗?"
@
confirm=
"confirmDelete"
></ConfirmDialog>
<RandomPlayDialog
v-model=
"randomPlayVisible"
:playStatus=
"playStatus"
:loading=
"modelValue"
:textTones=
"textTones"
:soundColor=
"soundColor"
@
message=
"sendMessage"
></RandomPlayDialog>
</div>
</div>
</template>
</template>
<
script
lang=
"ts"
setup
>
<
script
lang=
"ts"
setup
>
import
Button
from
'@/components/Button.vue'
;
import
Button
from
'@/components/Button.vue'
;
import
Loading
from
'@/components/loading.vue'
;
import
{
ref
,
onMounted
,
onBeforeUnmount
}
from
'vue'
;
import
AddReplyDialog
from
'./addReplyDialog.vue'
;
import
Select
from
'@/components/Select.vue'
;
import
{
deleteLiveReply
,
getLiveReplyList
}
from
'@/utils/api/userApi'
;
import
Popup
from
'@/components/Popup.vue'
;
import
{
throttle
,
ecursionDeepCopy
,
show_message
}
from
'@/utils/tool'
;
import
ConfirmDialog
from
'@/components/ConfirmDialog.vue'
;
import
RandomPlayDialog
from
'./randomPlayDialog.vue'
;
const
props
=
withDefaults
(
defineProps
<
{
modelValue
:
boolean
;
playStatus
:
boolean
;
textTones
:
string
|
number
;
soundColor
:
string
|
number
;
}
>
(),
{},
);
const
emit
=
defineEmits
([
'message'
]);
const
imgs
=
{
const
imgs
=
{
andom
:
new
URL
(
'@/assets/svg/ctrl/andom.svg'
,
import
.
meta
.
url
).
href
,
andom
:
new
URL
(
'@/assets/svg/ctrl/andom.svg'
,
import
.
meta
.
url
).
href
,
add
:
new
URL
(
'@/assets/svg/ctrl/add.svg'
,
import
.
meta
.
url
).
href
,
add
:
new
URL
(
'@/assets/svg/ctrl/add.svg'
,
import
.
meta
.
url
).
href
,
edit
:
new
URL
(
'@/assets/svg/home/edit.svg'
,
import
.
meta
.
url
).
href
,
deleteSvg
:
new
URL
(
'@/assets/svg/home/delete.svg'
,
import
.
meta
.
url
).
href
,
};
// 滚动元素
const
replyListRef
=
ref
<
HTMLDivElement
>
();
// 分组列表
const
options
=
ref
([]);
// 当前选择的分组
const
currentOption
=
ref
(
''
);
// 回复列表
const
replyList
=
ref
([]);
// 是否首次加载
const
isFirst
=
ref
(
true
);
const
loading
=
ref
(
false
);
const
editInfo
=
ref
({});
const
deleteInfo
=
ref
({});
const
isCreate
=
ref
(
true
);
// 新增回复弹窗状态
const
eplyDialogVisible
=
ref
(
false
);
// 确定删除弹窗
const
confirmDialogVisible
=
ref
(
false
);
// 随机播放弹窗
const
randomPlayVisible
=
ref
(
false
);
// 分页
const
pageNum
=
ref
(
1
);
const
pageSize
=
ref
(
10
);
const
total
=
ref
(
0
);
// 初始化分页的值
const
initPage
=
()
=>
{
pageNum
.
value
=
1
;
pageSize
.
value
=
10
;
replyList
.
value
=
[];
};
// 初始化元素滚动位置
const
initElementScrollTop
=
()
=>
{
if
(
replyListRef
.
value
)
{
replyListRef
.
value
.
scrollTo
({
top
:
0
,
behavior
:
'smooth'
,
});
}
};
// 打开随机播放弹窗
const
setRandomPlay
=
()
=>
{
randomPlayVisible
.
value
=
true
;
};
// 打开回复弹窗
const
addEply
=
()
=>
{
eplyDialogVisible
.
value
=
true
;
editInfo
.
value
=
{};
isCreate
.
value
=
true
;
};
// 发送内容
const
sendMessage
=
(
value
:
string
)
=>
{
if
(
props
.
modelValue
||
props
.
playStatus
)
{
show_message
(
'请等待消息发送完毕'
);
return
;
}
emit
(
'message'
,
value
);
};
// 编辑
const
onEdit
=
(
item
:
any
)
=>
{
editInfo
.
value
=
ecursionDeepCopy
(
item
);
eplyDialogVisible
.
value
=
true
;
item
.
popup
=
false
;
isCreate
.
value
=
false
;
};
const
getGroupList
=
(
list
:
any
[])
=>
{
options
.
value
=
list
;
if
(
isFirst
.
value
)
{
// 默认第一个
if
(
options
.
value
.
length
)
{
currentOption
.
value
=
options
.
value
[
0
].
value
;
getList
();
}
isFirst
.
value
=
false
;
}
};
// 打开确定删除弹窗
const
onDelete
=
(
item
:
any
)
=>
{
deleteInfo
.
value
=
item
;
confirmDialogVisible
.
value
=
true
;
item
.
popup
=
false
;
};
// 确定删除
const
confirmDelete
=
async
()
=>
{
try
{
let
res
:
any
=
await
deleteLiveReply
(
deleteInfo
.
value
.
id
);
if
(
res
.
code
==
0
)
{
show_message
(
'删除成功'
,
'success'
);
getList
();
}
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
// 回复内容变化
const
replyChange
=
()
=>
{
initPage
();
getList
();
};
const
groupChange
=
(
value
:
any
)
=>
{
currentOption
.
value
=
value
;
initPage
();
getList
();
};
};
// 获取分组下的回复列表
const
getList
=
async
()
=>
{
try
{
loading
.
value
=
true
;
const
res
:
any
=
await
getLiveReplyList
({
groups_id
:
currentOption
.
value
,
page
:
pageNum
.
value
,
limit
:
pageSize
.
value
,
});
if
(
res
.
code
==
0
)
{
// 回到顶部
if
(
pageNum
.
value
==
1
)
{
initElementScrollTop
();
}
res
.
data
.
data
.
forEach
((
item
:
any
)
=>
{
item
.
popup
=
false
;
});
replyList
.
value
=
replyList
.
value
.
concat
(
res
.
data
.
data
);
// 总量
total
.
value
=
res
.
data
.
total
;
}
loading
.
value
=
false
;
}
catch
(
e
)
{
loading
.
value
=
false
;
console
.
log
(
e
);
}
};
// 滚动事件
const
scrollEvent
=
throttle
(()
=>
{
if
(
loading
.
value
||
replyList
.
value
.
length
>=
total
.
value
)
{
return
;
}
const
scrollTop
=
replyListRef
.
value
.
scrollTop
;
const
scrollHeight
=
replyListRef
.
value
.
scrollHeight
;
const
clientHeight
=
replyListRef
.
value
.
clientHeight
;
// 元素剩余可滚动的距离
const
scrollDistance
=
scrollHeight
-
(
scrollTop
+
clientHeight
);
if
(
scrollDistance
<=
50
)
{
// 下一页
pageNum
.
value
+=
1
;
getList
();
}
},
200
);
onMounted
(()
=>
{
if
(
replyListRef
.
value
)
{
// 监听元素滚动
replyListRef
.
value
.
onscroll
=
scrollEvent
;
}
});
onBeforeUnmount
(()
=>
{
if
(
replyListRef
.
value
)
{
replyListRef
.
value
.
onscroll
=
null
;
}
});
</
script
>
</
script
>
<
style
lang=
"less"
>
<
style
lang=
"less"
>
...
@@ -58,14 +314,101 @@ const imgs = {
...
@@ -58,14 +314,101 @@ const imgs = {
}
}
}
}
.content
{
.content
{
height
:
100%
;
flex
:
1
;
overflow
:
hidden
;
border-radius
:
0px
3px
3px
3px
;
border-radius
:
0px
3px
3px
3px
;
border
:
1px
solid
#464646
;
border
:
1px
solid
#464646
;
background
:
#1e1e1e
;
background
:
#1e1e1e
;
padding
:
12px
;
display
:
flex
;
display
:
flex
;
position
:
relative
;
position
:
relative
;
flex-direction
:
column
;
flex-direction
:
column
;
overflow-y
:
auto
;
.quick-reply-select-group
{
position
:
sticky
;
top
:
0
;
z-index
:
10
;
background-color
:
#1e1e1e
;
padding
:
12px
16px
;
.custom-select-box
{
.t-input
{
border-radius
:
4px
;
background-color
:
#303030
;
width
:
100%
;
}
}
}
.quick-reply-list
{
position
:
relative
;
flex
:
1
;
padding
:
0
16px
12px
16px
;
.quick-reply-row
{
height
:
135px
;
background-color
:
#049c78
;
border-radius
:
4px
;
margin-top
:
12px
;
padding
:
12px
;
display
:
flex
;
flex-direction
:
column
;
position
:
relative
;
.title,
.value
{
color
:
#fff
;
}
.title
{
font-size
:
@
size-18
;
font-weight
:
700
;
}
.value
{
font-size
:
@
size-14
;
padding-top
:
6px
;
flex
:
1
;
overflow-y
:
auto
;
}
.send
{
text-align
:
right
;
.t-button
{
border
:
1px
solid
#464646
;
font-size
:
@
size-14
;
font-weight
:
bold
;
background-color
:
#303030
;
}
}
.dot
{
display
:
flex
;
position
:
absolute
;
right
:
16px
;
top
:
12px
;
cursor
:
pointer
;
&
>
*
{
width
:
7px
;
height
:
7px
;
border-radius
:
50%
;
background-color
:
rgb
(
217
,
217
,
217
);
margin
:
0
2px
;
}
}
}
}
}
}
.quick-reply-row-popup
{
.t-popup__content
{
border
:
1px
solid
#fff
;
}
.quick-reply-row-popup-button
{
color
:
#b4b4b4
;
font-size
:
@
size-14
;
display
:
flex
;
align-items
:
center
;
padding
:
6px
;
cursor
:
pointer
;
img
{
width
:
16px
;
height
:
16px
;
margin-right
:
6px
;
}
}
}
}
}
</
style
>
</
style
>
src/pages/InteractiveResponse/components/randomPlayDialog.vue
0 → 100644
View file @
a065d056
<
template
>
<Dialog
v-model=
"visible"
:footer=
"true"
className=
"random-play-dialog"
>
<template
#
header
>
随机播放设置
</
template
>
<
template
#
body
>
<FormItem
label=
"间隔"
>
<Input
v-model=
"inputValue"
type=
"number"
class=
"random-play-input"
placeholder=
"请输入间隔时间"
align=
"left"
>
<template
#
rightIcon
>
<div
class=
"random-play-input__right"
>
秒
</div>
</
template
>
</Input>
</FormItem>
<FormItem
label=
"状态"
>
<Switch
v-model=
"switchValue"
></Switch>
</FormItem>
</template>
<
template
#
footer
>
<DialogConfirmFooter
save=
"确定"
@
save=
"onSave"
></DialogConfirmFooter>
</
template
>
</Dialog>
</template>
<
script
lang=
"ts"
setup
>
import
Dialog
from
'@/components/Dialog.vue'
;
import
{
computed
,
onMounted
,
ref
}
from
'vue'
;
import
FormItem
from
'@/componentsUsiness/formItem.vue'
;
import
Input
from
'@/components/input/index.vue'
;
import
Switch
from
'@/components/switch'
;
import
DialogConfirmFooter
from
'@/componentsUsiness/dialogConfirmFooter.vue'
;
import
{
show_message
}
from
'@/utils/tool'
;
import
{
useRoute
}
from
'vue-router'
;
import
*
as
cache
from
'@/utils/cache'
;
import
{
randomLiveReply
}
from
'@/utils/api/userApi'
;
const
props
=
withDefaults
(
defineProps
<
{
modelValue
:
boolean
;
loading
:
boolean
;
playStatus
:
boolean
;
textTones
:
string
|
number
;
soundColor
:
string
|
number
;
}
>
(),
{},
);
const
emit
=
defineEmits
([
'update:modelValue'
,
'message'
]);
const
route
=
useRoute
();
// 本地数据的key
const
localKey
=
'reply_random_play_'
;
const
visible
=
computed
({
get
()
{
return
props
.
modelValue
;
},
set
(
value
)
{
emit
(
'update:modelValue'
,
value
);
},
});
let
interval
=
null
;
let
localInterval
=
null
;
// 间隔
const
inputValue
=
ref
(
''
);
const
switchValue
=
ref
(
false
);
// 任务队列
const
taskList
=
ref
([]);
const
getCacheId
=
()
=>
{
return
localKey
+
route
.
query
.
id
;
};
// 获取随机内容
const
getRandomValue
=
async
()
=>
{
try
{
let
res
:
any
=
await
randomLiveReply
();
if
(
res
.
code
==
0
&&
res
.
data
.
content
)
{
// 加入队列
taskList
.
value
.
push
(
res
.
data
.
content
);
}
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
// 打开定时器(从后台获取随机内容)
const
openInterval
=
()
=>
{
closeInterval
();
interval
=
window
.
setInterval
(
getRandomValue
,
parseInt
(
inputValue
.
value
)
*
1000
);
};
// 关闭定时器
const
closeInterval
=
()
=>
{
window
.
clearInterval
(
interval
);
clearInterval
(
interval
);
interval
=
null
;
};
// 打开定时器(从本地队列里取任务)
const
openLocalInterval
=
()
=>
{
localInterval
=
window
.
setInterval
(()
=>
{
// 禁止取任务
if
(
!
switchValue
.
value
||
props
.
loading
||
props
.
playStatus
||
!
taskList
.
value
.
length
||
!
props
.
textTones
||
!
props
.
soundColor
)
{
return
;
}
// 取任务
emit
(
'message'
,
taskList
.
value
[
0
]);
// 删除这条任务
taskList
.
value
.
shift
();
},
5000
);
};
const
onSave
=
()
=>
{
if
(
!
route
.
query
.
id
)
{
show_message
(
'禁止访问'
);
return
;
}
if
(
switchValue
.
value
&&
!
inputValue
.
value
)
{
show_message
(
'间隔时间必填,或关闭随机播放'
);
return
;
}
if
(
!
switchValue
.
value
)
{
// 关闭定时任务
closeInterval
();
// 清空队列
taskList
.
value
=
[];
}
else
{
openInterval
();
}
// 数据存本地,根据id
cache
.
setCache
(
getCacheId
(),
{
interval
:
inputValue
.
value
,
status
:
switchValue
.
value
,
});
visible
.
value
=
false
;
};
const
init
=
()
=>
{
const
data
=
cache
.
getCache
(
getCacheId
());
if
(
data
)
{
inputValue
.
value
=
data
.
interval
;
switchValue
.
value
=
data
.
status
;
}
// 打开随机播放
if
(
inputValue
.
value
&&
switchValue
.
value
)
{
openInterval
();
}
};
onMounted
(()
=>
{
init
();
openLocalInterval
();
});
</
script
>
<
style
lang=
"less"
>
@import
'@/style/variables.less'
;
.random-play-dialog
{
.t-dialog__body
{
margin-top
:
20px
;
.custom-usiness-form-item
{
align-items
:
center
;
.random-play-input
{
flex
:
1
;
.random-play-input__right
{
background
:
#5a5a5a
;
border-radius
:
0px
4px
4px
0px
;
color
:
#fff
;
font-size
:
@
size-12
;
font-weight
:
600
;
width
:
45px
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
height
:
100%
;
}
}
}
}
.dialog-confirm-footer
{
padding
:
0
;
align-items
:
flex-end
;
}
}
</
style
>
src/pages/InteractiveResponse/index.vue
View file @
a065d056
<
template
>
<
template
>
<div
class=
"custom-interactive-response-page"
>
<div
class=
"custom-interactive-response-page"
>
<QuickReply></QuickReply>
<QuickReply
<Human
@
createAudio=
"createAudio"
>
v-model=
"loading"
:soundColor=
"soundColorValue"
:textTones=
"textTonesValue"
:playStatus=
"playStatus"
@
message=
"onMessage"
></QuickReply>
<Human
v-model=
"loading"
v-model:soundColor=
"soundColorValue"
v-model:textTones=
"textTonesValue"
:message=
"message"
:sendNum=
"sendNum"
@
createAudio=
"createAudio"
>
<div
v-show=
"false"
>
<div
v-show=
"false"
>
<audio
<audio
:volume=
"liveDefaultVolume"
:volume=
"liveDefaultVolume"
...
@@ -22,9 +35,25 @@ import Human from './components/human.vue';
...
@@ -22,9 +35,25 @@ import Human from './components/human.vue';
import
{
callPyjsInWindow
}
from
'@/utils/pyqt'
;
import
{
callPyjsInWindow
}
from
'@/utils/pyqt'
;
import
QuickReply
from
'./components/quickReply.vue'
;
import
QuickReply
from
'./components/quickReply.vue'
;
// 音色id
const
soundColorValue
=
ref
(
''
);
// 音调id
const
textTonesValue
=
ref
(
''
);
// 音频文件
// 音频文件
const
audioRef
=
ref
<
HTMLAudioElement
>
();
const
audioRef
=
ref
<
HTMLAudioElement
>
();
const
audioFile
=
ref
(
''
);
const
audioFile
=
ref
(
''
);
const
loading
=
ref
(
false
);
const
message
=
ref
(
''
);
const
sendNum
=
ref
(
1
);
// 当前是否正在播放
const
playStatus
=
ref
(
false
);
// 接收回复内容
const
onMessage
=
(
value
:
string
)
=>
{
message
.
value
=
value
;
sendNum
.
value
+=
1
;
};
const
createAudio
=
(
url
:
string
)
=>
{
const
createAudio
=
(
url
:
string
)
=>
{
audioFile
.
value
=
url
;
audioFile
.
value
=
url
;
...
@@ -32,12 +61,14 @@ const createAudio = (url: string) => {
...
@@ -32,12 +61,14 @@ const createAudio = (url: string) => {
const
audioCanplay
=
()
=>
{
const
audioCanplay
=
()
=>
{
audioRef
.
value
.
play
();
audioRef
.
value
.
play
();
playStatus
.
value
=
true
;
// 通知python将直播页面的音量减小
// 通知python将直播页面的音量减小
callPyjsInWindow
(
'lowerVideoVolume'
);
callPyjsInWindow
(
'lowerVideoVolume'
);
};
};
// 音频播放结束
// 音频播放结束
const
audioEnded
=
()
=>
{
const
audioEnded
=
()
=>
{
playStatus
.
value
=
false
;
// 通知python将直播页面的音量恢复
// 通知python将直播页面的音量恢复
callPyjsInWindow
(
'videoVolumeRestoration'
);
callPyjsInWindow
(
'videoVolumeRestoration'
);
};
};
...
...
src/pages/OnlyVideoLive/useScript.ts
View file @
a065d056
...
@@ -244,17 +244,13 @@ export default function () {
...
@@ -244,17 +244,13 @@ export default function () {
}
}
};
};
// 找到所有已经播放完毕的主视频
// 找到所有已经播放完毕的主视频
let
playEndVideos
=
realVideoList
.
value
.
map
((
row
:
any
,
index
:
number
)
=>
{
let
playEndVideos
=
[];
realVideoList
.
value
.
forEach
((
row
:
any
,
index
:
number
)
=>
{
if
(
row
.
remove
&&
row
.
result
&&
row
.
status
&&
typeof
index
===
'number'
)
{
if
(
row
.
remove
&&
row
.
result
&&
row
.
status
&&
typeof
index
===
'number'
)
{
return
index
;
playEndVideos
.
push
(
index
);
}
});
// 再次过滤
playEndVideos
=
playEndVideos
.
map
((
row
:
any
,
index
:
number
)
=>
{
if
(
typeof
index
===
'number'
)
{
return
index
;
}
}
});
});
console
.
log
(
playEndVideos
,
'随机下标列表'
);
if
(
playEndVideos
.
length
)
{
if
(
playEndVideos
.
length
)
{
if
(
playEndVideos
.
length
===
1
)
{
if
(
playEndVideos
.
length
===
1
)
{
console
.
log
(
'只有一条视频播放完毕,重新播放该视频'
);
console
.
log
(
'只有一条视频播放完毕,重新播放该视频'
);
...
@@ -263,7 +259,22 @@ export default function () {
...
@@ -263,7 +259,22 @@ export default function () {
// 多条视频
// 多条视频
// 随机下标
// 随机下标
let
num
=
randomIntFormList
(
playEndVideos
);
let
num
=
randomIntFormList
(
playEndVideos
);
// 防止出错
try
{
if
(
typeof
num
!==
'number'
||
!
realVideoList
.
value
[
num
])
{
console
.
log
(
'num格式错误,初始化第1个视频'
,
num
);
num
=
0
;
}
}
catch
(
e
)
{
num
=
0
;
console
.
log
(
e
,
'初始化旧视频出错了,将num改为0'
);
writeLog
({
name
:
'初始化旧视频出错了,将num改为0'
,
value
:
e
,
});
}
console
.
log
(
`初始化第
${
num
}
个视频`
);
console
.
log
(
`初始化第
${
num
}
个视频`
);
console
.
log
(
realVideoList
.
value
[
num
]);
// 链接是否一致
// 链接是否一致
if
(
realVideoList
.
value
[
num
].
result
===
item
.
url
)
{
if
(
realVideoList
.
value
[
num
].
result
===
item
.
url
)
{
// 循环播放
// 循环播放
...
@@ -612,11 +623,11 @@ export default function () {
...
@@ -612,11 +623,11 @@ export default function () {
url
:
url
,
url
:
url
,
type
:
1
,
type
:
1
,
},
},
{
//
{
url
:
'http://yunyi-live.oss-cn-hangzhou.aliyuncs.com/upload/2/2023-08-217a51d89c-1a9f-476b-950c-f81d0423b816.mp4'
,
//
url: 'http://yunyi-live.oss-cn-hangzhou.aliyuncs.com/upload/2/2023-08-217a51d89c-1a9f-476b-950c-f81d0423b816.mp4',
type
:
3
,
//
type: 3,
play_time
:
0
,
//
play_time: 0,
},
//
},
];
];
res
.
data
.
url
=
list
;
res
.
data
.
url
=
list
;
...
...
src/pages/VocalCustomization/components/MyDigitalPerson.vue
View file @
a065d056
...
@@ -77,7 +77,7 @@ const confirm = () => {
...
@@ -77,7 +77,7 @@ const confirm = () => {
<
style
lang=
"less"
>
<
style
lang=
"less"
>
@import
'@/style/variables'
;
@import
'@/style/variables'
;
.image-custom-my-person-box
{
.image-custom-my-person-box
{
padding
:
30px
4
0px
;
padding
:
30px
2
0px
;
border-radius
:
4px
4px
0px
0px
;
border-radius
:
4px
4px
0px
0px
;
background
:
#303030
;
background
:
#303030
;
box-shadow
:
0px
0px
8px
0px
rgba
(
0
,
0
,
0
,
0.04
);
box-shadow
:
0px
0px
8px
0px
rgba
(
0
,
0
,
0
,
0.04
);
...
...
src/pages/VocalCustomization/index.vue
View file @
a065d056
...
@@ -9,7 +9,7 @@
...
@@ -9,7 +9,7 @@
version=
"v1"
version=
"v1"
:label=
"'声音定制'"
:label=
"'声音定制'"
>
>
<CustomTabs
v-model=
"currentTab"
theme=
"dark2"
>
<CustomTabs
v-model=
"currentTab"
theme=
"dark2"
class=
"custom-tabs-flex"
>
<CustomTabPanel
name=
"1"
label=
"我的音色"
>
<CustomTabPanel
name=
"1"
label=
"我的音色"
>
<MyDigitalPerson
:list=
"personList.list"
:loading=
"loading"
@
playAudio=
"myAudioPlay"
></MyDigitalPerson>
<MyDigitalPerson
:list=
"personList.list"
:loading=
"loading"
@
playAudio=
"myAudioPlay"
></MyDigitalPerson>
</CustomTabPanel>
</CustomTabPanel>
...
@@ -94,8 +94,10 @@ const getList = async () => {
...
@@ -94,8 +94,10 @@ const getList = async () => {
item
.
play_status
=
false
;
item
.
play_status
=
false
;
});
});
personList
.
list
=
res
.
soundColor
;
personList
.
list
=
res
.
soundColor
;
// 复制一份给记录列表
// 复制一份给记录列表
personList
.
record
=
dimensionalConvert
(
res
.
soundColor
);
personList
.
record
=
dimensionalConvert
(
res
.
soundColor
);
loading
.
value
=
false
;
loading
.
value
=
false
;
}
catch
(
e
)
{
}
catch
(
e
)
{
loading
.
value
=
false
;
loading
.
value
=
false
;
...
...
src/pages/createAction/components/createSuccess/index.less
View file @
a065d056
@import '@/style/variables';
@import '@/style/variables';
.action-create-success-tab {
.action-create-success-tab {
padding: 30px
4
0px;
padding: 30px
3
0px;
border-radius: 4px 4px 0px 0px;
border-radius: 4px 4px 0px 0px;
background: #303030;
background: #303030;
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.04);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.04);
...
...
src/pages/createAction/index.less
View file @
a065d056
@import '@/style/variables.less';
@import '@/style/variables.less';
.custom-action-page {
.custom-action-page {
height: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
.header {
.header {
margin
: 20px 0;
padding
: 20px 0;
.da();
.da();
font-size: @size-24;
font-size: @size-24;
font-weight: 700;
font-weight: 700;
...
@@ -79,6 +83,8 @@
...
@@ -79,6 +83,8 @@
}
}
}
}
.izable-page-tabs {
.izable-page-tabs {
margin-top: 50px;
padding-top: 50px;
flex: 1;
box-sizing: border-box;
}
}
}
}
src/pages/createAction/index.tsx
View file @
a065d056
...
@@ -237,7 +237,7 @@ export default defineComponent({
...
@@ -237,7 +237,7 @@ export default defineComponent({
</
div
>
</
div
>
</
div
>
</
div
>
<
div
class=
"izable-page-tabs"
>
<
div
class=
"izable-page-tabs"
>
<
CustomTabs
v
-
model=
{
currentTab
.
value
}
theme=
"dark2"
onChange=
{
tabsChange
}
>
<
CustomTabs
v
-
model=
{
currentTab
.
value
}
theme=
"dark2"
class=
"custom-tabs-flex"
onChange=
{
tabsChange
}
>
<
CustomTabPanel
<
CustomTabPanel
name=
"1"
name=
"1"
label=
"已创建"
label=
"已创建"
...
...
src/pages/home/components/myDigtalPeople.vue
View file @
a065d056
...
@@ -18,9 +18,7 @@
...
@@ -18,9 +18,7 @@
>
>
</
template
>
</
template
>
<
template
v-else
>
<
template
v-else
>
<Button
class=
"digtal-people-start-end"
theme=
"danger"
height=
"40px"
@
click=
"startLive(item)"
<Button
class=
"digtal-people-start-end"
theme=
"danger"
height=
"40px"
>
开播中
</Button>
>
开播中
</Button
>
<Button
class=
"digtal-people-ctrl"
theme=
"danger"
height=
"40px"
@
click=
"openInteractiveResponse(item)"
<Button
class=
"digtal-people-ctrl"
theme=
"danger"
height=
"40px"
@
click=
"openInteractiveResponse(item)"
>
控制台
</Button
>
控制台
</Button
>
>
...
...
src/style/ui.less
View file @
a065d056
...
@@ -70,3 +70,14 @@ html {
...
@@ -70,3 +70,14 @@ html {
background: #b4b4b4;
background: #b4b4b4;
border-radius: 8px;
border-radius: 8px;
}
}
.custom-tabs-flex {
height: 100%;
display: flex;
flex-direction: column;
.c-tabs-content {
flex: 1;
overflow-y: auto;
background-color: #303030;
}
}
src/utils/api/userApi.ts
View file @
a065d056
...
@@ -430,3 +430,91 @@ export const getLiveMovement = () => {
...
@@ -430,3 +430,91 @@ export const getLiveMovement = () => {
},
},
});
});
};
};
/**
* 中控台快捷回复模块
*/
// 创建分组
export
const
createEplyGroup
=
(
data
:
any
)
=>
{
const
header
=
getHeader
();
return
request
.
post
(
`/api/live/groups/interaction`
,
data
,
{
headers
:
{
...
header
,
},
});
};
// 获取分组列表
export
const
getEplyGroup
=
()
=>
{
const
header
=
getHeader
();
return
request
.
get
(
`/api/live/groups/interaction`
,
{
params
:
{},
headers
:
{
...
header
,
},
});
};
// 删除分组
export
const
deleteEplyGroup
=
(
id
:
number
|
string
)
=>
{
const
header
=
getHeader
();
return
request
.
delete
(
`/api/live/groups/interaction/
${
id
}
`
,
{
params
:
{},
headers
:
{
...
header
,
},
});
};
// 创建回复内容
export
const
createEplyContent
=
(
data
:
any
)
=>
{
const
header
=
getHeader
();
return
request
.
post
(
`/api/live/reply`
,
data
,
{
headers
:
{
...
header
,
},
});
};
// 获取回复内容列表
export
const
getLiveReplyList
=
(
data
:
any
)
=>
{
const
header
=
getHeader
();
return
request
.
get
(
`/api/live/reply`
,
{
params
:
data
,
headers
:
{
...
header
,
},
});
};
// 更新回复内容
export
const
updateLiveReply
=
(
id
:
number
|
string
,
data
:
any
)
=>
{
const
header
=
getHeader
();
return
request
.
post
(
`/api/live/reply/
${
id
}
`
,
data
,
{
headers
:
{
...
header
,
},
});
};
// 删除回复内容
export
const
deleteLiveReply
=
(
id
:
number
|
string
)
=>
{
const
header
=
getHeader
();
return
request
.
delete
(
`/api/live/reply/
${
id
}
`
,
{
params
:
{},
headers
:
{
...
header
,
},
});
};
// 随机获取回复内容
export
const
randomLiveReply
=
()
=>
{
const
header
=
getHeader
();
return
request
.
get
(
`/api/live/reply/rand`
,
{
params
:
{},
headers
:
{
...
header
,
},
});
};
src/utils/cache.ts
0 → 100644
View file @
a065d056
// set
export
const
setCache
=
(
key
:
string
,
value
:
any
,
type
:
'local'
|
'session'
=
'local'
)
=>
{
if
(
type
===
'local'
)
{
window
.
localStorage
.
setItem
(
key
,
JSON
.
stringify
(
value
));
}
else
{
window
.
sessionStorage
.
setItem
(
key
,
JSON
.
stringify
(
value
));
}
};
// get
export
const
getCache
=
(
key
:
string
,
type
:
'local'
|
'session'
=
'local'
)
=>
{
let
data
=
null
;
if
(
type
===
'local'
)
{
data
=
window
.
localStorage
.
getItem
(
key
);
}
else
{
data
=
window
.
sessionStorage
.
getItem
(
key
);
}
if
(
data
)
{
return
JSON
.
parse
(
data
);
}
return
data
;
};
src/utils/request.ts
View file @
a065d056
...
@@ -29,8 +29,8 @@ const getBaseUrl = async () => {
...
@@ -29,8 +29,8 @@ const getBaseUrl = async () => {
const
instance
=
axios
.
create
({
const
instance
=
axios
.
create
({
baseURL
:
''
,
baseURL
:
''
,
//
withCredentials: false,
withCredentials
:
false
,
withCredentials
:
isDev
()
?
true
:
false
,
//
withCredentials: isDev() ? true : false,
});
});
// 请求拦截
// 请求拦截
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment