|
@@ -470,63 +470,11 @@
|
|
|
@confirm="handleScenePromptConfirm" @cancel="scenePromptDialogVisible = false" />
|
|
@confirm="handleScenePromptConfirm" @cancel="scenePromptDialogVisible = false" />
|
|
|
|
|
|
|
|
<!-- 货号选择弹窗 -->
|
|
<!-- 货号选择弹窗 -->
|
|
|
- <el-dialog v-model="goodsSelectDialogVisible" title="请选择一个货号作为自定义商品的模板" width="60%" :close-on-click-modal="false"
|
|
|
|
|
- :close-on-press-escape="false" custom-class="goods-select-dialog">
|
|
|
|
|
- <div class="goods-select-content">
|
|
|
|
|
- <el-radio-group v-model="selectedGoodsArtNo" class="goods-radio-group">
|
|
|
|
|
- <div v-for="item in filteredGoodsList" :key="item.goods_art_no" class="goods-item"
|
|
|
|
|
- :class="{ 'selected': selectedGoodsArtNo === item.goods_art_no }"
|
|
|
|
|
- @click="selectedGoodsArtNo = item.goods_art_no">
|
|
|
|
|
-
|
|
|
|
|
- <div class="goods-item-header">
|
|
|
|
|
- <div class="goods-item-left flex left">
|
|
|
|
|
- <el-radio :label="item.goods_art_no" class="goods-radio" @click.stop> </el-radio>
|
|
|
|
|
- <span class="goods-art-no">{{ item.goods_art_no }}</span>
|
|
|
|
|
-
|
|
|
|
|
- <div class="goods-item-meta ">
|
|
|
|
|
- <span class="action-time flex left">
|
|
|
|
|
-
|
|
|
|
|
- <img src="@/assets/images/processImage.vue/riq.png" />
|
|
|
|
|
- {{ getTime(item.action_time) }}</span>
|
|
|
|
|
- <span class="image-count mar-left-10 flex left">
|
|
|
|
|
- <img src="@/assets/images/processImage.vue/tup.png" />
|
|
|
|
|
- {{ item.items?.length || 0 }}张图片</span>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="goods-item-images">
|
|
|
|
|
- <div v-for="(image, index) in item.items" :key="image.action_id || image.action_name"
|
|
|
|
|
- class="goods-item_image">
|
|
|
|
|
- <span class="tag" v-if="!image.PhotoRecord?.image_path">{{ image.action_name }}</span>
|
|
|
|
|
- <el-image v-if="image.PhotoRecord?.image_path" :src="getFilePath(image.PhotoRecord.image_path)"
|
|
|
|
|
- :preview-src-list="getPreviewImageList(item)" :initial-index="getPreviewIndex(item, index)"
|
|
|
|
|
- class="preview-image" fit="contain" :preview-teleported="true" lazy>
|
|
|
|
|
- <template #error>
|
|
|
|
|
- <div class="image-slot">
|
|
|
|
|
- <span class="tag">{{ image.action_name }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </template>
|
|
|
|
|
- </el-image>
|
|
|
|
|
- <div v-else class="image-placeholder">
|
|
|
|
|
- <span class="tag">{{ image.action_name }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- </div>
|
|
|
|
|
- </el-radio-group>
|
|
|
|
|
- </div>
|
|
|
|
|
- <template #footer>
|
|
|
|
|
- <div class="dialog-footer">
|
|
|
|
|
- <el-button @click="cancelGoodsSelection">取消</el-button>
|
|
|
|
|
- <el-button type="primary" :loading="goodsGenerateLoading" :disabled="goodsGenerateLoading"
|
|
|
|
|
- @click="confirmGoodsSelection">
|
|
|
|
|
- {{ goodsGenerateLoading ? '正在生成自定义商品模版' : '确定' }}
|
|
|
|
|
- </el-button>
|
|
|
|
|
- </div>
|
|
|
|
|
- </template>
|
|
|
|
|
- </el-dialog>
|
|
|
|
|
|
|
+ <GoodsSelectDialog
|
|
|
|
|
+ v-model:visible="goodsSelectDialogVisible"
|
|
|
|
|
+ @confirm="handleGoodsSelectionConfirm"
|
|
|
|
|
+ @cancel="handleGoodsSelectionCancel"
|
|
|
|
|
+ />
|
|
|
|
|
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -556,6 +504,7 @@ const socketStore = socket();
|
|
|
const useUserInfoStore = useUserInfo();
|
|
const useUserInfoStore = useUserInfo();
|
|
|
import ModelGenerationDialog from '@/components/ModelGeneration/index.vue'
|
|
import ModelGenerationDialog from '@/components/ModelGeneration/index.vue'
|
|
|
import ScenePromptDialog from '@/components/ScenePromptDialog/index.vue'
|
|
import ScenePromptDialog from '@/components/ScenePromptDialog/index.vue'
|
|
|
|
|
+import GoodsSelectDialog from './components/GoodsSelectDialog.vue'
|
|
|
|
|
|
|
|
import { Close, Warning } from '@element-plus/icons-vue'
|
|
import { Close, Warning } from '@element-plus/icons-vue'
|
|
|
import LoadingDialog from '@/views/Photography/components/LoadingDialog.vue'
|
|
import LoadingDialog from '@/views/Photography/components/LoadingDialog.vue'
|
|
@@ -569,13 +518,8 @@ const EXTERNAL_TOOL_EXECUTABLE = '智慧映拍照机辅助工具箱.exe'
|
|
|
|
|
|
|
|
import usePhotography from './mixin/usePhotography'
|
|
import usePhotography from './mixin/usePhotography'
|
|
|
|
|
|
|
|
-const {
|
|
|
|
|
- loading,
|
|
|
|
|
- goodsList,
|
|
|
|
|
- getPhotoRecords,
|
|
|
|
|
- getTime,
|
|
|
|
|
- getFilePath,
|
|
|
|
|
-} = usePhotography()
|
|
|
|
|
|
|
+// 从 mixin 中导入必要的函数和状态(已不再使用,保留以防其他地方需要)
|
|
|
|
|
+const { } = usePhotography()
|
|
|
|
|
|
|
|
|
|
|
|
|
const launchExternalTool = async (pagePath: string, successMessage: string) => {
|
|
const launchExternalTool = async (pagePath: string, successMessage: string) => {
|
|
@@ -611,189 +555,25 @@ const handleProductAlbumClick = () => launchExternalTool('/product_list', '产
|
|
|
|
|
|
|
|
// 货号选择弹窗相关状态
|
|
// 货号选择弹窗相关状态
|
|
|
const goodsSelectDialogVisible = ref(false)
|
|
const goodsSelectDialogVisible = ref(false)
|
|
|
-const filteredGoodsList = ref<any[]>([])
|
|
|
|
|
-const selectedGoodsArtNo = ref<string>('')
|
|
|
|
|
-const goodsGenerateLoading = ref(false)
|
|
|
|
|
-
|
|
|
|
|
-const addCustomTemplate = async () => {
|
|
|
|
|
- // 调用获取数据
|
|
|
|
|
- getPhotoRecords()
|
|
|
|
|
-
|
|
|
|
|
- // 处理数据的函数
|
|
|
|
|
- const processData = () => {
|
|
|
|
|
- // 从 goodsList 中筛选出 goods_art_no 在 goods_art_nos.value 中的对象
|
|
|
|
|
- const filteredGoods = goodsList.value.filter((item: any) =>
|
|
|
|
|
- goods_art_nos.value.includes(item.goods_art_no)
|
|
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
- console.log('goods_art_nos', goods_art_nos.value)
|
|
|
|
|
- console.log('filteredGoods', filteredGoods)
|
|
|
|
|
-
|
|
|
|
|
- if (filteredGoods.length > 0) {
|
|
|
|
|
- // 若有匹配项,则只展示匹配到的货号
|
|
|
|
|
- filteredGoodsList.value = filteredGoods
|
|
|
|
|
- selectedGoodsArtNo.value = filteredGoods[0].goods_art_no
|
|
|
|
|
- goodsSelectDialogVisible.value = true
|
|
|
|
|
- } else if (goodsList.value.length > 0) {
|
|
|
|
|
- // 若没有匹配到货号,则展示全部货号列表
|
|
|
|
|
- filteredGoodsList.value = goodsList.value
|
|
|
|
|
- selectedGoodsArtNo.value = goodsList.value[0].goods_art_no
|
|
|
|
|
- goodsSelectDialogVisible.value = true
|
|
|
|
|
- } else {
|
|
|
|
|
- // 列表本身为空时再提示
|
|
|
|
|
- ElMessage.warning('未找到匹配的货号数据')
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 使用 watch 监听 loading 状态,当从 true 变为 false 时,说明数据加载完成
|
|
|
|
|
- const stopWatcher = watch(
|
|
|
|
|
- () => loading.value,
|
|
|
|
|
- (isLoading, wasLoading) => {
|
|
|
|
|
- // 当 loading 从 true 变为 false 时,说明数据已经加载完成
|
|
|
|
|
- if (wasLoading && !isLoading) {
|
|
|
|
|
- processData()
|
|
|
|
|
- // 停止监听,避免重复执行
|
|
|
|
|
- stopWatcher()
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- )
|
|
|
|
|
|
|
|
|
|
- // 如果当前 loading 已经是 false,可能数据已经存在或加载很快完成
|
|
|
|
|
- // 使用 nextTick 等待一个 tick,如果 loading 仍然是 false,直接处理
|
|
|
|
|
- if (!loading.value) {
|
|
|
|
|
- await nextTick()
|
|
|
|
|
- // 如果 loading 仍然是 false,可能数据已经存在,直接处理
|
|
|
|
|
- if (!loading.value) {
|
|
|
|
|
- processData()
|
|
|
|
|
- stopWatcher() // 停止监听
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+const addCustomTemplate = () => {
|
|
|
|
|
+ goodsSelectDialogVisible.value = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// 根据选中的货号调用后端生成商品模板
|
|
|
|
|
-const generateGoodsTemplate = (goodsArtNo: string) => {
|
|
|
|
|
- return new Promise<void>((resolve, reject) => {
|
|
|
|
|
- try {
|
|
|
|
|
- console.log('调用 get_goods_image_json, goods_art_no:', goodsArtNo)
|
|
|
|
|
-
|
|
|
|
|
- // 按后端要求带上 token(参考其他生成类接口)
|
|
|
|
|
- const tokenStore = tokenInfo();
|
|
|
|
|
- const token = (tokenStore as any)?.getToken || '';
|
|
|
|
|
-
|
|
|
|
|
- // 先清理监听,避免重复回调
|
|
|
|
|
- clientStore.ipc.removeAllListeners(icpList.generate.getGoodsImageJson)
|
|
|
|
|
-
|
|
|
|
|
- clientStore.ipc.send(icpList.generate.getGoodsImageJson, {
|
|
|
|
|
- goods_art_no: goodsArtNo,
|
|
|
|
|
- token,
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- clientStore.ipc.on(icpList.generate.getGoodsImageJson, (event, result) => {
|
|
|
|
|
- clientStore.ipc.removeAllListeners(icpList.generate.getGoodsImageJson)
|
|
|
|
|
- console.log('get_goods_image_json result:', result)
|
|
|
|
|
- if (result && result.code === 0) {
|
|
|
|
|
- resolve(result.data)
|
|
|
|
|
- } else {
|
|
|
|
|
- const msg = result?.msg || '商品模板生成失败'
|
|
|
|
|
- ElMessage.error(msg)
|
|
|
|
|
- reject(new Error(msg))
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- } catch (error: any) {
|
|
|
|
|
- ElMessage.error(error?.message || '商品模板生成异常')
|
|
|
|
|
- reject(error)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+// 处理货号选择确认
|
|
|
|
|
+const handleGoodsSelectionConfirm = (selectedGoodsArtNo: string) => {
|
|
|
|
|
+ console.log('选中的货号:', selectedGoodsArtNo)
|
|
|
|
|
+ // 跳转到新增模板页(组件内部已经处理了数据存储到 sessionStorage)
|
|
|
|
|
+ router.push({
|
|
|
|
|
+ name: 'addTpl'
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// 确认选择货号
|
|
|
|
|
-const confirmGoodsSelection = async () => {
|
|
|
|
|
- if (!selectedGoodsArtNo.value) {
|
|
|
|
|
- ElMessage.warning('请选择一个货号')
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- console.log('选中的货号:', selectedGoodsArtNo.value)
|
|
|
|
|
- goodsGenerateLoading.value = true
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- const data = await generateGoodsTemplate(selectedGoodsArtNo.value)
|
|
|
|
|
- console.log('商品模版数据', data)
|
|
|
|
|
-
|
|
|
|
|
- // 组装 goods_images 数组:[{ key: 模板顺序项, value: 对应图片地址 }, ...]
|
|
|
|
|
- const goodsImages: Array<{ key: string; value: string }> = []
|
|
|
|
|
- const orderArr = (data?.template_image_order || '')
|
|
|
|
|
- .split(',')
|
|
|
|
|
- .map((s: string) => s.trim())
|
|
|
|
|
- .filter((s: string) => s)
|
|
|
|
|
- const imagesArr = Array.isArray(data?.customer_template_images)
|
|
|
|
|
- ? data.customer_template_images
|
|
|
|
|
- : []
|
|
|
|
|
-
|
|
|
|
|
- const len = Math.min(orderArr.length, imagesArr.length)
|
|
|
|
|
- for (let i = 0; i < len; i++) {
|
|
|
|
|
- goodsImages.push({
|
|
|
|
|
- key: orderArr[i],
|
|
|
|
|
- value: imagesArr[i],
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 将商品文字的 keys 转换为完整的对象结构
|
|
|
|
|
- const templateExcelHeaders = data?.template_excel_headers || []
|
|
|
|
|
- const defaultGoodsTextFallback = []
|
|
|
|
|
- const fullTemplateExcelHeaders = templateExcelHeaders.map(key => {
|
|
|
|
|
- const defaultItem = defaultGoodsTextFallback.find(item => item.key === key)
|
|
|
|
|
- return defaultItem || { key, value: '' }
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- // 使用sessionStorage传递数据,避免URL长度限制
|
|
|
|
|
- const templateData = {
|
|
|
|
|
- customer_template_images: goodsImages,
|
|
|
|
|
- template_image_order: data?.template_image_order || [],
|
|
|
|
|
- template_excel_headers: data?.template_excel_headers || [], // 传递完整的商品文字数据
|
|
|
|
|
- timestamp: Date.now() // 添加时间戳用于标识数据
|
|
|
|
|
- }
|
|
|
|
|
- sessionStorage.setItem('addTpl_template_data', JSON.stringify(templateData))
|
|
|
|
|
-
|
|
|
|
|
- // 生成商品模板成功后,跳转到新增模板页
|
|
|
|
|
- router.push({
|
|
|
|
|
- name: 'addTpl'
|
|
|
|
|
- })
|
|
|
|
|
- } finally {
|
|
|
|
|
- // 无论成功或失败,都关闭弹窗,保留当前选择
|
|
|
|
|
- goodsSelectDialogVisible.value = false
|
|
|
|
|
- goodsGenerateLoading.value = false
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 取消选择
|
|
|
|
|
-const cancelGoodsSelection = () => {
|
|
|
|
|
- goodsSelectDialogVisible.value = false
|
|
|
|
|
- selectedGoodsArtNo.value = ''
|
|
|
|
|
- filteredGoodsList.value = []
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 获取预览图片列表(只包含有图片路径的,保持原始顺序)
|
|
|
|
|
-const getPreviewImageList = (item: any) => {
|
|
|
|
|
- if (!item || !item.items) return []
|
|
|
|
|
- return item.items
|
|
|
|
|
- .filter((img: any) => img.PhotoRecord?.image_path)
|
|
|
|
|
- .map((img: any) => getFilePath(img.PhotoRecord.image_path))
|
|
|
|
|
|
|
+// 处理货号选择取消
|
|
|
|
|
+const handleGoodsSelectionCancel = () => {
|
|
|
|
|
+ // 取消选择,不做任何操作
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// 获取当前图片在预览列表中的索引
|
|
|
|
|
-const getPreviewIndex = (item: any, currentIndex: number) => {
|
|
|
|
|
- if (!item || !item.items) return 0
|
|
|
|
|
- // 计算当前图片在过滤后的预览列表中的索引
|
|
|
|
|
- let previewIndex = 0
|
|
|
|
|
- for (let i = 0; i <= currentIndex; i++) {
|
|
|
|
|
- if (item.items[i]?.PhotoRecord?.image_path) {
|
|
|
|
|
- if (i === currentIndex) break
|
|
|
|
|
- previewIndex++
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return previewIndex
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -3153,196 +2933,3 @@ const selectFolder = () => {
|
|
|
}
|
|
}
|
|
|
</style>
|
|
</style>
|
|
|
|
|
|
|
|
-<style lang="scss">
|
|
|
|
|
-// 货号选择弹窗样式(非 scoped,因为弹窗挂载在 body 上)
|
|
|
|
|
-.goods-select-dialog {
|
|
|
|
|
- max-width: 60vw;
|
|
|
|
|
-
|
|
|
|
|
- .el-dialog__body {
|
|
|
|
|
- padding: 20px;
|
|
|
|
|
- max-height: 70vh;
|
|
|
|
|
- overflow-y: auto;
|
|
|
|
|
- height: 60vh;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .goods-select-content {
|
|
|
|
|
- .goods-radio-group {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- flex-direction: column;
|
|
|
|
|
- gap: 20px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .goods-item {
|
|
|
|
|
- background: #FFFFFF;
|
|
|
|
|
- box-shadow: 0px 2px 4px 0px rgba(23, 33, 71, 0.1);
|
|
|
|
|
- border-radius: 10px;
|
|
|
|
|
- border: 1px solid #D9DEE6;
|
|
|
|
|
- margin-bottom: 20px;
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
- transition: all 0.3s;
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- .goods-radio {
|
|
|
|
|
- width: 30px;
|
|
|
|
|
- margin: 0;
|
|
|
|
|
- padding: 0;
|
|
|
|
|
- position: relative;
|
|
|
|
|
- margin-top: -10px;
|
|
|
|
|
-
|
|
|
|
|
- .el-radio__input {
|
|
|
|
|
- position: absolute;
|
|
|
|
|
- top: 14px;
|
|
|
|
|
- left: 18px;
|
|
|
|
|
- z-index: 10;
|
|
|
|
|
- transform: scale(1);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .el-radio__inner {
|
|
|
|
|
- border-width: 2px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &.is-checked {
|
|
|
|
|
- .el-radio__inner {
|
|
|
|
|
- background-color: #409eff;
|
|
|
|
|
- border-color: #409eff;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .el-radio__label {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- padding-left: 40px;
|
|
|
|
|
- display: none;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .goods-item-header {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- justify-content: flex-start;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- height: 40px;
|
|
|
|
|
- background: linear-gradient(90deg, #F4ECFF 0%, #DFEDFF 100%);
|
|
|
|
|
- border-radius: 10px 10px 0px 0px;
|
|
|
|
|
-
|
|
|
|
|
- .goods-item-left {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 16px;
|
|
|
|
|
-
|
|
|
|
|
- .goods-art-no {
|
|
|
|
|
- font-size: 16px;
|
|
|
|
|
- font-weight: 500;
|
|
|
|
|
- color: #333;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .goods-item-meta {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- justify-content: space-between;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
- color: #666;
|
|
|
|
|
-
|
|
|
|
|
- img {
|
|
|
|
|
- height: 14px;
|
|
|
|
|
- margin-right: 2px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .action-time {
|
|
|
|
|
- color: #666;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .image-count {
|
|
|
|
|
- color: #666;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .goods-item-images {
|
|
|
|
|
- display: grid;
|
|
|
|
|
- grid-template-columns: repeat(5, 1fr);
|
|
|
|
|
- gap: 10px;
|
|
|
|
|
- padding: 15px;
|
|
|
|
|
- border-top: 1px solid #f0f0f0;
|
|
|
|
|
- overflow-x: auto;
|
|
|
|
|
-
|
|
|
|
|
- @media (min-width: 1200px) {
|
|
|
|
|
- grid-template-columns: repeat(5, 1fr);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @media (max-width: 768px) {
|
|
|
|
|
- grid-template-columns: repeat(3, 1fr);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .goods-item_image {
|
|
|
|
|
- position: relative;
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- aspect-ratio: 1;
|
|
|
|
|
- background: #F7F7F7;
|
|
|
|
|
- border-radius: 10px;
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
- border: 1px solid #D9DEE6;
|
|
|
|
|
- transition: all 0.3s;
|
|
|
|
|
-
|
|
|
|
|
- .tag {
|
|
|
|
|
- color: #bbb;
|
|
|
|
|
- position: absolute;
|
|
|
|
|
- left: 0;
|
|
|
|
|
- right: 0;
|
|
|
|
|
- top: 50%;
|
|
|
|
|
- margin-top: -10px;
|
|
|
|
|
- line-height: 20px;
|
|
|
|
|
- text-align: center;
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
- z-index: 1;
|
|
|
|
|
- pointer-events: none;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .preview-image {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
-
|
|
|
|
|
- .el-image__inner {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
- object-fit: cover;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .image-placeholder {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
- background: #F7F7F7;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .image-slot {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
- background: #F7F7F7;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &:hover {
|
|
|
|
|
- border-color: #409eff;
|
|
|
|
|
- transform: scale(1.02);
|
|
|
|
|
- box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .dialog-footer {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- justify-content: flex-end;
|
|
|
|
|
- gap: 10px;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-</style>
|
|
|