|
@@ -83,15 +83,19 @@
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<!-- 未开发的功能 -->
|
|
<!-- 未开发的功能 -->
|
|
|
- <div class="service-tab disabled" title="功能开发中">
|
|
|
|
|
|
|
+ <div class="service-tab " title="新增自定义详情页模板"
|
|
|
|
|
+ @click="addCustomTemplate"
|
|
|
|
|
+ v-log="{ describe: { action: '点击新增自定义详情页模板', service: '新增自定义详情页模板' } }"
|
|
|
|
|
+ >
|
|
|
<div class="tab-content">
|
|
<div class="tab-content">
|
|
|
<div class="tab-img flex">
|
|
<div class="tab-img flex">
|
|
|
<img src="@/assets/images/detail/xqmb.svg" alt="详情页模板自定义" class="tab-icon" />
|
|
<img src="@/assets/images/detail/xqmb.svg" alt="详情页模板自定义" class="tab-icon" />
|
|
|
</div>
|
|
</div>
|
|
|
- <span class="tab-name">详情页模板自定义</span>
|
|
|
|
|
|
|
+ <span class="tab-name">新增自定义详情页模板</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
+
|
|
|
<div
|
|
<div
|
|
|
class="service-tab external-tool"
|
|
class="service-tab external-tool"
|
|
|
title="白底图批量导出"
|
|
title="白底图批量导出"
|
|
@@ -229,7 +233,33 @@
|
|
|
</div>
|
|
</div>
|
|
|
<div class="template-info">
|
|
<div class="template-info">
|
|
|
<span class="mar-left-10 chaochu_1">{{ template.template_name }}</span>
|
|
<span class="mar-left-10 chaochu_1">{{ template.template_name }}</span>
|
|
|
- <div class="template-view" v-if="isDetailServiceSelected" @click.stop="viewTemplate(template)" v-log="{ describe: { action: '点击查看模板详情', template_name: template.template_name } }">查看</div>
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="template-view"
|
|
|
|
|
+ v-if="isDetailServiceSelected && template.template_type == 0"
|
|
|
|
|
+ @click.stop="viewTemplate(template)"
|
|
|
|
|
+ v-log="{ describe: { action: '点击查看模板详情', template_name: template.template_name } }"
|
|
|
|
|
+ >
|
|
|
|
|
+ 查看
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="template-actions flex"
|
|
|
|
|
+ v-if="isDetailServiceSelected && template.template_type == 1"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="template-view"
|
|
|
|
|
+ @click.stop="editTemplate(template)"
|
|
|
|
|
+ v-log="{ describe: { action: '点击编辑模板详情', template_name: template.template_name } }"
|
|
|
|
|
+ >
|
|
|
|
|
+ 编辑
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="template-view template-view-delete"
|
|
|
|
|
+ @click.stop="deleteTemplate(template)"
|
|
|
|
|
+ v-log="{ describe: { action: '点击删除自定义模板', template_name: template.template_name } }"
|
|
|
|
|
+ >
|
|
|
|
|
+ 删除
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -510,6 +540,81 @@
|
|
|
@cancel="scenePromptDialogVisible = false"
|
|
@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">
|
|
|
|
|
+ <el-radio
|
|
|
|
|
+ :label="item.goods_art_no"
|
|
|
|
|
+ class="goods-radio"
|
|
|
|
|
+ @click.stop
|
|
|
|
|
+ > </el-radio>
|
|
|
|
|
+
|
|
|
|
|
+ </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>
|
|
|
|
|
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -541,13 +646,24 @@ import ScenePromptDialog from '@/components/ScenePromptDialog/index.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'
|
|
|
|
|
|
|
|
-
|
|
|
|
|
import configInfo from "@/stores/modules/config";
|
|
import configInfo from "@/stores/modules/config";
|
|
|
|
|
+import { deleteCustomerTemplate } from '@/apis/other'
|
|
|
|
|
|
|
|
const useConfigInfoStore = configInfo();
|
|
const useConfigInfoStore = configInfo();
|
|
|
|
|
|
|
|
const EXTERNAL_TOOL_EXECUTABLE = '智慧映拍照机辅助工具箱.exe'
|
|
const EXTERNAL_TOOL_EXECUTABLE = '智慧映拍照机辅助工具箱.exe'
|
|
|
|
|
|
|
|
|
|
+import usePhotography from './mixin/usePhotography'
|
|
|
|
|
+
|
|
|
|
|
+const {
|
|
|
|
|
+ loading,
|
|
|
|
|
+ goodsList,
|
|
|
|
|
+ getPhotoRecords,
|
|
|
|
|
+ getTime,
|
|
|
|
|
+ getFilePath,
|
|
|
|
|
+} = usePhotography()
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
const launchExternalTool = async (pagePath: string, successMessage: string) => {
|
|
const launchExternalTool = async (pagePath: string, successMessage: string) => {
|
|
|
if (!clientStore?.ipc || !clientStore.isClient) {
|
|
if (!clientStore?.ipc || !clientStore.isClient) {
|
|
|
ElMessage.error('当前环境暂不支持外部工具');
|
|
ElMessage.error('当前环境暂不支持外部工具');
|
|
@@ -579,6 +695,180 @@ const launchExternalTool = async (pagePath: string, successMessage: string) => {
|
|
|
const handleWhiteBgExportClick = () => launchExternalTool('/copy_800_tool', '白底图批量导出工具已启动')
|
|
const handleWhiteBgExportClick = () => launchExternalTool('/copy_800_tool', '白底图批量导出工具已启动')
|
|
|
const handleProductAlbumClick = () => launchExternalTool('/product_list', '产品图册生成工具已启动')
|
|
const handleProductAlbumClick = () => launchExternalTool('/product_list', '产品图册生成工具已启动')
|
|
|
|
|
|
|
|
|
|
+// 货号选择弹窗相关状态
|
|
|
|
|
+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 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 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],
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 生成商品模板成功后,跳转到新增模板页,并携带当前选中的货号
|
|
|
|
|
+ router.push({
|
|
|
|
|
+ name: 'addTpl',
|
|
|
|
|
+ query: {
|
|
|
|
|
+ // 统一用 JSON 字符串传递图片与顺序信息
|
|
|
|
|
+ customer_template_images: encodeURIComponent(JSON.stringify(goodsImages)),
|
|
|
|
|
+ template_image_order: data?.template_image_order || '',
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
|
|
+ } 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 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
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
|
|
import { useCheckInfo } from '@/composables/userCheck';
|
|
import { useCheckInfo } from '@/composables/userCheck';
|
|
@@ -618,6 +908,42 @@ const progressSteps = ref<Array<{
|
|
|
error: number
|
|
error: number
|
|
|
}>>([])
|
|
}>>([])
|
|
|
|
|
|
|
|
|
|
+// 删除自定义模板
|
|
|
|
|
+const deleteTemplate = async (template: any) => {
|
|
|
|
|
+ if (!template?.id) return
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ await ElMessageBox.confirm(
|
|
|
|
|
+ `确定要删除自定义模板「${template.template_name || ''}」吗?`,
|
|
|
|
|
+ '提示',
|
|
|
|
|
+ {
|
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ type: 'warning',
|
|
|
|
|
+ },
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ const res = await deleteCustomerTemplate({ id: template.id })
|
|
|
|
|
+ const data = res?.data
|
|
|
|
|
+
|
|
|
|
|
+ if (data?.code === 0) {
|
|
|
|
|
+ ElMessage.success('删除成功')
|
|
|
|
|
+ // 从当前模板列表中移除
|
|
|
|
|
+ const idx = templates.value.findIndex((item: any) => item.id === template.id)
|
|
|
|
|
+ if (idx !== -1) {
|
|
|
|
|
+ templates.value.splice(idx, 1)
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ElMessage.error(data?.msg || '删除失败')
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e: any) {
|
|
|
|
|
+ if (e !== 'cancel' && e !== 'close') {
|
|
|
|
|
+ console.error('删除模板失败:', e)
|
|
|
|
|
+ ElMessage.error(e?.message || '删除失败')
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// 更新进度步骤
|
|
// 更新进度步骤
|
|
|
const updateProgressStep = (msgType: string, stepData: any) => {
|
|
const updateProgressStep = (msgType: string, stepData: any) => {
|
|
|
console.log('updateProgressStep called:', msgType, stepData)
|
|
console.log('updateProgressStep called:', msgType, stepData)
|
|
@@ -745,12 +1071,10 @@ const hasTemplates = computed(() => templates.value.length > 0)
|
|
|
const canUsePublishSection = computed(() => isDetailServiceSelected.value && hasTemplates.value)
|
|
const canUsePublishSection = computed(() => isDetailServiceSelected.value && hasTemplates.value)
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
// 页面访问埋点
|
|
// 页面访问埋点
|
|
|
-
|
|
|
|
|
const goods_art_data = route.query.goods_art_nos
|
|
const goods_art_data = route.query.goods_art_nos
|
|
|
goods_art_nos.value = Array.isArray(goods_art_data) ? goods_art_data : [goods_art_data]
|
|
goods_art_nos.value = Array.isArray(goods_art_data) ? goods_art_data : [goods_art_data]
|
|
|
getCompanyTemplates()
|
|
getCompanyTemplates()
|
|
|
getLogolist()
|
|
getLogolist()
|
|
|
-
|
|
|
|
|
loadDetailCache()
|
|
loadDetailCache()
|
|
|
|
|
|
|
|
// 初始化目录打开状态标记
|
|
// 初始化目录打开状态标记
|
|
@@ -859,10 +1183,32 @@ const viewTemplate = (template) => {
|
|
|
dialogImageUrl.value = template.template_preview_image
|
|
dialogImageUrl.value = template.template_preview_image
|
|
|
|
|
|
|
|
};
|
|
};
|
|
|
|
|
+// 编辑自定义模版
|
|
|
|
|
+const editTemplate = (template: any) => {
|
|
|
|
|
+ if (!template) return
|
|
|
|
|
+
|
|
|
|
|
+ // 将画布 JSON、名称、商品图片等信息通过 query 传给编辑页
|
|
|
|
|
+ const customerTemplateJson = template.customer_template_json || []
|
|
|
|
|
+ const customerTemplateImages = template.customer_template_images || []
|
|
|
|
|
+ const templateImageOrder = template.template_image_order || ''
|
|
|
|
|
+ const templateName = template.template_name || ''
|
|
|
|
|
+
|
|
|
|
|
+ router.push({
|
|
|
|
|
+ name: 'editTpl',
|
|
|
|
|
+ params: { id: template.id },
|
|
|
|
|
+ query: {
|
|
|
|
|
+ customer_template_json: encodeURIComponent(JSON.stringify(customerTemplateJson)),
|
|
|
|
|
+ template_name: templateName,
|
|
|
|
|
+ customer_template_images: encodeURIComponent(JSON.stringify(customerTemplateImages)),
|
|
|
|
|
+ template_image_order: templateImageOrder,
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
// 获取模版列表
|
|
// 获取模版列表
|
|
|
const getCompanyTemplates = async () => {
|
|
const getCompanyTemplates = async () => {
|
|
|
const { data } = await getCompanyTemplatesApi()
|
|
const { data } = await getCompanyTemplatesApi()
|
|
|
- console.log(data);
|
|
|
|
|
|
|
+ console.log('getCompanyTemplatesApi' ,data);
|
|
|
templates.value = data.list || []
|
|
templates.value = data.list || []
|
|
|
// 获取电商平台列表 - 支持新的数据结构
|
|
// 获取电商平台列表 - 支持新的数据结构
|
|
|
if (data.online_store_temp_list) {
|
|
if (data.online_store_temp_list) {
|
|
@@ -2774,3 +3120,196 @@ const selectFolder = () => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
</style>
|
|
</style>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+// 货号选择弹窗样式(非 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: 100%;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+ padding: 0;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+
|
|
|
|
|
+ .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;
|
|
|
|
|
+ padding: 0 16px;
|
|
|
|
|
+ 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>
|