fix: 区域优化

This commit is contained in:
old burden 2026-04-02 09:51:41 +08:00
parent d2c1fff13f
commit f075e6b2b1
2 changed files with 210 additions and 81 deletions

View File

@ -74,12 +74,6 @@
上传资产
</mf-button>
</div>
<div class="vg-asset-controls">
<input v-model.trim="newGroupName" class="vg-asset-group-input" placeholder="输入新素材组名称" />
<mf-button class="vg-compose-left-upload" size="small" type="primary" @click="createAssetGroup" :loading="groupLoading">
新建素材组
</mf-button>
</div>
<div v-if="mediaList.length === 0" class="vg-compose-empty" @click="openFilePicker">
<div class="vg-compose-empty-icon" aria-hidden="true">+</div>
@ -115,12 +109,34 @@
</div>
</div>
</div>
<!-- 文生视频模式 - 左侧不显示素材 -->
<div v-else class="vg-compose-left hidden">
<!-- 文生视频无需参考素材 -->
</div>
<a-modal
v-model:visible="assetPickerVisible"
title="选择素材"
:ok-button-props="{ disabled: !assetPickerSelectedKeys.length }"
@ok="confirmPickAssets">
<div class="vg-asset-picker">
<div v-if="assetQueryResults.length === 0" class="vg-asset-picker-empty">当前分组暂无可用素材</div>
<label v-for="it in assetQueryResults" :key="it.assetId || it.id" class="vg-asset-picker-item">
<input
type="checkbox"
:value="String(it.assetId || it.id)"
v-model="assetPickerSelectedKeys"
/>
<div class="vg-asset-picker-preview">
<img v-if="it.mediaType === 'image'" :src="it.url" alt="" />
<video v-else-if="it.mediaType === 'video'" :src="it.url" muted playsinline preload="metadata"></video>
<div v-else class="vg-audio-tile"> 音频</div>
</div>
<div class="vg-asset-picker-name">{{ it.name || it.assetId }}</div>
</label>
</div>
</a-modal>
<div class="vg-compose-right">
<div class="vg-compose-right-head">
<div class="vg-compose-right-title">描述画面与动态</div>
@ -178,7 +194,7 @@ import { computed, getCurrentInstance, nextTick, onMounted, ref, watch } from 'v
import { Message } from '@arco-design/web-vue'
import { uploadFile, extractUploadUrlFromResponse, PORTAL_TENCENT_COS_UPLOAD_URL } from '@/utils/file'
/** 参考素材:同类最多不同素材条数(同一素材可多次 @),与 maxMediaCount 对齐 */
/** 参考素材:@ 引用同一类(图/视频/音频)最多 9 种不同素材;左侧列表最多可插入 12 条(由 maxMediaCount 控制) */
const MAX_REFERENCE_UNIQUE_KIND = 9
const props = defineProps({
@ -223,7 +239,9 @@ const assetGroupId = ref('')
const assetLoading = ref(false)
const groupLoading = ref(false)
const assetGroups = ref([])
const newGroupName = ref('')
const assetPickerVisible = ref(false)
const assetQueryResults = ref([])
const assetPickerSelectedKeys = ref([])
watch(
() => props.modelValue,
@ -415,35 +433,6 @@ const loadAssetGroups = async () => {
}
}
const createAssetGroup = async () => {
const name = String(newGroupName.value || '').trim()
if (!name) {
Message.warning('请输入素材组名称')
return
}
if (!proxy?.$axios) return
groupLoading.value = true
try {
const res = await proxy.$axios({
url: 'api/byteAssetGroup/createAssetGroup',
method: 'POST',
data: {
Name: name,
ProjectName: 'default'
}
})
const gid = res?.data?.Id || res?.data?.id || ''
newGroupName.value = ''
await loadAssetGroups()
if (gid) assetGroupId.value = gid
Message.success('素材组创建成功')
} catch (err) {
Message.error(err?.message || '创建素材组失败')
} finally {
groupLoading.value = false
}
}
const loadAssetsByGroup = async () => {
const gid = String(assetGroupId.value || '').trim()
if (!gid) {
@ -487,8 +476,10 @@ const loadAssetsByGroup = async () => {
}
})
.filter((x) => x.assetId && /^https?:\/\//i.test(String(x.url || '').trim()))
mergeAssetsToMediaList(assets)
Message.success(`已加载 ${assets.length} 条可用素材`)
assetQueryResults.value = assets
assetPickerSelectedKeys.value = []
assetPickerVisible.value = true
Message.success(`查询到 ${assets.length} 条可用素材`)
} catch (err) {
Message.error(err?.message || '查询素材失败')
} finally {
@ -496,6 +487,16 @@ const loadAssetsByGroup = async () => {
}
}
const confirmPickAssets = () => {
const pickedKeys = new Set((assetPickerSelectedKeys.value || []).map((x) => String(x)))
const picked = (assetQueryResults.value || []).filter((x) =>
pickedKeys.has(String(x.assetId || x.id))
)
mergeAssetsToMediaList(picked)
assetPickerVisible.value = false
assetPickerSelectedKeys.value = []
}
const handleSelectFiles = async (event) => {
const input = event.target
const files = Array.from(input.files || [])
@ -1136,22 +1137,22 @@ defineExpose({
<style scoped lang="less">
.vg-compose-card {
display: flex;
gap: 16px;
gap: 12px;
align-items: stretch;
background: rgba(22, 24, 30, 0.92);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 18px;
padding: 10px;
padding: 8px;
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.06);
min-height: 240px;
min-height: 200px;
}
.vg-compose-left {
width: 260px;
width: 240px;
flex-shrink: 0;
display: flex;
flex-direction: column;
gap: 12px;
gap: 10px;
}
.vg-compose-left.hidden {
@ -1285,6 +1286,54 @@ defineExpose({
box-shadow: 0 0 0 2px rgba(0, 202, 224, 0.12);
}
.vg-asset-picker {
display: flex;
flex-direction: column;
gap: 8px;
max-height: 420px;
overflow: auto;
}
.vg-asset-picker-item {
display: grid;
grid-template-columns: 18px 56px 1fr;
gap: 8px;
align-items: center;
padding: 8px;
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 8px;
}
.vg-asset-picker-preview {
width: 56px;
height: 56px;
border-radius: 6px;
overflow: hidden;
background: rgba(255, 255, 255, 0.06);
display: flex;
align-items: center;
justify-content: center;
}
.vg-asset-picker-preview img,
.vg-asset-picker-preview video {
width: 100%;
height: 100%;
object-fit: cover;
}
.vg-asset-picker-name {
font-size: 12px;
color: rgba(255, 255, 255, 0.85);
word-break: break-all;
}
.vg-asset-picker-empty {
color: rgba(255, 255, 255, 0.6);
font-size: 12px;
padding: 8px 0;
}
.hidden-input {
display: none;
}
@ -1335,8 +1384,8 @@ defineExpose({
}
.vg-compose-media-item {
width: 96px;
height: 96px;
width: 80px;
height: 80px;
scroll-snap-align: start;
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.1);
@ -1429,12 +1478,12 @@ defineExpose({
.vg-compose-textarea {
flex: 1;
min-height: 150px;
min-height: 120px;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 16px;
border-radius: 12px;
padding: 8px 10px;
font-size: 14px;
line-height: 1.6;
line-height: 1.55;
color: rgba(255, 255, 255, 0.92);
resize: none;
outline: none;
@ -1446,7 +1495,8 @@ defineExpose({
flex: 1;
display: flex;
flex-direction: column;
min-height: 150px;
min-height: 120px;
min-width: 0;
}
.vg-rich-editor {
@ -1610,5 +1660,36 @@ defineExpose({
width: 100%;
}
}
/* 小于 1920 宽:参考素材与富文本上下排列,避免横向过窄时布局错乱 */
@media (max-width: 1919px) {
.vg-compose-card {
flex-direction: column;
align-items: stretch;
min-height: 0;
}
.vg-compose-left {
width: 100%;
}
.vg-reference-panel {
min-height: 0;
}
.vg-compose-media-scroll {
max-width: 100%;
}
.vg-compose-right {
flex: 1;
min-width: 0;
width: 100%;
}
.vg-rich-editor-wrap {
min-height: 100px;
}
}
</style>

View File

@ -183,7 +183,7 @@
@click="generateVideo"
:title="price ? $t('common.createVideo', { price }) : $t('common.generateVideo')">
<span class="vg-submit-circle-inner">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor" d="M12.002 3c.424 0 .806.177 1.079.46l5.98 5.98.103.114a1.5 1.5 0 0 1-2.225 2.006l-3.437-3.436V19.5l-.008.153a1.5 1.5 0 0 1-2.985 0l-.007-.153V8.122l-3.44 3.438a1.5 1.5 0 0 1-2.225-2.006l.103-.115 6-5.999.025-.025.059-.052.044-.037c.029-.023.06-.044.09-.065l.014-.01a1.43 1.43 0 0 1 .101-.062l.03-.017c.209-.11.447-.172.699-.172Z" />
</svg>
</span>
@ -262,7 +262,7 @@ export default {
maxMediaCount() {
if (this.videoMode === 'image-first-frame') return 1
if (this.videoMode === 'image-first-last-frame') return 2
if (this.videoMode === 'image-reference') return 9
if (this.videoMode === 'image-reference') return 12
return 12
},
allowedMediaTypes() {
@ -989,8 +989,8 @@ export default {
flex-direction: column;
min-height: 100%;
height: 100%;
gap: 20px;
padding: 28px 28px 32px;
gap: 14px;
padding: 20px 20px 16px;
box-sizing: border-box;
overflow-y: hidden;
overflow-x: hidden;
@ -1001,11 +1001,11 @@ export default {
/* —— Body —— */
.vg-body {
display: flex;
flex: 0 0 auto;
flex: 0 1 auto;
order: 1;
min-height: 0;
max-height: none;
gap: 16px;
max-height: min(48vh, 560px);
gap: 12px;
align-items: stretch;
}
@ -1075,12 +1075,13 @@ export default {
.vg-generator-inner {
flex: 1;
min-height: 0;
overflow-y: visible;
overflow-y: auto;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
display: flex;
flex-direction: column;
gap: 16px;
padding: 16px;
gap: 10px;
padding: 12px 14px;
background: var(--vg-panel);
border: 1px solid var(--vg-border);
border-radius: 20px;
@ -1194,11 +1195,11 @@ export default {
.vg-toolbar {
display: flex;
align-items: center;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
margin-top: 14px;
padding-top: 14px;
gap: 10px;
margin-top: 8px;
padding-top: 10px;
border-top: 1px solid var(--vg-border);
}
@ -1211,10 +1212,10 @@ export default {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 12px 14px;
padding: 6px 10px;
gap: 8px 10px;
padding: 4px 8px;
background: rgba(0, 0, 0, 0.2);
border-radius: 12px;
border-radius: 10px;
border: 1px solid var(--vg-border);
}
@ -1222,41 +1223,44 @@ export default {
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
flex: 1 1 220px;
min-width: 200px;
gap: 6px;
flex: 1 1 160px;
min-width: 0;
}
.vg-param-label {
font-size: 12px;
font-size: 11px;
color: var(--vg-muted);
font-weight: 600;
white-space: nowrap;
min-width: 48px;
min-width: 44px;
}
.vg-param-select {
flex: 1;
min-width: 120px;
min-width: 0;
:deep(.arco-select-view-single) {
background: rgba(0, 0, 0, 0.2) !important;
border: 1px solid var(--vg-border) !important;
border-radius: 10px !important;
border-radius: 8px !important;
color: var(--vg-text) !important;
min-height: 30px !important;
}
:deep(.arco-select-view-value) {
color: var(--vg-text) !important;
font-size: 12px;
}
}
.vg-toolbar-actions {
flex-shrink: 0;
align-self: center;
}
.vg-submit-circle {
width: 52px;
height: 52px;
width: 42px;
height: 42px;
padding: 0;
border: none;
border-radius: 50%;
@ -1424,13 +1428,13 @@ export default {
.vg-chat-section {
order: 0;
flex: 1;
margin-top: 8px;
padding: 18px 22px;
flex: 1 1 auto;
margin-top: 0;
padding: 14px 18px;
background: var(--vg-panel);
border: 1px solid var(--vg-border);
border-radius: 16px;
min-height: 0;
min-height: min(42vh, 480px);
display: flex;
flex-direction: column;
}
@ -1685,4 +1689,48 @@ export default {
.vg-link:hover {
text-decoration: underline;
}
/* 小于 1920×1080 常见宽度:底部参数区纵向排布,避免挤压富文本 */
@media (max-width: 1919px) {
.video-gen {
padding: 14px 12px 12px;
gap: 10px;
}
.vg-chat-section {
min-height: min(40vh, 440px);
padding: 12px 14px;
}
.vg-body {
max-height: min(50vh, 540px);
}
.vg-generator-inner {
padding: 10px 12px;
gap: 8px;
}
.vg-toolbar {
flex-direction: column;
align-items: stretch;
gap: 8px;
}
.vg-toolbar-actions {
align-self: flex-end;
}
.vg-params-row {
flex-direction: column;
align-items: stretch;
gap: 8px;
}
.vg-param {
flex: 1 1 auto;
width: 100%;
min-width: 0;
}
}
</style>