Jelajahi Sumber

first commit

liuhairui 1 bulan lalu
induk
melakukan
c91b05119b

+ 61 - 0
src/api/mes/job.js

@@ -1168,3 +1168,64 @@ export const oversizedloss = (data) => {
 }
 
 
+//获取文生图模型列表
+export const txttoimg_moxing = (params) => {
+  return service({
+    url: '/mes_server/Facility/txttoimg_moxing',
+    method: 'get',
+    params
+  })
+}
+//修改默认文生图模型
+export const txttoimg_update = (data) => {
+  return service({
+    url: '/mes_server/Facility/txttoimg_update',
+    method: 'post',
+    data
+  })
+}
+
+
+export const getPreviewFolders = (params) => {
+  return service({
+    url: '/mes_server/Facility/getPreviewFolders',
+    method: 'get',
+    params
+  })
+}
+
+export const Getvideolist = (params) => {
+  return service({
+    url: '/mes_server/work_order/Getvideolist',
+    method: 'get',
+    params
+  })
+}
+export const video = (params) => {
+  return service({
+    url: '/mes_server/work_order/video',
+    method: 'get',
+    params
+  })
+}
+export const videoContent = (params) => {
+  return service({
+    url: '/mes_server/work_order/videoContent',
+    method: 'get',
+    params
+  })
+}
+export const GetHttpUrl = (params) => {
+  return service({
+    url: '/mes_server/work_order/GetHttpUrl',
+    method: 'get',
+    params
+  })
+}
+export const GetTxtToTxt = (params) => {
+  return service({
+    url: '/mes_server/work_order/GetTxtToTxt',
+    method: 'get',
+    params
+  })
+}

+ 441 - 0
src/view/performance/QualityAssessment/Category.vue

@@ -0,0 +1,441 @@
+<template>
+  <div class="food-category">
+    <el-card shadow="hover">
+      <template #header>
+        <div class="card-header">
+          <span>食品数据管理</span>
+        </div>
+      </template>
+      
+      <!-- 搜索和筛选区域 -->
+      <div class="search-filter">
+        <el-form :model="searchForm" label-width="80px" inline>
+          <el-form-item label="食品名称">
+            <el-input 
+              v-model="searchForm.productName" 
+              placeholder="请输入食品名称" 
+              clearable
+              @keyup.enter="getProductList"
+            />
+          </el-form-item>
+          <el-form-item label="食品类型">
+            <el-select 
+              v-model="searchForm.foodType" 
+              placeholder="请选择食品类型" 
+              clearable
+            >
+              <el-option label="蔬菜" value="vegetable" />
+              <el-option label="水果" value="fruit" />
+              <el-option label="肉类" value="meat" />
+              <el-option label="海鲜" value="seafood" />
+              <el-option label="加工食品" value="processed" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="生成状态">
+            <el-select 
+              v-model="searchForm.status" 
+              placeholder="请选择状态" 
+              clearable
+            >
+              <el-option label="已生成" value="success" />
+              <el-option label="生成中" value="generating" />
+              <el-option label="生成失败" value="failed" />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="getProductList">搜索</el-button>
+            <el-button @click="resetSearch">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+      
+      <!-- 产品列表 -->
+      <div class="food-list">
+        <el-table 
+          :data="productList" 
+          style="width: 100%" 
+          stripe
+          @row-click="handleRowClick"
+        >
+          <el-table-column prop="id" label="食品ID" width="80" />
+          <el-table-column prop="productName" label="食品名称" width="200" />
+          <el-table-column prop="foodType" label="食品类型" width="120">
+            <template #default="scope">
+              <el-tag 
+                :type="scope.row.foodType === 'vegetable' ? 'success' : 
+                      scope.row.foodType === 'fruit' ? 'warning' : 
+                      scope.row.foodType === 'meat' ? 'danger' : 
+                      scope.row.foodType === 'seafood' ? 'primary' : 'info'"
+              >
+                {{ scope.row.foodType === 'vegetable' ? '蔬菜' : 
+                   scope.row.foodType === 'fruit' ? '水果' : 
+                   scope.row.foodType === 'meat' ? '肉类' : 
+                   scope.row.foodType === 'seafood' ? '海鲜' : '加工食品' }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column prop="size" label="图片尺寸" width="120" />
+          <el-table-column prop="style" label="设计风格" width="120" />
+          <el-table-column prop="status" label="生成状态" width="120">
+            <template #default="scope">
+              <el-tag 
+                :type="scope.row.status === 'success' ? 'success' : 
+                      scope.row.status === 'generating' ? 'warning' : 'danger'"
+              >
+                {{ scope.row.status === 'success' ? '已生成' : 
+                   scope.row.status === 'generating' ? '生成中' : '生成失败' }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column prop="createTime" label="创建时间" width="180" />
+          <el-table-column label="操作" width="200">
+            <template #default="scope">
+              <el-button type="primary" size="small" @click="viewProduct(scope.row)">查看详情</el-button>
+              <el-button type="danger" size="small" @click="deleteProduct(scope.row.id)">删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        
+        <!-- 分页 -->
+        <div class="pagination">
+          <el-pagination
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"
+            :current-page="pagination.currentPage"
+            :page-sizes="[10, 20, 50, 100]"
+            :page-size="pagination.pageSize"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="pagination.total"
+          />
+        </div>
+      </div>
+    </el-card>
+    
+    <!-- 产品详情对话框 -->
+    <el-dialog
+      v-model="detailDialogVisible"
+      title="食品详情"
+      width="800px"
+      :before-close="handleDetailClose"
+    >
+      <div class="food-detail" v-if="selectedProduct">
+        <div class="detail-section">
+          <h3>基本信息</h3>
+          <el-descriptions :column="2" border>
+            <el-descriptions-item label="食品ID">{{ selectedProduct.id }}</el-descriptions-item>
+            <el-descriptions-item label="食品名称">{{ selectedProduct.productName }}</el-descriptions-item>
+            <el-descriptions-item label="食品类型">
+              <el-tag 
+                :type="selectedProduct.foodType === 'vegetable' ? 'success' : 
+                      selectedProduct.foodType === 'fruit' ? 'warning' : 
+                      selectedProduct.foodType === 'meat' ? 'danger' : 
+                      selectedProduct.foodType === 'seafood' ? 'primary' : 'info'"
+              >
+                {{ selectedProduct.foodType === 'vegetable' ? '蔬菜' : 
+                   selectedProduct.foodType === 'fruit' ? '水果' : 
+                   selectedProduct.foodType === 'meat' ? '肉类' : 
+                   selectedProduct.foodType === 'seafood' ? '海鲜' : '加工食品' }}
+              </el-tag>
+            </el-descriptions-item>
+            <el-descriptions-item label="产地">{{ selectedProduct.origin }}</el-descriptions-item>
+            <el-descriptions-item label="营养价值">{{ selectedProduct.nutrition }}</el-descriptions-item>
+            <el-descriptions-item label="图片尺寸">{{ selectedProduct.size }}</el-descriptions-item>
+            <el-descriptions-item label="设计风格">{{ selectedProduct.style }}</el-descriptions-item>
+            <el-descriptions-item label="生成状态">
+              <el-tag 
+                :type="selectedProduct.status === 'success' ? 'success' : 
+                      selectedProduct.status === 'generating' ? 'warning' : 'danger'"
+              >
+                {{ selectedProduct.status === 'success' ? '已生成' : 
+                   selectedProduct.status === 'generating' ? '生成中' : '生成失败' }}
+              </el-tag>
+            </el-descriptions-item>
+            <el-descriptions-item label="创建时间" :span="2">{{ selectedProduct.createTime }}</el-descriptions-item>
+          </el-descriptions>
+        </div>
+        
+        <div class="detail-section">
+          <h3>提示词信息</h3>
+          <el-input
+            v-model="selectedProduct.prompt"
+            type="textarea"
+            :rows="4"
+            readonly
+            style="background-color: #f5f7fa"
+          />
+        </div>
+        
+        <div class="detail-section">
+          <h3>生成结果</h3>
+          <div class="generated-image">
+            <el-image
+              v-if="selectedProduct.generatedImage"
+              :src="selectedProduct.generatedImage"
+              fit="contain"
+              style="max-width: 100%; max-height: 400px"
+            >
+              <template #error>
+                <div class="image-error">图片加载失败</div>
+              </template>
+            </el-image>
+            <el-empty v-else description="暂无生成图片" />
+          </div>
+        </div>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import {ref,reactive,onMounted} from 'vue'
+import {ElMessage,ElMessageBox,ElEmpty,ElImage} from 'element-plus'
+import {Loading} from '@element-plus/icons-vue'
+import {useUserStore} from '@/pinia/modules/user'
+// 假设存在获取产品列表的API,需要根据实际情况修改
+// import {getProductListApi, deleteProductApi} from '@/api/mes/product'
+
+// 定义组件名称
+
+defineOptions({name: 'Category'})
+
+// 搜索表单
+const searchForm = reactive({
+  productName: '',
+  foodType: '',
+  status: ''
+})
+
+// 食品列表数据
+const productList = ref([])
+
+// 分页信息
+const pagination = reactive({
+  currentPage: 1,
+  pageSize: 10,
+  total: 0
+})
+
+// 加载状态
+const loading = ref(false)
+
+// 详情对话框
+const detailDialogVisible = ref(false)
+const selectedProduct = ref(null)
+
+// 模拟食品数据
+const mockProducts = [
+  {
+    id: 1,
+    productName: '有机胡萝卜',
+    foodType: 'vegetable',
+    origin: '山东寿光',
+    nutrition: '富含胡萝卜素、维生素A',
+    size: '1024x1024',
+    style: 'realistic',
+    status: 'success',
+    createTime: '2023-10-20 10:30:00',
+    prompt: '创建一张有机胡萝卜的宣传图片,展示新鲜的有机胡萝卜,背景使用自然土壤色调,突出健康、有机的主题。',
+    generatedImage: 'https://picsum.photos/seed/carrot1/1024/1024'
+  },
+  {
+    id: 2,
+    productName: '挪威三文鱼',
+    foodType: 'seafood',
+    origin: '挪威',
+    nutrition: '富含Omega-3脂肪酸、蛋白质',
+    size: '1024x1024',
+    style: 'realistic',
+    status: 'success',
+    createTime: '2023-10-21 11:45:00',
+    prompt: '设计一张挪威三文鱼的宣传海报,展示新鲜的三文鱼片,背景使用海洋元素,突出其新鲜和营养价值。',
+    generatedImage: 'https://picsum.photos/seed/salmon1/1024/1024'
+  },
+  {
+    id: 3,
+    productName: '原味鱼干',
+    foodType: 'processed',
+    origin: '福建厦门',
+    nutrition: '富含蛋白质、钙、磷',
+    size: '1024x1024',
+    style: 'realistic',
+    status: 'success',
+    createTime: '2023-10-23 09:00:00',
+    prompt: '创建一张原味鱼干的宣传图片,展示自然晾晒的鱼干,背景使用海边场景,突出其新鲜和传统工艺。',
+    generatedImage: 'https://images.unsplash.com/photo-1610486295123-078299c50e79?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1024&q=80'
+  }
+]
+
+// 获取食品列表
+const getProductList = async () => {
+  loading.value = true
+  try {
+    // 实际项目中这里应该调用API获取数据
+    // const res = await getProductListApi({
+    //   page: pagination.currentPage,
+    //   pageSize: pagination.pageSize,
+    //   productName: searchForm.productName,
+    //   foodType: searchForm.foodType,
+    //   status: searchForm.status
+    // })
+    
+    // 模拟API调用
+    await new Promise(resolve => setTimeout(resolve, 500))
+    
+    // 模拟筛选数据
+    let filteredProducts = [...mockProducts]
+    if (searchForm.productName) {
+      filteredProducts = filteredProducts.filter(p => p.productName.includes(searchForm.productName))
+    }
+    if (searchForm.foodType) {
+      filteredProducts = filteredProducts.filter(p => p.foodType === searchForm.foodType)
+    }
+    if (searchForm.status) {
+      filteredProducts = filteredProducts.filter(p => p.status === searchForm.status)
+    }
+    
+    productList.value = filteredProducts
+    pagination.total = filteredProducts.length
+    
+    ElMessage({ message: '获取食品列表成功', type: 'success' })
+  } catch (error) {
+    console.error('获取食品列表失败:', error)
+    ElMessage({ message: '获取食品列表失败', type: 'error' })
+  } finally {
+    loading.value = false
+  }
+}
+
+// 重置搜索
+const resetSearch = () => {
+  searchForm.productName = ''
+  searchForm.foodType = ''
+  searchForm.status = ''
+  pagination.currentPage = 1
+  getProductList()
+}
+
+// 分页处理
+const handleSizeChange = (size) => {
+  pagination.pageSize = size
+  pagination.currentPage = 1
+  getProductList()
+}
+
+const handleCurrentChange = (current) => {
+  pagination.currentPage = current
+  getProductList()
+}
+
+// 查看产品详情
+const viewProduct = (product) => {
+  selectedProduct.value = {...product}
+  detailDialogVisible.value = true
+}
+
+// 处理行点击
+const handleRowClick = (row) => {
+  viewProduct(row)
+}
+
+// 删除产品
+const deleteProduct = (id) => {
+  ElMessageBox.confirm('确定要删除该产品吗?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  }).then(async () => {
+    try {
+      // 实际项目中这里应该调用API删除数据
+      // await deleteProductApi(id)
+      
+      // 模拟API调用
+      await new Promise(resolve => setTimeout(resolve, 300))
+      
+      // 从列表中移除
+      const index = productList.value.findIndex(p => p.id === id)
+      if (index > -1) {
+        productList.value.splice(index, 1)
+        pagination.total--
+      }
+      
+      ElMessage({ message: '删除成功', type: 'success' })
+    } catch (error) {
+      console.error('删除失败:', error)
+      ElMessage({ message: '删除失败', type: 'error' })
+    }
+  }).catch(() => {
+    // 取消删除
+  })
+}
+
+// 处理详情对话框关闭
+const handleDetailClose = () => {
+  detailDialogVisible.value = false
+  selectedProduct.value = null
+}
+
+// 页面挂载时获取产品列表
+onMounted(() => {
+  getProductList()
+})
+</script>
+
+<style scoped>
+.product-category {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-filter {
+  margin-bottom: 20px;
+}
+
+.product-list {
+  margin-top: 20px;
+}
+
+.pagination {
+  margin-top: 20px;
+  text-align: right;
+}
+
+.product-detail {
+  padding: 10px 0;
+}
+
+.detail-section {
+  margin-bottom: 25px;
+}
+
+.detail-section h3 {
+  margin-bottom: 15px;
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+  border-bottom: 1px solid #ebeef5;
+  padding-bottom: 5px;
+}
+
+.generated-image {
+  margin-top: 10px;
+  padding: 20px;
+  background-color: #fafafa;
+  border-radius: 8px;
+  text-align: center;
+}
+
+.image-error {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 200px;
+  background-color: #f5f7fa;
+  color: #909399;
+}
+</style>

+ 970 - 0
src/view/performance/QualityAssessment/Newdialogue.vue

@@ -0,0 +1,970 @@
+<template>
+  <div class="chat-interface">
+    <!-- 生成类型选项卡 -->
+    <div class="generation-tabs">
+      <el-tabs v-model="activeTab" type="card">
+        <el-tab-pane label="视频生成" name="video">
+          <template #label>
+            <div class="tab-label">
+              <el-icon class="tab-icon"><VideoPlay /></el-icon>
+              <span>视频生成</span>
+            </div>
+          </template>
+        </el-tab-pane>
+        <el-tab-pane label="图片生成" name="image">
+          <template #label>
+            <div class="tab-label">
+              <el-icon class="tab-icon"><Picture /></el-icon>
+              <span>图片生成</span>
+            </div>
+          </template>
+        </el-tab-pane>
+      </el-tabs>
+    </div>
+
+    <!-- 输入区域容器 -->
+    <div class="input-container">
+      <!-- 上传区域:上传按钮和已上传图片水平排列 -->
+    <div class="upload-area">
+      <!-- 上传按钮 -->
+      <el-button 
+        type="default" 
+        class="add-btn"
+        @click="triggerUpload"
+        title="上传"
+      >
+        <el-icon><Plus /></el-icon>
+        <span>上传</span>
+      </el-button>
+
+      <!-- 已上传图片预览 -->
+      <div class="uploaded-images-container">
+        <div 
+          v-for="(img, index) in uploadedImages" 
+          :key="index"
+          class="message-image"
+        >
+          <!-- 使用自定义图片预览功能 -->
+          <el-image 
+            :src="img.url" 
+            fit="cover"
+            @click="handleImageClick(img)"
+          />
+          <el-button 
+            type="text" 
+            size="small" 
+            class="delete-img-btn"
+            @click.stop="removeImage(index)"
+          >
+            <el-icon><Delete /></el-icon>
+          </el-button>
+        </div>
+      </div>
+      
+      <!-- 隐藏的文件输入框 -->
+      <input
+        ref="fileInput"
+        type="file"
+        accept="image/*"
+        style="display: none"
+        @change="handleFileChange"
+      />
+    </div>
+
+      <!-- 输入区域:输入框和发送按钮 -->
+      <div class="input-wrapper">
+        <!-- 文本输入框 -->
+        <el-input 
+          v-model="prompt" 
+          type="textarea" 
+          :rows="3" 
+          :placeholder="getPlaceholder"
+          @paste="handlePaste"
+          class="chat-input"
+        />
+        
+        <!-- 右侧提交按钮 -->
+        <el-button type="primary" class="send-btn" @click="handleSubmit" :loading="uploading">
+          提交
+        </el-button>
+      </div>
+    </div>
+  </div>
+
+   <el-form inline>
+      <el-form-item>
+        <el-input v-model="searchInfo" placeholder="搜索关键字" clearable style="width: 300px;" />
+        
+        <!-- 文件夹筛选下拉菜单 -->
+        <el-dropdown @command="handleFolderCommand" style="margin-right: 10px;">
+          <el-button  icon="search" title="文件夹筛选">
+            {{ selectedFolder || '文件夹筛选' }}<el-icon class="el-icon--right"><arrow-down /></el-icon>
+          </el-button>
+          <template #dropdown>
+            <el-dropdown-menu>
+              <el-dropdown-item command="">全部文件夹</el-dropdown-item>
+              <el-dropdown-item v-for="(folder, index) in folderList" :key="index" :command="folder">
+                {{ folder }}
+              </el-dropdown-item>
+            </el-dropdown-menu>
+          </template>
+        </el-dropdown>
+        
+        <el-button type="primary" icon="search" @click="onSubmit" title="搜索">查询</el-button>
+      </el-form-item>
+    </el-form>
+
+  <!-- 表格展示 -->
+    <el-table
+      ref="multipleTable"
+      style="width: 100%; height: 62vh;"
+      :row-style="{ height: '20px' }"
+      :header-cell-style="{ padding: '0px' }"
+      :cell-style="{ padding: '0px' }"
+      :header-row-style="{ height: '20px' }"
+      border tooltip-effect="dark"
+      :data="tableData1"
+      row-key="ID"
+      highlight-current-row
+      :cell-class-name="tableDataCellClass"
+      @selection-change="SelectionChange"
+      @row-dblclick="onRowDblClick"
+      :show-overflow-tooltip="true"
+    >
+      <el-table-column type="selection" width="55" />
+      <el-table-column label="ID" prop="id" width="70" />
+      <el-table-column label="第一段" prop="chinese_description" width="300" />
+      <el-table-column label="第二段" prop="english_description" width="300" />
+      <el-table-column label="图片名称" prop="img_name" width="300" />
+      <el-table-column label="原图" width="120">
+        <template #default="{ row }">
+          <el-image
+            :src="formatImageUrl(row.old_image_url)"
+            :preview-src-list="[formatImageUrl(row.old_image_url)]"
+            style="width: 90px; height: 70px;"
+            fit="contain"
+            preview-teleported
+          />
+        </template>
+      </el-table-column>
+	  
+	  
+	  <el-table-column
+	    v-if="tableData1.some(row => row.model === 'black-forest-labs/FLUX.1-kontext-pro')" 
+	    label="FLUX.1" 
+	    width="120">
+	    <template #default="{ row }">
+	      <el-image
+	        v-if="row.model === 'black-forest-labs/FLUX.1-kontext-pro'"
+	        :src="formatImageUrl(row.new_image_url)"
+	        :preview-src-list="[formatImageUrl(row.new_image_url)]"
+	        style="width: 90px; height: 70px;"
+	        fit="contain"
+	        preview-teleported
+	      />
+	      <span v-else>-</span>
+	    </template>
+	  </el-table-column>
+	  <el-table-column
+	    v-if="tableData1.some(row => row.model === 'dall-e-3')" 
+	    label="dall-e-3" 
+	    width="120">
+	    <template #default="{ row }">
+	      <el-image
+	        v-if="row.model === 'dall-e-3'"
+	        :src="formatImageUrl(row.new_image_url)"
+	        :preview-src-list="[formatImageUrl(row.new_image_url)]"
+	        style="width: 90px; height: 70px;"
+	        fit="contain"
+	        preview-teleported
+	      />
+	      <span v-else>-</span>
+	    </template>
+	  </el-table-column>
+	  <el-table-column 
+	    v-if="tableData1.some(row => row.model === 'gpt-image-1')" 
+	    label="gpt-image-1" 
+	    width="120">
+	    <template #default="{ row }">
+	      <el-image
+	        v-if="row.model === 'gpt-image-1'"
+	        :src="formatImageUrl(row.new_image_url)"
+	        :preview-src-list="[formatImageUrl(row.new_image_url)]"
+	        style="width: 90px; height: 70px;"
+	        fit="contain"
+	        preview-teleported
+	      />
+	      <span v-else>-</span>
+	    </template>
+	  </el-table-column>
+	  <el-table-column
+	    v-if="tableData1.some(row => row.model === 'MID_JOURNEY')" 
+	    label="MID_JOURNEY" 
+	    width="130">
+	    <template #default="{ row }">
+	      <el-image
+	        v-if="row.model === 'MID_JOURNEY'"
+	        :src="`https://chatapi.onechats.ai/mj/image/${row.taskId}`"  
+	        :preview-src-list="[`https://chatapi.onechats.ai/mj/image/${row.taskId}`]"
+	        style="width: 90px; height: 70px;"
+	        fit="contain"
+	        preview-teleported
+	      />
+	      <span v-else>-</span>
+	    </template>
+	  </el-table-column>
+      
+      <el-table-column label="图生图预览" width="120">
+        <template #default="{ row }">
+          <el-image
+            :src="formatImageUrl(row.imgtoimg_url)"
+            :preview-src-list="[formatImageUrl(row.imgtoimg_url)]"
+            style="width: 90px; height: 70px;"
+            fit="contain"
+            preview-teleported
+          />
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <div class="gva-pagination">
+      <el-pagination
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+        :current-page="page"
+        :page-sizes="[10, 30, 50, 100]"
+        :page-size="pageSize"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="total"
+      />
+    </div>
+</template>
+
+<script setup>
+import { ref, computed, onMounted } from 'vue'
+import { Delete, ZoomIn, CirclePlus, VideoPlay, Picture } from '@element-plus/icons-vue'
+import { ElMessage } from 'element-plus'
+import { useUserStore } from '@/pinia/modules/user'
+import { isImageMime } from '@/utils/image'
+import service from '@/utils/request'
+import {imageToText,getTable, Template_ids,txttoimg_moxing,GetHttpUrl,txttoimg_update, getSide} from '@/api/mes/job'
+
+//获取登录用户信息
+const userStore = useUserStore()
+const _username = ref('')
+_username.value = userStore.userInfo.userName + '/' + userStore.userInfo.nickName
+console.log('获取用户信息',_username.value)
+console.log('获取用户名称',userStore.userInfo.nickName)
+
+//获取服务器地址
+const baseUrl = ref('')
+const port = ref('')
+const full_url = ref('')
+// 从接口获取服务器地址
+const fetchServerUrl = async () => {
+  try {
+    const res = await GetHttpUrl()
+    if (res.code === 0 && res.data && res.data.full_url) {
+      full_url.value = res.data.full_url
+      baseUrl.value = res.data.baseUrl
+      port.value = res.data.port
+	  console.log('获取服务器地址',full_url.value)
+	  console.log('IP地址',baseUrl.value)
+	  console.log('端口',port.value)
+    }
+  } catch (error) {
+    console.error('获取服务器地址失败:', error)
+  }
+}
+fetchServerUrl();
+
+const tableData1 = ref([])
+const selectedFolder = ref('')
+const folderList = ref([])
+
+const getTableData = async () => {
+    const res = await getTable({
+      search: searchInfo.value,
+      limit: pageSize.value,
+      page: page.value,
+      folder: selectedFolder.value
+    })
+    tableData1.value = res.data.list
+    total.value = res.data.total
+    
+    // 更新文件夹列表
+    if (res.data.folder) {
+      folderList.value = res.data.folder
+    }
+
+    // const res_Template = await Template_ids({path:row['old_image_url']});
+    // height.value = res_Template.data.height
+    // width.value = res_Template.data.width
+}
+getTableData()
+
+// 处理文件夹选择
+const handleFolderCommand = (command) => {
+  selectedFolder.value = command
+  onSubmit()
+}
+
+// 消息内容
+const prompt = ref('')
+// 已上传图片列表
+const uploadedImages = ref([])
+// 文件输入框引用
+const fileInput = ref(null)
+// 上传状态
+const uploading = ref(false)
+// 激活的标签页
+const activeTab = ref('image')
+// 生成类型
+const generationType = computed(() => activeTab.value === 'video' ? '视频生成' : '图片生成')
+// API路径
+const path = ref(import.meta.env.VITE_BASE_API)
+
+// 触发文件上传
+const triggerUpload = () => {
+  fileInput.value?.click()
+}
+
+// 处理文件选择
+const handleFileChange = (e) => {
+  const file = e.target.files[0]
+  if (file) {
+    processImageFile(file)
+  }
+  // 清空文件输入
+  if (fileInput.value) {
+    fileInput.value.value = ''
+  }
+}
+
+// 处理粘贴事件
+const handlePaste = (e) => {
+  console.log('粘贴事件触发')
+  const items = e.clipboardData.items
+  console.log('剪贴板项目:', items)
+  
+  for (let i = 0; i < items.length; i++) {
+    console.log('项目', i, '类型:', items[i].type)
+    if (items[i].type.indexOf('image') !== -1) {
+      const file = items[i].getAsFile()
+      console.log('获取到图片文件:', file)
+      processImageFile(file)
+      break
+    }
+  }
+}
+
+// 处理图片文件
+const processImageFile = (file) => {
+  // 验证文件类型
+  if (!isImageMime(file.type)) {
+    ElMessage.error('请选择JPG、PNG或WebP格式的图片')
+    return
+  }
+  
+  // 验证文件大小(限制5MB)
+  const maxSize = 5 * 1024 * 1024
+  if (file.size > maxSize) {
+    ElMessage.error('图片大小不能超过5MB')
+    return
+  }
+  
+  // 读取文件并添加到上传列表
+  const reader = new FileReader()
+  reader.onload = (e) => {
+    const imageUrl = e.target.result
+    // 检查图片是否已存在
+    const isDuplicate = uploadedImages.value.some(img => img.url === imageUrl)
+    if (!isDuplicate) {
+      uploadedImages.value.push({
+        url: imageUrl,
+        file: file
+      })
+    }
+  }
+  reader.readAsDataURL(file)
+}
+
+// 删除图片(从已上传列表)
+const removeImage = (index) => {
+  uploadedImages.value.splice(index, 1)
+}
+
+// 处理图片点击(放大查看)
+const handleImageClick = (img) => {
+  // 创建自定义图片预览
+  const previewContainer = document.createElement('div')
+  previewContainer.className = 'custom-image-preview'
+  previewContainer.style.cssText = `
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: rgba(0, 0, 0, 0.9);
+    z-index: 9999;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  `
+  
+  // 添加图片
+  const previewImage = document.createElement('img')
+  previewImage.src = img.url
+  previewImage.style.cssText = `
+    max-width: 90%;
+    max-height: 90%;
+    object-fit: contain;
+  `
+  
+  // 添加关闭按钮
+  const closeButton = document.createElement('button')
+  closeButton.innerHTML = '&times;'
+  closeButton.style.cssText = `
+    position: absolute;
+    top: 20px;
+    right: 20px;
+    font-size: 30px;
+    color: white;
+    background: transparent;
+    border: none;
+    cursor: pointer;
+    padding: 0;
+    width: 30px;
+    height: 30px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  `
+  
+  // 组装预览组件
+  previewContainer.appendChild(previewImage)
+  previewContainer.appendChild(closeButton)
+  document.body.appendChild(previewContainer)
+  
+  // 关闭预览的处理
+  const closePreview = () => {
+    document.body.removeChild(previewContainer)
+  }
+  
+  closeButton.addEventListener('click', closePreview)
+  previewContainer.addEventListener('click', (e) => {
+    if (e.target === previewContainer) {
+      closePreview()
+    }
+  })
+  
+  // ESC键关闭
+  const handleEscKey = (e) => {
+    if (e.key === 'Escape') {
+      closePreview()
+      document.removeEventListener('keydown', handleEscKey)
+    }
+  }
+  document.addEventListener('keydown', handleEscKey)
+}
+
+
+// 提交处理
+const handleSubmit = async () => {
+  if (!prompt.value.trim() && uploadedImages.value.length === 0) {
+    ElMessage.warning('请输入消息或上传图片')
+    return
+  }
+  
+  try {
+    uploading.value = true
+    
+    // 准备提交数据
+    let status_val = ''
+    
+    // 根据标签页和上传内容确定生成类型
+    if (activeTab.value === 'image') {
+      // 图片生成
+      status_val = uploadedImages.value.length > 0 ? '图生图' : '文生图'
+    } else {
+      // 视频生成
+      status_val = uploadedImages.value.length > 0 ? '图生视频' : '文生视频'
+    }
+    
+    const payload = {
+      status_val: status_val,
+      batch: uploadedImages.value.map(item => item.file), // 图片数组
+      prompt: prompt.value
+    }
+    
+    // 打印调试区域
+    console.log(payload);
+    await new Promise(resolve => setTimeout(resolve, 2000));
+    uploading.value = false;
+    return;
+
+    const res = await imageToText(payload)
+    
+    // 处理接口返回结果
+    if (res.code === 0) {
+      ElMessage.success('提交成功')
+      console.log('接口返回结果:', res)
+      
+      // 清空输入和图片列表
+      prompt.value = ''
+      uploadedImages.value = []
+    } else {
+      ElMessage.error(res.msg || '提交失败')
+    }
+  } catch (error) {
+    console.error('提交失败:', error)
+    ElMessage.error('提交失败,请稍后重试')
+  } finally {
+    uploading.value = false
+  }
+}
+
+// 计算预览列表
+const previewList = computed(() => {
+  return uploadedImages.value.map(item => item.url)
+})
+
+// 计算已选图片数量
+const selectedImagesCount = computed(() => {
+  return uploadedImages.value.length
+})
+
+// 根据生成类型获取占位符
+const getPlaceholder = computed(() => {
+  if (generationType.value === '视频生成') {
+    return '输入视频生成的提示词'
+  } else {
+    return '输入图片生成的提示词'
+  }
+})
+
+// 将DataURL转换为File对象
+const dataURLtoFile = (dataurl, filename) => {
+  const arr = dataurl.split(',')
+  const mime = arr[0].match(/:(.*?);/)[1]
+  const bstr = atob(arr[1])
+  let n = bstr.length
+  const u8arr = new Uint8Array(n)
+  while (n--) {
+    u8arr[n] = bstr.charCodeAt(n)
+  }
+  return new File([u8arr], filename, { type: mime })
+}
+
+
+</script>
+
+<style scoped>
+/* 生成类型选项卡 */
+.generation-tabs {
+  margin-bottom: 10px;
+  width: 100%;
+}
+
+.generation-tabs :deep(.el-tabs__header) {
+  margin: 0;
+}
+
+.generation-tabs :deep(.el-tabs__nav-wrap) {
+  margin: 0;
+}
+
+.generation-tabs :deep(.el-tabs__nav) {
+  background: transparent;
+}
+
+.generation-tabs :deep(.el-tabs__item) {
+  padding: 0 20px;
+  height: 40px;
+  line-height: 40px;
+  font-size: 14px;
+  color: #606266;
+  border: none;
+  border-radius: 0;
+  transition: all 0.3s ease;
+}
+
+.generation-tabs :deep(.el-tabs__item.is-active) {
+  color: #409eff;
+  font-weight: 500;
+  background: transparent;
+}
+
+.generation-tabs :deep(.el-tabs__active-bar) {
+  background-color: #409eff;
+  height: 2px;
+}
+
+.generation-tabs :deep(.tab-label) {
+  display: flex;
+  align-items: center;
+  gap: 6px;
+}
+
+.generation-tabs :deep(.tab-icon) {
+  font-size: 16px;
+}
+
+/* 聊天界面样式 */
+.chat-interface {
+  display: flex;
+  flex-direction: column;
+  width: 70%;
+  margin: 0 auto;
+  padding: 20px;
+}
+
+/* 输入区域容器 */
+.input-container {
+  display: flex;
+  flex-direction: column;
+  border: 1px solid #e4e7ed;
+  border-radius: 12px;
+  overflow: hidden;
+  width: 100%;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
+  background-color: #fff;
+}
+
+/* 上传图片列表容器 */
+.uploaded-images-container {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+  padding: 0;
+  min-height: auto;
+  max-height: 150px;
+  overflow-y: auto;
+}
+
+/* 单张图片样式 */
+.message-image {
+  position: relative;
+  width: 60px;
+  height: 60px;
+  border-radius: 4px;
+  overflow: hidden;
+  cursor: pointer;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+  transition: all 0.3s ease;
+}
+
+.message-image:hover {
+  transform: translateY(-1px);
+  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
+}
+
+.message-image :deep(.el-image) {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+  cursor: zoom-in;
+}
+
+/* 删除按钮 */
+.delete-img-btn {
+  position: absolute;
+  top: 2px;
+  right: 2px;
+  background-color: rgba(255, 255, 255, 0.8);
+  border-radius: 50%;
+  width: 20px;
+  height: 20px;
+  padding: 0;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  font-size: 12px;
+  cursor: pointer;
+}
+
+/* 图片选择对话框样式 */
+.image-selector {
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+  height: 100%;
+  max-height: 600px;
+  overflow-y: auto;
+}
+
+.image-upload-area {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 240px;
+  padding: 15px;
+  border: 1px dashed #dcdfe6;
+  border-radius: 8px;
+  background-color: #fafafa;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.upload-box {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+  justify-content: center;
+  align-items: center;
+  height: 100%;
+}
+
+.upload-icon {
+  font-size: 24px;
+  color: #909399;
+  margin-bottom: 8px;
+}
+
+.upload-text {
+  font-size: 14px;
+  color: #606266;
+}
+
+.upload-hint {
+  font-size: 12px;
+  color: #909399;
+  margin-top: 4px;
+}
+
+.image-upload-area:hover {
+  border-color: #409eff;
+  color: #409eff;
+  background-color: #ecf5ff;
+}
+
+
+.image-upload-area:hover {
+  border-color: #409eff;
+  background-color: #ecf5ff;
+}
+
+.upload-box {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  color: #909399;
+}
+
+.upload-icon {
+  font-size: 24px;
+  color: #c0c4cc;
+}
+
+.upload-box span {
+  font-size: 14px;
+  font-weight: 500;
+}
+
+/* 移除AI绘图文字相关样式 */
+.image-overlay {
+  display: none;
+}
+
+.image-tags {
+  display: none;
+}
+
+/* 图片预览容器 */
+.image-preview-container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  padding: 20px;
+  max-height: 70vh;
+  overflow: auto;
+}
+
+.full-size-image {
+  max-width: 100%;
+  max-height: 100%;
+  object-fit: contain;
+  border-radius: 4px;
+}
+
+.message-image:hover .delete-img-btn {
+  opacity: 1;
+}
+
+/* 上传区域:上传按钮和已上传图片水平排列 */
+.upload-area {
+  display: flex;
+  gap: 10px;
+  background-color: #fafafa;
+  border-bottom: 1px solid #e4e7ed;
+  margin-bottom: 0;
+  padding: 16px;
+}
+
+/* 上传按钮 */
+.add-btn {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 60px;
+  height: 60px;
+  border: 2px dashed #dcdfe6;
+  border-radius: 8px;
+  background-color: #fff;
+  color: #909399;
+  font-size: 24px;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.add-btn:hover {
+  border-color: #409eff;
+  color: #409eff;
+  background-color: #ecf5ff;
+  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
+}
+
+.add-btn span {
+  display: none;
+}
+
+/* 已上传图片容器 */
+.uploaded-images-container {
+  display: flex;
+  gap: 10px;
+  flex-wrap: wrap;
+  align-items: center;
+}
+
+/* 消息图片 */
+.message-image {
+  position: relative;
+  width: 60px;
+  height: 60px;
+  border-radius: 8px;
+  overflow: hidden;
+  cursor: pointer;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+}
+
+.message-image .el-image {
+  width: 100%;
+  height: 100%;
+  border-radius: 8px;
+}
+
+.input-wrapper {
+  display: flex;
+  gap: 12px;
+  align-items: flex-end;
+  padding: 16px;
+  background-color: #fff;
+}
+
+.add-btn :deep(.el-icon) {
+  font-size: 24px;
+  margin-bottom: 4px;
+}
+
+/* 聊天输入框 */
+.chat-input {
+  flex: 1;
+  border: none;
+  border-radius: 4px;
+  resize: none;
+  outline: none;
+  font-size: 14px;
+  line-height: 1.5;
+}
+
+:deep(.el-textarea) {
+  width: 100%;
+  margin: 0;
+}
+
+:deep(.el-textarea__inner) {
+  border: 1px solid #e4e7ed;
+  border-radius: 8px;
+  resize: none;
+  padding: 12px 16px;
+  font-size: 14px;
+  line-height: 1.5;
+  background-color: #fff;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  min-height: 80px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+}
+
+:deep(.el-textarea__inner:focus) {
+  border-color: #409eff;
+  box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
+  outline: none;
+}
+
+/* 发送按钮 */
+.send-btn {
+  border-radius: 8px;
+  padding: 8px 16px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  font-size: 14px;
+  background-color: #409eff;
+  border-color: #409eff;
+  transition: all 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
+  align-self: flex-end;
+  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
+}
+
+.send-btn:hover {
+  background-color: #66b1ff;
+  border-color: #66b1ff;
+  transform: translateY(-1px);
+  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  /* 输入容器响应式 */
+  .input-container {
+    border-radius: 8px;
+  }
+  
+  /* 上传区域响应式 */
+  .upload-area {
+    padding: 12px;
+    gap: 8px;
+  }
+  
+  .add-btn {
+    width: 50px;
+    height: 50px;
+    font-size: 20px;
+  }
+  
+  .message-image {
+    width: 50px;
+    height: 50px;
+  }
+  
+  /* 输入区域响应式 */
+  .input-wrapper {
+    flex-direction: column;
+    align-items: stretch;
+    padding: 12px;
+    gap: 12px;
+  }
+  
+  .chat-input {
+    min-height: 70px;
+  }
+  
+  .send-btn {
+    width: 44px;
+    height: 44px;
+    font-size: 18px;
+  }
+}
+</style>

+ 610 - 0
src/view/performance/QualityAssessment/TemplateManage.vue

@@ -0,0 +1,610 @@
+<template>
+  <div class="quality-assessment-template">
+    <el-card shadow="hover">
+      <template #header>
+        <div class="card-header">
+          <span>提示词模板管理</span>
+        </div>
+      </template>
+      
+      <!-- 左右两栏布局容器 -->
+      <div class="content-container">
+        <!-- 左侧表单部分 -->
+        <div class="form-section">
+             <!-- 尺寸选择 -->
+            <el-form-item label="选择尺寸"  label-width="120px"  prop="size">
+              <el-select v-model="formData.size" placeholder="请选择DALL-E 3支持的尺寸">
+                <el-option label="1024x1024 (正方形)" value="1024x1024" />
+                <el-option label="1792x1024 (宽屏)" value="1792x1024" />
+                <el-option label="1024x1792 (竖屏)" value="1024x1792" />
+              </el-select>
+            </el-form-item>
+
+          <el-form :model="formData" label-width="120px" :rules="rules" ref="formRef">
+            <!-- 场景分类选择 -->
+            <el-form-item label="场景分类" prop="sceneCategory">
+              <el-select v-model="formData.sceneCategory" placeholder="请选择场景分类" @change="onCategoryChange">
+                <el-option v-for="category in sceneCategories" :key="category.value" :label="category.label" :value="category.value" />
+              </el-select>
+            </el-form-item>
+            
+            <!-- 模板选择 -->
+            <el-form-item label="选择模板" prop="template">
+              <el-select v-model="formData.template" placeholder="请选择模板" @change="onTemplateChange">
+                <el-option 
+                  v-for="template in filteredTemplates" 
+                  :key="template.value" 
+                  :label="template.label" 
+                  :value="template.value"
+                >
+                  <template #default>
+                    <div class="template-option">
+                      <div class="template-title">{{ template.label }}</div>
+                      <div class="template-desc">{{ template.description }}</div>
+                    </div>
+                  </template>
+                </el-option>
+              </el-select>
+            </el-form-item>
+            
+            <!-- 通用产品字段 -->
+            <el-form-item v-if="currentTemplate?.fields?.productName" label="产品名称" prop="productName">
+              <el-input v-model="formData.productName" placeholder="请输入产品名称" />
+            </el-form-item>
+            
+            <!-- 通用主题字段 -->
+            <el-form-item v-if="currentTemplate?.fields?.theme" label="主题" prop="theme">
+              <el-input v-model="formData.theme" placeholder="请输入主题" />
+            </el-form-item>
+            
+            <!-- 活动相关字段 -->
+            <el-form-item v-if="currentTemplate?.fields?.eventName" label="活动名称" prop="eventName">
+              <el-input v-model="formData.eventName" placeholder="请输入活动名称" />
+            </el-form-item>
+            
+            <el-form-item v-if="currentTemplate?.fields?.eventSlogan" label="宣传语" prop="eventSlogan">
+              <el-input v-model="formData.eventSlogan" type="textarea" :rows="2" placeholder="请输入宣传语" />
+            </el-form-item>
+            
+            <el-form-item v-if="currentTemplate?.fields?.eventContent" label="活动内容" prop="eventContent">
+              <el-input v-model="formData.eventContent" type="textarea" :rows="2" placeholder="请输入活动内容" />
+            </el-form-item>
+            
+            <el-form-item v-if="currentTemplate?.fields?.eventDesc" label="活动描述" prop="eventDesc">
+              <el-input v-model="formData.eventDesc" type="textarea" :rows="2" placeholder="请输入活动描述" />
+            </el-form-item>
+            
+            <el-form-item v-if="currentTemplate?.fields?.eventTime" label="活动时间" prop="eventTime">
+              <el-input v-model="formData.eventTime" placeholder="请输入活动时间,如:7月30日-8月1日 16:00-22:00" />
+            </el-form-item>
+            
+            <el-form-item v-if="currentTemplate?.fields?.eventLocation" label="活动地点" prop="eventLocation">
+              <el-input v-model="formData.eventLocation" placeholder="请输入活动地点,如:上海市静安区南京西路1266号恒隆广场" />
+            </el-form-item>
+            
+            <!-- 食品相关字段 -->
+            <el-form-item v-if="currentTemplate?.fields?.foodType" label="食品类型" prop="foodType">
+              <el-input v-model="formData.foodType" placeholder="请输入食品类型,如:鱼干" />
+            </el-form-item>
+            
+            <el-form-item v-if="currentTemplate?.fields?.foodFlavor" label="食品口味" prop="foodFlavor">
+              <el-input v-model="formData.foodFlavor" placeholder="请输入食品口味,如:原味、香辣" />
+            </el-form-item>
+            
+            <el-form-item v-if="currentTemplate?.fields?.foodFeatures" label="产品特点" prop="foodFeatures">
+              <el-input v-model="formData.foodFeatures" type="textarea" :rows="2" placeholder="请输入产品特点,如:鲜香可口,营养丰富" />
+            </el-form-item>
+            
+            <!-- 电商相关字段 -->
+            <el-form-item v-if="currentTemplate?.fields?.productPrice" label="产品价格" prop="productPrice">
+              <el-input v-model="formData.productPrice" placeholder="请输入产品价格,如:99元" />
+            </el-form-item>
+            
+            <el-form-item v-if="currentTemplate?.fields?.productBenefits" label="产品优势" prop="productBenefits">
+              <el-input v-model="formData.productBenefits" type="textarea" :rows="3" placeholder="请输入产品优势,如:有机材料、环保包装" />
+            </el-form-item>
+            
+            <!-- 提示词输入 -->
+            <el-form-item label="提示词" prop="prompt">
+              <div class="prompt-hint" v-if="currentTemplate">
+                <el-alert
+                  :title="`${currentTemplate.label}提示:${currentTemplate.hint}`"
+                  type="info"
+                  :closable="false"
+                  show-icon
+                  style="margin-bottom: 10px;"
+                />
+              </div>
+              <el-input
+                v-model="formData.prompt"
+                type="textarea"
+                :rows="10"
+                placeholder="请输入提示词,或使用模板自动生成"
+              />
+            </el-form-item>
+            
+            <!-- 按钮区域 -->
+            <el-form-item>
+              <el-button type="primary" @click="expandText">优化提示词</el-button>
+              <el-button type="success" @click="generateImage">立即生成图片</el-button>
+              <el-button @click="resetForm">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+        
+        <!-- 右侧结果部分 -->
+        <div class="result-section">
+          <h3>生图结果</h3>
+          <!-- 加载状态显示 -->
+          <div v-if="loading" class="image-result">
+            <div style="text-align: center; padding: 50px 0;">
+              <el-icon class="is-loading" style="font-size: 32px; margin-bottom: 10px;">
+                <Loading />
+              </el-icon>
+              <p style="margin-bottom: 20px;">{{ progressText }}</p>
+              <el-progress :percentage="progress" :stroke-width="8" style="max-width: 300px; margin: 0 auto;"></el-progress>
+              <p style="margin-top: 10px;">{{ progress }}%</p>
+            </div>
+          </div>
+          <!-- 图片结果显示 -->
+          <div v-else-if="generatedImage" class="image-result">
+            <el-image
+              :src="generatedImage"
+              fit="contain"
+              style="max-width: 100%; max-height: 500px"
+            >
+              <template #error>
+                <div class="image-error">加载失败</div>
+              </template>
+            </el-image>
+          </div>
+          <!-- 空状态显示 -->
+          <div v-else class="no-result">
+            <el-empty description="点击生成图片按钮查看结果"></el-empty>
+          </div>
+        </div>
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import {ref,reactive,computed,watch} from 'vue'
+import {ElMessage,ElMessageBox,ElEmpty,ElImage} from 'element-plus'
+import {Loading} from '@element-plus/icons-vue'
+import {useUserStore} from '@/pinia/modules/user'
+import {GetTxtToTxt,imageToText} from '@/api/mes/job'
+
+defineOptions({name: 'TemplateManage'})
+
+// 场景分类
+const sceneCategories = [
+  { label: '产品宣传', value: 'productPromotion' },
+  { label: '活动海报', value: 'eventPoster' },
+  { label: '食品行业', value: 'foodIndustry' },
+  { label: '其他场景', value: 'other' }
+]
+
+// 模板内容定义(按场景分类)
+const templates = [
+  // 产品宣传类
+  {
+    value: 'productPromo',
+    label: '通用产品宣传',
+    category: 'productPromotion',
+    description: '适用于各类产品的宣传海报,突出产品特点和优势',
+    hint: '请填写产品名称和主题,系统将自动生成专业的产品宣传提示词',
+    fields: {
+      productName: true,
+      theme: true
+    },
+    generatePrompt: (formData) => {
+      return `创建一张精美的产品宣传图片,产品名称:${formData.productName},主题:${formData.theme || '宣传'}。尺寸${formData.size}。包含产品图片、产品名称、核心特点。设计风格现代简洁,色彩搭配协调,突出产品优势,整体视觉效果吸引人。`
+    }
+  },
+  {
+    value: 'techProductPromo',
+    label: '科技产品宣传',
+    category: 'productPromotion',
+    description: '专为科技类产品设计,突出科技感和创新特点',
+    hint: '适合电子产品、软件、数码设备等科技产品的宣传',
+    fields: {
+      productName: true,
+      theme: true,
+      productBenefits: true
+    },
+    generatePrompt: (formData) => {
+      return `设计一张科技感十足的产品宣传海报,产品名称:${formData.productName},主题:${formData.theme || '创新科技'}。尺寸${formData.size}。突出产品的科技感和创新特点,使用现代简约风格,蓝色调为主,包含产品图片、名称和核心优势:${formData.productBenefits || '高性能、智能化'}。整体设计具有未来感和视觉冲击力。`
+    }
+  },
+  
+  // 活动海报类
+  {
+    value: 'eventPoster',
+    label: '通用活动海报',
+    category: 'eventPoster',
+    description: '适用于各类活动的宣传海报,包含活动关键信息',
+    hint: '请填写活动名称、宣传语、时间地点等信息',
+    fields: {
+      eventName: true,
+      eventSlogan: true,
+      eventTime: true,
+      eventLocation: true,
+      eventContent: true,
+      eventDesc: true
+    },
+    generatePrompt: (formData) => {
+      return `设计一张精美的活动宣传海报,活动名称:${formData.eventName},宣传语:${formData.eventSlogan || '精彩不容错过'}。尺寸${formData.size}。活动时间:${formData.eventTime || '待定'},地点:${formData.eventLocation || '待定'}。活动内容:${formData.eventContent || '丰富多样的活动内容'},活动描述:${formData.eventDesc || '期待您的参与'}。使用鲜明的色彩,吸引人的排版,突出活动主题,整体设计具有视觉冲击力。`
+    }
+  },
+  {
+    value: 'festivalPoster',
+    label: '节日活动海报',
+    category: 'eventPoster',
+    description: '专为节日庆典活动设计的宣传海报',
+    hint: '适合节日派对、庆典活动、主题晚会等',
+    fields: {
+      eventName: true,
+      eventSlogan: true,
+      eventTime: true,
+      eventLocation: true,
+      theme: true
+    },
+    generatePrompt: (formData) => {
+      return `设计一张充满节日氛围的活动宣传海报,活动名称:${formData.eventName},节日主题:${formData.theme || '节日庆典'}。尺寸${formData.size}。宣传语:${formData.eventSlogan || '欢度佳节'}。活动时间:${formData.eventTime || '待定'},地点:${formData.eventLocation || '待定'}。使用节日相关的色彩和元素,营造欢快喜庆的氛围,整体设计具有强烈的视觉吸引力。`
+    }
+  },
+  {
+    value: 'foodGeneral',
+    label: '通用食品宣传',
+    category: 'foodIndustry',
+    description: '适用于各类食品的宣传海报,突出食品的美味和品质',
+    hint: '适合零食、饮料、餐饮等各类食品的宣传',
+    fields: {
+      productName: true,
+      foodType: true,
+      foodFlavor: true,
+      foodFeatures: true,
+      productPrice: true
+    },
+    generatePrompt: (formData) => {
+      return `设计一张诱人的${formData.foodType || '食品'}产品宣传海报,产品名称:${formData.productName},口味:${formData.foodFlavor || '美味'}。尺寸${formData.size}。特点:${formData.foodFeatures || '新鲜美味,品质保证'}。价格:${formData.productPrice || '面议'}。使用高饱和度的色彩,突出食品的质感和美味,包含产品图片、名称、口味、特点和价格。整体设计具有食欲感和视觉吸引力。`
+    }
+  },
+  
+  
+  // 其他场景
+  {
+    value: 'customTemplate',
+    label: '自定义模板',
+    category: 'other',
+    description: '自由发挥,自定义提示词生成图片',
+    hint: '可根据需求自由填写提示词,不受固定模板限制',
+    fields: {},
+    generatePrompt: (formData) => {
+      return formData.prompt || '请输入自定义提示词'
+    }
+  }
+]
+
+// 表单数据
+const formData = reactive({
+  sceneCategory: '',
+  size: '1024x1024',
+  template: '',
+  prompt: '',
+  // 通用字段
+  productName: '',
+  theme: '',
+  // 活动相关字段
+  eventName: '',
+  eventSlogan: '',
+  eventContent: '',
+  eventDesc: '',
+  eventTime: '',
+  eventLocation: '',
+  // 食品相关字段
+  foodType: '',
+  foodFlavor: '',
+  foodFeatures: '',
+  // 电商相关字段
+  productPrice: '',
+  productBenefits: ''
+})
+
+// 监听表单字段变化,自动更新提示词
+watch(() => ({
+  productName: formData.productName,
+  theme: formData.theme,
+  eventName: formData.eventName,
+  eventSlogan: formData.eventSlogan,
+  eventContent: formData.eventContent,
+  eventDesc: formData.eventDesc,
+  eventTime: formData.eventTime,
+  eventLocation: formData.eventLocation,
+  foodType: formData.foodType,
+  foodFlavor: formData.foodFlavor,
+  foodFeatures: formData.foodFeatures,
+  productPrice: formData.productPrice,
+  productBenefits: formData.productBenefits,
+  template: formData.template
+}), () => {
+  // 只有当选择了模板且当前模板不是自定义模板时,才自动更新提示词
+  if (currentTemplate.value && currentTemplate.value.value !== 'customTemplate') {
+    formData.prompt = currentTemplate.value.generatePrompt(formData)
+  }
+}, { deep: true })
+
+// 表单验证规则
+const rules = {
+  sceneCategory: [
+    { required: true, message: '请选择场景分类', trigger: 'change' }
+  ],
+  size: [
+    { required: true, message: '请选择尺寸', trigger: 'change' }
+  ],
+  template: [
+    { required: true, message: '请选择模板', trigger: 'change' }
+  ],
+  prompt: [
+    { required: true, message: '请输入提示词', trigger: 'blur' }
+  ]
+}
+
+// 表单引用
+const formRef = ref(null)
+
+// 生成的图片
+const generatedImage = ref('')
+// 加载状态变量
+const loading = ref(false)
+// 进度状态变量
+const progress = ref(0)
+const progressText = ref('准备生成')
+
+// 根据场景分类过滤模板
+const filteredTemplates = computed(() => {
+  if (!formData.sceneCategory) return templates
+  return templates.filter(template => template.category === formData.sceneCategory)
+})
+
+// 当前选中的模板
+const currentTemplate = computed(() => {
+  return templates.find(template => template.value === formData.template)
+})
+
+// 场景分类变化事件处理
+const onCategoryChange = () => {
+  // 重置模板选择
+  formData.template = ''
+  formData.prompt = ''
+}
+
+// 模板变化事件处理
+const onTemplateChange = () => {
+  // 根据选择的模板生成默认提示词
+  if (currentTemplate.value) {
+    formData.prompt = currentTemplate.value.generatePrompt(formData)
+  }
+}
+
+
+
+// 扩写文本方法
+const expandText = async () => {
+  formRef.value.validate(async (valid) => {
+    if (valid) {
+      // 调用扩写文本接口
+      ElMessage({ message: '正在扩写文本...', type: 'info' })
+      
+      // 准备请求参数
+      const params = {
+        status_val: '文生文',
+        prompt: formData.prompt,
+        size: formData.size,
+        productName: formData.productName,
+        theme: formData.theme,
+        template: formData.template,
+        sceneCategory: formData.sceneCategory
+      }
+      
+      try {
+        // 使用async/await调用API接口
+        const res = await GetTxtToTxt(params)
+        formData.prompt = res.data.content
+        ElMessage({ message: '文本扩写成功', type: 'success' })
+      } catch (error) {
+        console.error('扩写文本失败:', error)
+        ElMessage({ message: '扩写失败,请稍后重试', type: 'error' })
+      }
+    }
+  })
+}
+
+// 生成图片方法
+const generateImage = async () => {
+  formRef.value.validate(async (valid) => {
+    if (valid) {
+      // 解析尺寸
+      const [width, height] = formData.size.split('x').map(Number)
+      
+      // 设置加载状态为true
+      loading.value = true
+      // 初始化进度
+      progress.value = 0
+      progressText.value = '正在准备...'
+      
+      // 模拟进度更新(由于实际API可能不支持实时进度返回,使用定时器模拟)
+      const progressInterval = setInterval(() => {
+        if (progress.value < 90) { // 最多到90%,留10%给最终完成
+          progress.value += Math.floor(Math.random() * 10) + 5 // 随机增加5-15%
+          if (progress.value > 90) progress.value = 90
+          
+          // 更新进度文本
+          if (progress.value < 30) {
+            progressText.value = '正在处理请求...'
+          } else if (progress.value < 60) {
+            progressText.value = '正在生成图片内容...'
+          } else {
+            progressText.value = '正在优化图片细节...'
+          }
+        }
+      }, 500) // 每500毫秒更新一次进度
+      
+      // 准备请求参数
+      const params = {
+        status_val: '文生图',
+        prompt: formData.prompt,
+        width: width,
+        height: height,
+        size: formData.size,
+        productName: formData.productName,
+        theme: formData.theme,
+        template: formData.template,
+        sceneCategory: formData.sceneCategory
+      }
+      
+      try {
+        // 使用async/await调用API接口
+        const res = await GetTxtToTxt(params)
+        
+        // 处理API返回结果
+        if (res && res.data && res.data.code === 200) {
+          // 完成进度
+          progress.value = 100
+          progressText.value = '已完成'
+          
+          if (res.data.data.type === 'image') {
+            generatedImage.value = res.data.data.image_path
+            ElMessage({ message: '图片生成成功', type: 'success' })
+          } else {
+            generatedImage.value = res.data.data.content || res.data.data.image_data || res.data.data
+            ElMessage({ message: '图片生成成功', type: 'success' })
+          }
+        } else {
+          const errorMsg = res.data?.message || '生成失败,返回数据格式不正确'
+          ElMessage({ message: errorMsg, type: 'error' })
+        }
+      } catch (error) {
+        console.error('生成图片失败:', error)
+        ElMessage({ message: '生成失败,请稍后重试', type: 'error' })
+        progress.value = 0
+        progressText.value = '生成失败'
+      } finally {
+        // 无论成功或失败,都关闭加载状态和进度定时器
+        loading.value = false
+        clearInterval(progressInterval)
+      }
+    }
+  })
+}
+
+// 重置表单
+const resetForm = () => {
+  formRef.value.resetFields()
+  generatedImage.value = ''
+}
+</script>
+
+<style scoped>
+.quality-assessment-template {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+/* 左右两栏布局 */
+.content-container {
+  display: flex;
+  gap: 30px;
+  margin-top: 20px;
+}
+
+.form-section {
+  flex: 1;
+  max-width: 50%;
+}
+
+.result-section {
+  flex: 1;
+  max-width: 50%;
+  min-height: 400px;
+  border-left: 1px solid #ebeef5;
+  padding-left: 30px;
+}
+
+.result-section h3 {
+  margin-top: 0;
+  margin-bottom: 20px;
+  font-size: 18px;
+  font-weight: 600;
+  color: #303133;
+}
+
+/* 风格选择下拉框已替代卡片式选择器,相关样式已清理 */
+
+.image-result {
+  margin-top: 20px;
+  padding: 20px;
+  background-color: #fafafa;
+  border-radius: 8px;
+}
+
+.no-result {
+  height: 400px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: #fafafa;
+  border-radius: 8px;
+}
+
+.image-error {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 200px;
+  background-color: #f5f7fa;
+  color: #909399;
+}
+
+/* 模板选项样式 */
+.template-option {
+  padding: 10px;
+}
+
+.template-title {
+  font-weight: 600;
+  margin-bottom: 5px;
+}
+
+.template-desc {
+  font-size: 12px;
+  color: #909399;
+  line-height: 1.4;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .content-container {
+    flex-direction: column;
+  }
+  
+  .form-section,
+  .result-section {
+    max-width: 100%;
+  }
+  
+  .result-section {
+    border-left: none;
+    border-top: 1px solid #ebeef5;
+    padding-left: 0;
+    padding-top: 30px;
+  }
+}
+</style>

+ 153 - 80
src/view/performance/QualityAssessment/TestTemplate.vue

@@ -26,28 +26,39 @@
       </el-form-item>
     </el-form>
 
-    <!-- 模型选择 -->
-    <el-descriptions column="1" border>
-      <el-descriptions-item label="文生图模型">
-        <div style="display: flex; align-items: center; gap: 20px;">
-          <el-radio-group 
-            v-model="txtimgselectedModel"
-            @change="handleModelChange"
-          >
-            <el-radio 
-              v-for="item in txttoimg_modelList" 
-              :key="item.id"
-              :label="item.txttoimg"
-            >
-              {{ item.txttoimg }} 
-              <span v-if="item.id === usedId" style="color: #67C23A; margin-left: 5px;">(当前使用)</span>
-            </el-radio>
-          </el-radio-group>
-        </div>
-      						
-		<el-button type="success" @click="setActive" :disabled="selectedId === usedId">设为当前使用模型</el-button>
-      </el-descriptions-item>
-    </el-descriptions>
+    <!-- 文生图弹窗 -->
+    <el-dialog v-model="txtimgDialogVisible" title="文生图" width="660px" top="10%">
+      <el-form label-width="100px">
+         <!-- <el-form-item label="提示词" prop="chinese_description">
+          <el-input 
+            v-model="form.chinese_description" 
+            type="textarea" 
+            :rows="3" 
+            placeholder="请输入文生图描述"
+          />
+        </el-form-item> -->
+        <el-form-item label="文生图模型">
+          <div style="display: flex; align-items: center; gap: 20px; flex-wrap: wrap;">
+            <el-radio-group v-model="txtimgselectedModel" @change="handleModelChange">
+              <el-radio 
+                v-for="item in txttoimg_modelList" 
+                :key="item.id"
+                :label="item.txttoimg">
+                {{ item.txttoimg }} 
+                <span v-if="item.id === usedIds.wenshengtu" style="color: #67C23A; margin-left: 5px;">(默认使用)</span>
+              </el-radio>
+            </el-radio-group>
+            <el-button type="success"  @click="setActive('wenshengtu')"  :disabled="!selectedIds.wenshengtu || selectedIds.wenshengtu === usedIds.wenshengtu">
+              设为默认使用模型
+            </el-button>
+          </div>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="txtimgDialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="generateTxtImg" :loading="isGenerating">生成文生图</el-button>
+      </template>
+    </el-dialog>
 
     <!-- 表格展示 -->
     <el-table
@@ -148,30 +159,6 @@
 	      <span v-else>-</span>
 	    </template>
 	  </el-table-column>
-	  
-	  <!-- <el-table-column label="文生图预览" width="120">
-	    <template #default="{ row }">
-	      <el-image
-	        :src="row.taskId ? `https://chatapi.onechats.ai/mj/image/${row.taskId}` : formatImageUrl(row.new_image_url)"
-	        :preview-src-list="[row.taskId ? `https://chatapi.onechats.ai/mj/image/${row.taskId}` : formatImageUrl(row.new_image_url)]"
-	        style="width: 90px; height: 70px;"
-	        fit="contain"
-	        preview-teleported
-	      />
-	    </template>
-	  </el-table-column> -->
-	  
-      <!-- <el-table-column label="文生图预览" width="120">
-        <template #default="{ row }">
-          <el-image
-            :src="formatImageUrl(row.new_image_url)"
-            :preview-src-list="[formatImageUrl(row.new_image_url)]"
-            style="width: 90px; height: 70px;"
-            fit="contain"
-            preview-teleported
-          />
-        </template>
-      </el-table-column> -->
       
       <el-table-column label="图生图预览" width="120">
         <template #default="{ row }">
@@ -258,12 +245,38 @@
 <script setup>
 import { ref, reactive, toRaw, onMounted } from 'vue'
 import { ElMessage } from 'element-plus'
-import { getTable, imageToText, Template_ids,txttoimg_moxing,txttoimg_update, getSide } from '@/api/mes/job'
+import { getTable, imageToText, Template_ids,txttoimg_moxing,GetHttpUrl,txttoimg_update, getSide } from '@/api/mes/job'
 import { useUserStore } from '@/pinia/modules/user'
 import { ArrowDown } from '@element-plus/icons-vue'
 
+//获取登录用户信息
 const userStore = useUserStore()
-const _username = ref(userStore.userInfo.userName + '/' + userStore.userInfo.nickName)
+const _username = ref('')
+_username.value = userStore.userInfo.userName + '/' + userStore.userInfo.nickName
+console.log('获取用户信息',_username.value)
+console.log('获取用户名称',userStore.userInfo.nickName)
+
+//获取服务器地址
+const baseUrl = ref('')
+const port = ref('')
+const full_url = ref('')
+// 从接口获取服务器地址
+const fetchServerUrl = async () => {
+  try {
+    const res = await GetHttpUrl()
+    if (res.code === 0 && res.data && res.data.full_url) {
+      full_url.value = res.data.full_url
+      baseUrl.value = res.data.baseUrl
+      port.value = res.data.port
+	  console.log('获取服务器地址',full_url.value)
+	  console.log('IP地址',baseUrl.value)
+	  console.log('端口',port.value)
+    }
+  } catch (error) {
+    console.error('获取服务器地址失败:', error)
+  }
+}
+fetchServerUrl();
 
 const searchInfo = ref('')
 const tableData1 = ref([])
@@ -276,7 +289,7 @@ const width = ref('')
 const height = ref('')
 const isLoading = ref(false)
 const txttotxt_selectedOption = ref('gemini-2.0-flash')
-const selectedOption = ref('black-forest-labs/FLUX.1-kontext-pro')
+const selectedOption = ref('dall-e-3')
 const num = ref(1)
 const _parh = ref([])
 const folderList = ref([])
@@ -292,16 +305,53 @@ const editFormData = reactive({
   img_name: ''
 })
 
+// 定义文生图表单对象
+const form = reactive({
+  chinese_description: ''
+})
+
 const formatImageUrl = (path) => {
   if (!path) return ''
-  const base = 'http://20.0.16.128:9093'
-  return `${base}/${path.replace(/^public\//, '')}`
+  return `${full_url.value}/${path.replace(/^public\//, '')}`
 }
 
 const txttoimg_modelList = ref([]); // 存储所有模型数据
 const txtimgselectedModel = ref(''); // 当前选中的模型名称
-const usedId = ref(null); // 当前使用的模型ID
-const selectedId = ref(null); // 用户选择的模型ID
+const usedId = ref(null); // 当前使用的模型ID(兼容旧代码)
+const selectedId = ref(null); // 用户选择的模型ID(兼容旧代码)
+const txtimgDialogVisible = ref(false); // 文生图弹窗可见性
+const isGenerating = ref(false); // 文生图生成中状态
+const usedIds = ref({}); // 当前使用的模型ID集合
+const selectedIds = ref({}); // 用户选择的模型ID集合
+
+// 获取文生图模型列表
+const fetchTxtImgModels = async () => {
+  try {
+    const response = await txttoimg_moxing();
+    txttoimg_modelList.value = response.data.models.wenshengtu;
+    // 获取当前使用的模型ID
+    usedIds.value = response.data.used_ids;
+    const currentUsedId = usedIds.value.wenshengtu;
+    
+    // 设置默认选中的模型
+    const defaultModel = txttoimg_modelList.value.find(item => item.id === currentUsedId);
+    if (defaultModel) {
+      txtimgselectedModel.value = defaultModel.txttoimg;
+      usedId.value = defaultModel.id;
+      selectedId.value = defaultModel.id; 
+      selectedIds.value.wenshengtu = defaultModel.id;
+      selectedOption.value = defaultModel.txttoimg;
+    }
+    
+    console.log('文生图模型列表:', txttoimg_modelList.value);
+    console.log('当前使用的模型ID:', currentUsedId);
+    console.log('默认选中的模型:', defaultModel);
+  } catch (error) {
+    console.error('获取文生图模型列表失败:', error);
+    ElMessage.error('获取模型列表失败');
+  }
+}
+fetchTxtImgModels();
 
 const getTableData = async () => {
     const res = await getTable({
@@ -318,38 +368,39 @@ const getTableData = async () => {
       folderList.value = res.data.folder
     }
 
-    const res_Template = await Template_ids()
-    height.value = res_Template.data.height
-    width.value = res_Template.data.width
-	
-	//文生图模型列表
-	const response = await txttoimg_moxing();
-	txttoimg_modelList.value = response.data.list;
-	// 设置默认选中的模型(txttoimg_val为"1"的模型)
-	const defaultModel = response.data.list.find(item => item.txttoimg_val === "1");
-	if (defaultModel) {
-	  txtimgselectedModel.value = defaultModel.txttoimg;
-	  usedId.value = defaultModel.id;
-	  selectedId.value = defaultModel.id; 
-	  selectedOption.value = defaultModel.txttoimg;
-	}
+    // const res_Template = await Template_ids({path:row['old_image_url']});
+    // height.value = res_Template.data.height
+    // width.value = res_Template.data.width
 }
 
+
 // 当选择模型变化时
 const handleModelChange = (modelName) => {
   const model = txttoimg_modelList.value.find(item => item.txttoimg === modelName);
   if (model) {
     selectedId.value = model.id;
-	selectedOption.value = model.txttoimg
+    selectedIds.value.wenshengtu = model.id;
+    selectedOption.value = model.txttoimg;
+    console.log('选择的模型ID:', model.id);
   }
 }
-//设置模型
-const setActive = async () => {
-  if (selectedId.value) {
-    const result = await txttoimg_update({id:selectedId.value});
-    console.log(result)
-    usedId.value = selectedId.value;
-    ElMessage.success(`设置成功`);
+// 设置默认模型
+const setActive = async (type) => {
+  const id = selectedIds.value[type]
+  if (id) {
+    try {
+      // 调用API设置默认模型
+      const res = await txttoimg_update({ id: id,type:"wenshengtu"})
+      if (res.code === 0) {
+        usedIds.value[type] = id
+        ElMessage.success('默认模型设置成功')
+      } else {
+        ElMessage.error(res.msg || '设置默认模型失败')
+      }
+    } catch (error) {
+      console.error('设置默认模型失败', error)
+      ElMessage.error('设置默认模型失败')
+    }
   }
 }
 
@@ -380,15 +431,32 @@ const SelectionChange = (rows) => {
   _parh.value = rows.map(item => item.old_image_url)
 }
 
-const texttoimg = () => {
-  processImages(toRaw(_parh.value), '文生图')
+
+// 文生图生成函数
+const generateTxtImg = () => {
+  txtimgDialogVisible.value = false
+  processImages(toRaw(_parh.value), '文生图', form.chinese_description)
+}
+
+const texttoimg = async () => {
+  if (_parh.value.length === 0) {
+    ElMessage.warning('请先选择要处理的图片')
+    return
+  }
+  // 获取模型列表
+  await fetchTxtImgModels()
+  // 显示弹窗
+  txtimgDialogVisible.value = true
 }
 
 const imgtoimg = () => {
   processImages(toRaw(_parh.value), '图生图')
 }
 
-const processImages = async (files, type) => {
+// 是否执行几何图(默认不执行)
+const executeKeywords = ref(false)
+
+const processImages = async (files, type, prompt = '') => {
   if (!Array.isArray(files) || files.length === 0) {
     ElMessage.warning('请选择要处理的图片')
     return
@@ -414,9 +482,14 @@ const processImages = async (files, type) => {
       num: num.value,
       width: width.value,
       height: height.value,
-	  executeKeywords:'',
+      executeKeywords:executeKeywords.value,
     }
 
+    // console.log(payload);
+    // await new Promise(resolve => setTimeout(resolve, 2000));
+    // isLoading.value = false;
+    // return;
+
     try {
       await imageToText(payload)
       ElMessage.success(`处理目录:${dir},共 ${images.length} 张 * ${num.value} 次`)

+ 47 - 21
src/view/performance/QualityAssessment/excessive.vue

@@ -151,7 +151,6 @@
 	<el-dialog v-model="showDescDialog" title="" width="890px" top="0%">
 	  <div style="display: flex; gap: 10px; max-height: 70vh; overflow: hidden;">
 	    <!-- 左侧图片区域,自适应图片尺寸,可滚动查看完整图片 -->
-		
 		<div style="flex: 1; display: flex; align-items: start; justify-content: center; border: 1px solid #eee; overflow: auto; max-height: 80vh;">
 		  <template v-if="path_image_url">
 		    <el-image
@@ -161,7 +160,6 @@
 		        :preview-src-list="[formatImageUrl(path_image_url)]"
 		        :initial-index="0"
 		      />
-			  
 		    </template>
 		  <template v-else>
 			  <el-image
@@ -668,7 +666,7 @@
 </template>
 
 <script setup>
-import {ref,reactive,toRaw} from 'vue'
+import {ref,reactive,toRaw,watch} from 'vue'
 import {ElMessage, ElMessageBox,ElLoading } from 'element-plus'
 import axios from 'axios'
 import {Plus,Delete,CircleCheck,CircleClose} from '@element-plus/icons-vue'
@@ -678,7 +676,7 @@ textToImage,Template_ids,sd_models,getSide,
 TemplateList,
 Template,
 updatetemplate,getPreviewFolders,
-setActiveTemplate,
+setActiveTemplate,GetHttpUrl,
 packImagess,getUploadPath,get_queue_logs,getTaskProgress
 } from '@/api/mes/job'
 import { useUserStore } from '@/pinia/modules/user';
@@ -690,18 +688,44 @@ _username.value = userStore.userInfo.userName + '/' + userStore.userInfo.nickNam
 console.log('获取用户信息',_username.value)
 console.log('获取用户名称',userStore.userInfo.nickName)
 
-
 //获取服务器地址
+const baseUrl = ref('')
+const port = ref('')
+const full_url = ref('')
+// 从接口获取服务器地址
+const fetchServerUrl = async () => {
+  try {
+    const res = await GetHttpUrl()
+    if (res.code === 0 && res.data && res.data.full_url) {
+      full_url.value = res.data.full_url
+      baseUrl.value = res.data.baseUrl
+      port.value = res.data.port
+	  console.log('获取服务器地址',full_url.value)
+	  console.log('IP地址',baseUrl.value)
+	  console.log('端口',port.value)
+    }
+  } catch (error) {
+    console.error('获取服务器地址失败:', error)
+  }
+}
+fetchServerUrl();
+
 const formatImageUrl = (path) => {
   if (!path) return ''
-  const base = 'http://20.0.16.128:9093'
-  return `${base}/${path.replace(/^public\//, '')}`
+  // 如果path已经是完整URL,直接返回
+  if (path.startsWith('http://') || path.startsWith('https://')) {
+    return path
+  }
+  // 如果path是相对路径,拼接baseUrl
+  return `${full_url.value}/${path.replace(/^public\//, '')}`
 }
 
+
 // --------------------- 图片上传 ---------------------
 const tableData = ref([])
 const getPreviewSubDirslist = async () => {
 	const res = await getPreviewSubDirs()
+	console.log('getPreviewSubDirs',res)
 	const processedData = res.data.map(item => {
 	  return {
 	    ...item,
@@ -713,9 +737,12 @@ const getPreviewSubDirslist = async () => {
 getPreviewSubDirslist()
 
 // 环境配置
-const basePath = import.meta.env.VITE_BASE_PATH || 'http://20.0.16.128'
-const uploadsPort = import.meta.env.VITE_UPLOADS_PORT || '9093'
-const uploadUrl = ref(`${basePath}:${uploadsPort}/api/Facility/ImgUpload`)
+const uploadUrl = ref(`${full_url.value}/api/Facility/ImgUpload`)
+
+// 确保上传URL与服务器地址同步
+watch(full_url, (newUrl) => {
+  uploadUrl.value = `${newUrl}/api/Facility/ImgUpload`
+})
 const uploadHeaders = { 
   'Content-Type': 'multipart/form-data',
   'Authorization': 'Bearer ' + localStorage.getItem('token')
@@ -1678,26 +1705,25 @@ const confirmPack = async () => {
       ElMessage.warning(`没有找到${zipselectedOption.value}尺寸的图片`);
       return;
     }
-// console.log(imagePaths)
-// return;
-    const packRes = await packImagess({ paths: imagePaths });
+	// console.log(imagePaths)
+	// return;
 
+    const packRes = await packImagess({ paths: imagePaths });
     if (packRes.code === 0 && packRes.download_url) {
       ElMessage.success('打包成功,正在下载...');
-
-      // ✅ 替换为服务的真实 IP 和端口
-      const basePath = import.meta.env.VITE_BASE_PATH || 'http://20.0.16.128';
-      const uploadsPort = import.meta.env.VITE_UPLOADS_PORT || '9093';
-
       let url = packRes.download_url;
-
       try {
         const parsedUrl = new URL(url);
         if (parsedUrl.hostname === '127.0.0.1' || parsedUrl.hostname === 'localhost') {
-          parsedUrl.hostname = new URL(basePath).hostname;
-          parsedUrl.port = uploadsPort;
+          // 使用从接口获取的服务器地址
+          const serverUrl = new URL(full_url.value);
+          parsedUrl.hostname = serverUrl.hostname;
+          parsedUrl.port = serverUrl.port;
           url = parsedUrl.toString();
         }
+	   console.log('修改前URL:', packRes.download_url);
+	   console.log('修改后URL:', url);
+	   console.log('使用的服务器地址:', full_url.value);
       } catch (e) {
         console.error('URL 解析失败:', e);
       }

+ 0 - 337
src/view/performance/QualityAssessment/gongdanhesuan.vue

@@ -1,337 +0,0 @@
-<template>
-  <div>
-    <!--左侧树侧形结构-->
-	<el-form>
-	  <el-form-item>
-	    <!-- <el-input v-model="searchInfo" placeholder="搜索" clearable style="width: 180px;" /> -->
-	    <!-- <el-button type="primary" icon="search" @click="onSubmit" title="搜索">查询</el-button> -->
-	    	<el-button type="primary" icon="search" class="bt" @click="analyzeMonthlyOverloss">AI 超节损分析(月度)</el-button>
-	    <!-- <el-button type="primary" icon="edit" class="bt" @click="handleShowAdd">新增</el-button> -->
-	    <!-- <el-button type="primary" icon="delete" class="bt" @click="handleDelete">删除</el-button> -->
-	  </el-form-item>
-	</el-form>
-	
-    <el-container>
-      <layout-sider :resize-directions="['right']" :width="220" style="margin-right: 10px;">
-        <div class="JKWTree-tree" style="height: 70vh;">
-          <h3>工单超节损核算</h3>
-          <el-tree :data="treeData" highlight-current @node-click="handleNodeClick" />
-        </div>
-      </layout-sider>
-      <el-container>
-
-        <el-main>
-          <div class="gva-table-box">
-            
-            <el-table ref="multipleTable" style="width: 100%;height: 65vh"
-              :row-style="{ height: '20px' }" :header-cell-style="{ padding: '0px' }"
-              :cell-style="{ padding: '0px' }" :header-row-style="{ height: '20px' }"
-              border tooltip-effect="dark" :data="tableData1" row-key="ID"
-              highlight-current-row="true"
-              :cell-class-name="tableDataCellClass"
-              @selection-change="cjsSelectionChange" :show-overflow-tooltip="true">
-              <el-table-column type="selection" width="55" />
-                  <el-table-column align="left" sortable label="工单编号" prop="Gd_gdbh" width="110" fixed />
-                  <el-table-column align="left" label="印件号" prop="jjcp_yjno" width="70" />
-                  <el-table-column align="left" label="联数" prop="yj_ls" width="70" />
-                  <el-table-column align="left" sortable label="印件代号" prop="yjdh" width="110" />
-                  <el-table-column align="left" sortable label="产品名称" prop="成品名称" width="250" />
-                  <el-table-column align="left" label="实际投料" prop="实际投料" width="90" />
-                  <el-table-column align="left" label="计量单位" prop="计量单位" width="85" />
-                  <el-table-column align="left" label="入仓数量" prop="warehousing_num" width="90" />
-                  <el-table-column align="left" sortable label="目标合格率" prop="target_rate" width="120" />
-                  <el-table-column align="left" sortable label="实际合格率" prop="real_rate" width="120" />
-                  <el-table-column align="left" sortable label="奖罚金额合计" prop="reward_money" width="140" />
-                  <el-table-column align="left" sortable label="废品合计" prop="废品合计" width="120" />
-                  <el-table-column align="left" sortable label="工单无形损" prop="工单无形损" width="120" />
-                  <el-table-column align="left" label="材料废" prop="材料废" width="80" />
-                  <el-table-column align="left" label="处发废" prop="外发废" width="80" />
-                  <el-table-column align="left" label="工单计划损耗" prop="工单计划损耗" width="110" />
-                  <el-table-column align="left" label="工单制程废" prop="zcfp" width="100" />
-                  <el-table-column align="left" label="工单检验废" prop="工单质检废" width="100" />
-                </el-table>
-            <!-- 分页 -->
-            <div class="gva-pagination">
-              <el-pagination @size-change="handleSizeChange"  @current-change="handleCurrentChange"
-                :current-page="page"
-                :page-sizes="[10, 30, 50, 100]"
-                :page-size="pageSize"
-                layout="total, sizes, prev, pager, next, jumper" :total="total">
-              </el-pagination>
-            </div>
-          </div>
-        </el-main>
-      </el-container>
-    </el-container>
-
-
-    <!-- 弹窗部分 -->
-
-  </div>
-</template>
-
-<script>
-
-</script>
-<script setup>
-import {Layout,LayoutContent,LayoutHeader,LayoutSider} from '@arco-design/web-vue'
-import {ElMessage,ElMessageBox,dayjs} from 'element-plus'
-import {reactive,ref,nextTick,onMounted} from 'vue'
-import {  getSide,
-  getTable,oversizedloss
-} from '@/api/mes/job'
-import {useUserStore} from '@/pinia/modules/user'
-defineOptions({name: '06PackingDocuments'})
-
-//获取登录用户信息
-const userStore = useUserStore()
-const _username = ref('')
-_username.value = userStore.userInfo.userName + '/' + userStore.userInfo.nickName
-console.log('用户名称:',userStore.userInfo.nickName)
-
-//全局获取当前日期
-const today = new Date();
-const year = today.getFullYear();
-const month = String(today.getMonth() + 1).padStart(2, '0'); // 月份从 0 开始,需要补零
-const day = String(today.getDate()).padStart(2, '0');
-const hours = String(today.getHours()).padStart(2, '0');
-const minutes = String(today.getMinutes()).padStart(2, '0');
-const seconds = String(today.getSeconds()).padStart(2, '0');
-const currentDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
-const currentDates = `${year}-${month}-${day}`;
-
-
-//=========== 左侧树侧形结构 =========== 
-// 侧边栏数据
-const treeData = ref([])
-const getSideData = async() => {
-  const res = await getSide()
-  if (res.code === 0) {
-    const { data } = res
-    const transformedData = []
-
-    for (const [key, value] of Object.entries(data)) {
-      const [date, total] = key.split('-') // 提取日期和数量
-      const transformedItem = {
-        label: `${date}(工单数:${total})`,
-        date: date,
-        // children: value.map((item) => ({
-        //   label: `${item['客户编号']}【${item['客户名称']}】(工单数:${item.total})`,
-        //   date: date,
-        //   code: item?.['客户编号'],
-        // })),
-      }
-      transformedData.push(transformedItem)
-    }
-    treeData.value = transformedData
-  }
-}
-getSideData()
-
-
-
-//=========== 点击左侧树形获取数据 ===========
-const tableData1 = ref([])
-const _date = ref('')
-const handleNodeClick = async (node) => {
-	console.log(node.date)
-	_date.value = node.date
-	const res = await getTable({ date: node.date, limit: 9999, page: 1 });
-	console.log(res); // 调试数据
-	
-	tableData1.value = res.data.map((item) => ({
-		...item,
-		csgd:
-		parseFloat(item['target_rate']) - parseFloat(item['real_rate']) > 0
-		  ? '√'
-		  : '',
-		date: node.date,
-		考核: String(item['考核']) === '是' ? '参与' : '否' // 确保数据类型一致
-	}));
-}
-
-//上方表格字体颜色
-function cellClassName({ row, column, rowIndex, columnIndex }) {
-	if(column.property === '考核' && row.考核 === '参与'){
-	return 'red-cell'
-	}
-	// if ([8,12,].includes(columnIndex)) {
-	//   return 'red-cell'
-	// }
-	return ''
-}
-
-const analyzeMonthlyOverloss = async () => {
-  if (tableData1.value.length === 0) {
-    ElMessage({ type: 'warning', message: '请选择具体的月份' });
-    return;
-  }
-
-  // 显示原始数据用于调试
-  // console.log('原始数据:', tableData1.value);
-
-  // 字段对应中文名称映射
-  const fieldMap = {
-    Gd_gdbh: '工单编号',
-    jjcp_yjno: '印件号',
-    yj_ls: '联数',
-    yjdh: '印件代号',
-    '成品名称': '产品名称',
-    '实际投料': '实际投料',
-    '计量单位': '计量单位',
-    warehousing_num: '入仓数量',
-    target_rate: '目标合格率',
-    real_rate: '实际合格率',
-    reward_money: '奖罚金额合计',
-    '废品合计': '废品合计',
-    '工单无形损': '工单无形损',
-    '材料废': '材料废',
-    '外发废': '处发废',
-    '工单计划损耗': '工单计划损耗',
-    zcfp: '工单制程废',
-    '工单质检废': '工单检验废',
-  };
-
-  // 创建要发送的数据结构
-  const requestData = {
-    content: tableData1.value.map(row => {
-      const formattedRow = {};
-      Object.keys(fieldMap).forEach(key => {
-        formattedRow[fieldMap[key]] = row[key] ?? '';
-      });
-      return formattedRow;
-    })
-  };
-
-  console.log('提交内容:', requestData);
-
-	const res = await oversizedloss({ content: requestData.content,date:_date.value });
-	console.log('接口响应:', res);
-
-};
-
-
-//搜索框
-const searchInfo = ref('')
-
-//搜索按钮
-const onSubmit = async (row) => {
-	console.log("搜索按钮")
-}
-	
-//表格
-const tableData = reactive([])
-
-//单击表格行
-const Clickonthetable = async (row) => {
-	console.log(row)
-}
-
-//双击表格行
-const Doubleclickonthetable = async (row) => {
-	console.log(row)
-}
-
-//复选框 表格
-const cjsSelectionChange = async (row) => {
-	console.log(row)
-}
-
-
-	
-//分页
-const total = ref(0)
-const page = ref(1)
-const limit = ref(10)
-const handleCurrentChange = (val) => {
-  page.value = val;
-  //调用接口↓↓↓↓
-  
-};
-
-// 修改页面容量 点击多少条/页
-const handleSizeChange = (val) => {
-  pageSize.value = val;
-  //调用接口↓↓↓↓
-  
-};
-
-	
-</script>
-
-<style scoped>
-:deep(.plan-usage-low div) {
-	color: red !important;
-}
-
-.JKWTree-container {
-	display: flex;
-}
-
-.JKWTree-tree {
-	width: 100%;
-	background-color: #fff;
-	/*background-color: rgba(241, 224, 224, 0.99);*/
-	padding: 10px;
-	margin-right: 20px;
-}
-
-.JKWTree-tree h3 {
-	font-size: 15px;
-	font-weight: 700;
-	margin: 10px 0;
-}
-
-.JKWTree-content {
-	flex: 1;
-}
-
-:deep(.el-table__body .warning-row) {
-	background: #FFFF80 !important;
-}
-
-/* 选中某行时的背景色 */
-:deep(.el-table__body tr.current-row)>td {
-	background: #ff80ff !important;
-}
-
-:deep(.el-table .bg-yellow) {
-	background: yellow;
-}
-</style>
-<style scoped>
-:deep(.el-table td .cell) {
-	line-height: 25px !important;
-}
-
-:deep(.el-tabs__header) {
-	margin-bottom: 0;
-}
-
-.search {
-	margin-left: 0px !important;
-	margin-right: 10px !important;
-}
-
-.bt {
-	margin-left: 2px !important;
-	padding: 3px !important;
-	font-size: 12px;
-
-}
-:deep(.red-cell div) {
-  color: #ff0000 !important;
-}
-
-.el-tabs__header {
-	margin: 0px !important;
-}
-
-.gva-table-box {
-	padding: 0px !important;
-}
-
-.mab {
-	margin-bottom: 5px;
-}
-</style>

+ 583 - 0
src/view/performance/QualityAssessment/texttoimage.vue

@@ -0,0 +1,583 @@
+<template>
+  <div class="image-generation-container">
+    <el-card class="mb-4">
+      <template #header>
+          <span>文生图生成</span>
+      </template>
+      <br>
+      <el-form ref="formRef" :model="form" label-width="100px" class="mb-4"
+          style="margin: 0px;padding: 0px !important;">
+        <el-form-item label="提示词" prop="chinese_description">
+          <el-input 
+            v-model="form.chinese_description" 
+            type="textarea" 
+            :rows="3" 
+            placeholder="请输入文生图描述"
+          />
+        </el-form-item>
+        
+        <el-form-item label="模型" prop="model">
+          <div style="display: flex; align-items: center; gap: 20px;">
+            <el-radio-group v-model="txtimgselectedModel" @change="handleModelChange">
+                <el-radio 
+                v-for="item in txttoimg_modelList" 
+                :key="item.id"
+                :label="item.txttoimg">
+                {{ item.txttoimg }} 
+                <span v-if="item.id === usedIds.wenshengtu" style="color: #67C23A; margin-left: 5px;">(默认使用)</span>
+                </el-radio>
+            </el-radio-group>
+            <el-button type="success"  @click="setActive('wenshengtu')"  :disabled="!selectedIds.wenshengtu || selectedIds.wenshengtu === usedIds.wenshengtu">
+            设为默认使用模型
+            </el-button>
+          </div>
+        </el-form-item>
+        
+        <el-form-item label="出图尺寸">
+          <div style="display: flex; gap: 10px;">
+            <div style="width: calc(50% - 5px);">
+              <el-input 
+                v-model.number="form.width" 
+                placeholder="宽度" 
+                type="number" 
+                min="1" 
+                style="width: 100%"
+              />
+            </div>
+            <div style="width: calc(50% - 5px);">
+              <el-input 
+                v-model.number="form.height" 
+                placeholder="高度" 
+                type="number" 
+                min="1" 
+                style="width: 100%"
+              />
+            </div>
+          </div>
+        </el-form-item>
+        
+        <el-form-item>
+          <el-button 
+            type="primary" 
+            @click="texttoimg" 
+            :loading="isGenerating"
+          >
+            {{ isGenerating ? '生成中...' : '生成文生图' }}
+          </el-button>
+          <el-button @click="resetForm">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+    
+    <!-- 历史记录 -->
+    <el-card class="mt-1">
+      <el-table :data="historyList"
+                :row-style="{ height: '20px' }"
+                :cell-style="{ padding: '0px' }" :header-row-style="{ height: '20px' }"
+                :header-cell-style="{ padding: '0px' }"
+                style="width: 100%;height: 40vh">
+        <el-table-column align="center" prop="id" label="ID" width="80" />
+        <el-table-column prop="prompt" label="提示词" width="500">
+          <template #default="scope">
+            <span :title="scope.row.prompt" class="text-ellipsis" style="display: inline-block; width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">{{ scope.row.prompt }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="model" label="模型" width="100" />
+        <el-table-column label="尺寸" width="100">
+          <template #default="scope">
+            {{ scope.row.width }}x{{ scope.row.height }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="sys_rq" label="创建时间" width="180" />
+        <el-table-column label="状态" width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.web_url ? 'success' : 'warning'">
+              {{ scope.row.web_url ? '已完成' : '生成中' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="300">
+            <template #default="scope">
+              <el-button 
+                size="small" 
+                @click="viewHistoryImage(scope.row)"
+                :disabled="!scope.row.web_url"
+              >
+                查看
+              </el-button>
+              <el-button 
+                size="small" 
+                type="primary" 
+                @click="refreshImage(scope.row)"
+                v-if="!scope.row.web_url && scope.row.image_id"
+              >
+                重新获取图片
+              </el-button>
+            </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页组件 -->
+      <div class="gva-pagination">
+          <el-pagination
+              v-model:current-page="page"
+              v-model:page-size="pageSize"
+              :page-sizes="[10, 30, 50, 100, 500, 1000]"
+              layout="total, sizes, prev, pager, next, jumper"
+              :total="total"
+              @size-change="handleSizeChange"
+              @current-change="handleCurrentChange">
+          </el-pagination>
+        </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue'
+import { ElMessage } from 'element-plus'
+import { txttoimg_moxing, txttoimg_update,imageToText } from '@/api/mes/job'
+import { useUserStore } from '@/pinia/modules/user';
+
+//获取登录用户信息
+const userStore = useUserStore()
+const _username = ref('')
+_username.value = userStore.userInfo.userName + '/' + userStore.userInfo.nickName
+console.log('获取用户信息',_username.value)
+console.log('获取用户名称',userStore.userInfo.nickName)
+
+// 表单数据
+const form = reactive({
+  chinese_description: '',
+  model: '',
+  width: 1024, // 默认宽度
+  height: 1024 // 默认高度
+})
+
+// 表单引用
+const formRef = ref()
+
+// 页面状态
+const isGenerating = ref(false);
+const dialogVisible = ref(false);
+const dialogImageUrl = ref('');
+const isPreviewLoading = ref(false);
+
+// 历史记录相关
+const historyList = ref([]);
+const page = ref(1);
+const pageSize = ref(10);
+const total = ref(0);
+
+// 模型选择相关变量
+const txtimgselectedModel = ref('');
+const txttoimg_modelList = ref([]);
+const usedIds = ref({});
+const selectedIds = ref({});
+
+// 格式化图片URL
+const formatImageUrl = (path) => {
+  if (!path) return ''
+  
+  // 避免重复拼接http://
+  if (path.startsWith('http://') || path.startsWith('https://')) {
+    return path
+  }
+  
+  const base = 'http://20.0.16.128:9093'
+  // 避免重复拼接斜杠
+  const normalizedPath = path.startsWith('/') ? path.substring(1) : path
+  const normalizedBase = base.endsWith('/') ? base : `${base}/`
+  
+  return `${normalizedBase}${normalizedPath}`
+}
+
+const loadImageHistory = async () => {
+  // 获取模型列表和历史记录
+  const response = await txttoimg_moxing();
+  txttoimg_modelList.value = response.data.models.wenshengtu;
+  usedIds.value = response.data.used_ids;
+  // 设置默认选中的模型
+  if (txttoimg_modelList.value.length > 0) {
+    const defaultModel = txttoimg_modelList.value.find(item => item.id === usedIds.value.wenshengtu);
+    if (defaultModel) {
+      txtimgselectedModel.value = defaultModel.txttoimg;
+      selectedIds.value.wenshengtu = defaultModel.id;
+      form.model = defaultModel.txttoimg;
+    }
+  }
+}
+loadImageHistory()
+
+// 生成图片
+const texttoimg = async () => {
+  if (!form.chinese_description) {
+    ElMessage.warning('请输入提示词')
+    return
+  }
+  
+  // 加载开启
+  isGenerating.value = true
+  
+  try {
+    const payload = {
+        status_val : '文生图',
+        type: '文生图',
+        selectedOption: txtimgselectedModel.value,
+        width: form.width,
+        height: form.height,
+        chinese_description: form.chinese_description,
+        sys_id:userStore.userInfo.nickName
+    }
+
+    // 打印调试信息
+    console.log('生成图片请求参数:', payload)
+    // await new Promise(resolve => setTimeout(resolve, 2000));
+	// isLoading.value = false;
+	// return;
+
+    // 调用图片生成API
+    const res = await imageToText(payload)
+    
+    if (res.code === 200) {
+      ElMessage.success('图片生成任务已提交')
+      // 生成成功后刷新历史记录
+      await loadImageHistory()
+      // 重置表单
+      resetForm()
+    } else {
+      ElMessage.error(res.msg || '图片生成失败')
+    }
+  } catch (error) {
+    console.error('图片生成过程中发生错误:', error)
+    ElMessage.error('图片生成失败,请检查网络连接后重试')
+  } finally {
+    // 关闭加载状态
+    isGenerating.value = false
+  }
+}
+
+// 轮询检查视频生成进度
+let checkInterval = null
+const startCheckingProgress = (videoId) => {
+  if (!videoId) return
+  
+  // 清除之前的轮询
+  if (checkInterval) {
+    clearInterval(checkInterval)
+  }
+  
+  // 最大检查次数,避免无限轮询
+  let checkCount = 0
+  const maxCheckCount = 20 // 最多检查20次(60秒)
+  
+  // 每3秒检查一次
+  checkInterval = setInterval(async () => {
+    checkCount++
+    
+    if (checkCount > maxCheckCount) {
+      ElMessage.info('视频生成可能需要更长时间,请手动刷新查看')
+      clearInterval(checkInterval)
+      return
+    }
+    
+    try {
+      // 使用videoContent接口检查视频状态
+      const statusRes = await videoContent({ video_id: videoId, action: 'status' })
+      
+      if (statusRes.code === 0 && statusRes.data?.status === 'completed' && statusRes.data?.web_url) {
+        // 视频生成完成
+        ElMessage.success('视频生成完成')
+        
+        // 重新加载历史记录
+        await loadVideoHistory()
+        
+        // 查找对应的视频记录
+        const videoItem = historyList.value.find(item => item.video_id === videoId)
+        if (videoItem) {
+          // 自动打开视频播放对话框
+          playHistoryVideo(videoItem)
+        }
+        
+        clearInterval(checkInterval)
+      } else if (statusRes.code !== 0) {
+        console.error('检查视频状态失败', statusRes.msg)
+      }
+    } catch (error) {
+      console.error('检查视频进度失败', error)
+    }
+  }, 3000)
+}
+
+// 重置表单
+const resetForm = () => {
+  form.prompt = ''
+  form.model = 'sora-2'
+  form.seconds = 4
+  form.size = '1280x720'
+  videoUrl.value = ''
+}
+
+// 下载视频
+const downloadVideo = () => {
+  if (!videoUrl.value) return
+  
+  // 创建下载链接
+  const link = document.createElement('a')
+  link.href = videoUrl.value
+  link.download = `video_${Date.now()}.mp4`
+  document.body.appendChild(link)
+  link.click()
+  document.body.removeChild(link)
+  
+  ElMessage.success('视频下载中')
+}
+
+// 下载历史视频
+const downloadHistoryVideo = (row) => {
+  if (!row.web_url) {
+    ElMessage.warning('视频尚未生成完成')
+    return
+  }
+  
+  const videoUrl = formatVideoUrl(row.web_url)
+  const link = document.createElement('a')
+  link.href = videoUrl
+  link.download = `video_${row.video_id || Date.now()}.mp4`
+  document.body.appendChild(link)
+  link.click()
+  document.body.removeChild(link)
+  
+  ElMessage.success('视频下载中')
+}
+
+// 下载对话框中的视频
+const downloadDialogVideo = () => {
+  if (!currentVideoItem.value || !currentVideoItem.value.web_url) return
+  
+  downloadHistoryVideo(currentVideoItem.value)
+}
+
+// 重新生成
+const regenerateVideo = () => {
+  generateVideo()
+}
+
+// 播放历史视频
+const playHistoryVideo = (row) => {
+  if (!row.web_url) {
+    ElMessage.warning('视频尚未生成完成')
+    return
+  }
+  
+  // 设置当前视频项和URL
+  currentVideoItem.value = row
+  dialogVideoUrl.value = formatVideoUrl(row.web_url)
+  
+  console.log('正在播放视频:', dialogVideoUrl.value)
+  
+  // 显示对话框
+  dialogVisible.value = true
+  
+  // 填充表单
+  // form.prompt = row.prompt
+  // form.model = row.model
+  // form.seconds = row.seconds
+  // form.size = row.size
+}
+
+// 重新获取视频
+const refreshVideo = async (row) => {
+  if (!row.video_id) {
+    ElMessage.warning('视频ID不存在,无法重新获取')
+    return
+  }
+    ElMessage.info('正在重新获取视频...')
+    // 调用videoContent接口重新获取视频
+    const res = await videoContent({ video_id: row.video_id })
+    // 无论获取结果如何,都刷新表格数据
+    await loadVideoHistory()
+    if (res.code === 0) {
+      // 如果获取到了视频URL
+      if (res.data && res.data.web_url) {
+        ElMessage.success('视频获取成功')
+        
+        // 查找更新后的视频项
+        const updatedVideo = historyList.value.find(item => item.video_id === row.video_id)
+        if (updatedVideo && updatedVideo.web_url) {
+          // 自动播放获取到的视频
+          playHistoryVideo(updatedVideo)
+        }
+      } else {
+        ElMessage.info('视频仍在生成中,请稍后再试')
+      }
+    }
+}
+
+// 处理模型选择变化
+const handleModelChange = (modelName) => {
+  // 找到当前选中模型的ID
+  const selectedModel = txttoimg_modelList.value.find(item => item.txttoimg === modelName)
+  if (selectedModel) {
+    selectedIds.value.wenshengtu = selectedModel.id
+    form.model = modelName
+  }
+}
+
+// 设置默认模型
+const setActive = async (type) => {
+  const id = selectedIds.value[type]
+  if (id) {
+    try {
+      // 调用API设置默认模型
+      const res = await txttoimg_update({ id: id,type:"wenshengtu"})
+      if (res.code === 0) {
+        usedIds.value[type] = id
+        ElMessage.success('默认模型设置成功')
+      } else {
+        ElMessage.error(res.msg || '设置默认模型失败')
+      }
+    } catch (error) {
+      console.error('设置默认模型失败', error)
+      ElMessage.error('设置默认模型失败')
+    }
+  }
+}
+
+// 搜索处理
+const handleSearch = () => {
+  // 重置页码为1
+  page.value = 1
+  // 重新加载数据
+  loadVideoHistory()
+}
+
+// 分页大小变化处理
+const handleSizeChange = (size) => {
+  pageSize.value = size
+  // 重新加载数据
+  loadVideoHistory()
+}
+
+// 当前页码变化处理
+const handleCurrentChange = (current) => {
+  page.value = current
+  // 重新加载数据
+  loadVideoHistory()
+}
+
+// 删除历史视频
+const deleteHistoryVideo = async (id) => {
+  try {
+    // 这里应该调用实际的删除API
+    // const res = await deleteVideoApi({ id })
+    // if (res.code === 0) {
+      const index = historyList.value.findIndex(item => item.id === id)
+      if (index !== -1) {
+        historyList.value.splice(index, 1)
+        ElMessage.success('删除成功')
+      }
+    // }
+  } catch (error) {
+    console.error('删除视频失败', error)
+    ElMessage.error('删除失败,请重试')
+  }
+}
+</script>
+
+<style scoped lang="scss">
+
+::v-deep(.el-card__body){
+	padding: 0px;
+}
+.video-generation-container {
+  padding: 0px;
+  
+  .card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+  
+  .refresh-button {
+    margin-left: auto;
+  }
+}
+
+.el-form {
+  .el-form-item {
+    margin-bottom: 10px;
+    padding: 0px;
+  }
+}
+
+.el-table {
+  .el-button {
+    margin-right: 5px;
+  }
+}
+
+// 对话框视频样式
+.dialog-video-preview {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  min-height: 400px;
+  padding: 20px 0;
+  
+  video {
+    max-height: 600px;
+    max-width: 100%;
+    border-radius: 4px;
+  }
+  
+  .loading-text {
+    font-size: 16px;
+    color: #909399;
+  }
+}
+
+// 最新生成结果样式
+.video-result-preview {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 10px;
+  background-color: #fafafa;
+  border-radius: 4px;
+  
+  .video-result-info {
+    flex: 1;
+    p {
+      margin: 5px 0;
+      font-size: 14px;
+    }
+  }
+  
+  .video-result-actions {
+    display: flex;
+    gap: 10px;
+  }
+}
+
+// 响应式调整
+@media screen and (max-width: 768px) {
+  .dialog-video-preview {
+    min-height: 300px;
+    
+    video {
+      max-height: 400px;
+    }
+  }
+  
+  .video-result-preview {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 15px;
+    
+    .video-result-actions {
+      width: 100%;
+      justify-content: flex-start;
+    }
+  }
+}
+</style>

+ 622 - 0
src/view/performance/QualityAssessment/video.vue

@@ -0,0 +1,622 @@
+<template>
+  <div class="video-generation-container">
+    <el-card class="mb-4">
+      <template #header>
+          <span>文生视频生成</span>
+      </template>
+      <br>
+      <el-form ref="formRef" :model="form" label-width="100px" class="mb-4"
+          style="margin: 0px;padding: 0px !important;">
+        <el-form-item label="提示词" prop="prompt" required>
+          <el-input 
+            v-model="form.prompt" 
+            type="textarea" 
+            :rows="3" 
+            placeholder="请输入视频描述,例如:一个穿着宇航服的宇航员在月球上行走, 高品质, 电影级"
+          />
+        </el-form-item>
+        
+        <el-form-item label="模型" prop="model">
+          <el-select v-model="form.model" placeholder="请选择模型">
+            <el-option label="sora-2" value="sora-2" />
+          </el-select>
+        </el-form-item>
+        
+        <el-form-item label="时长(秒)" prop="seconds">
+          <el-select 
+            v-model.number="form.seconds" 
+            placeholder="请选择视频时长" 
+            style="width: 100%"
+          >
+            <el-option label="4秒" :value="4" />
+            <el-option label="8秒" :value="8" />
+            <el-option label="12秒" :value="12" />
+          </el-select>
+        </el-form-item>
+        
+        <el-form-item label="分辨率" prop="size">
+          <el-select v-model="form.size" placeholder="请选择分辨率" style="width: 100%">
+            <el-option label="720x1280" value="720x1280" />
+            <el-option label="1280x720" value="1280x720" />
+          </el-select>
+        </el-form-item>
+        
+        <el-form-item>
+           <!-- <el-input 
+              v-model="searchInfo" 
+              placeholder="搜索提示词" 
+              @keyup.enter="handleSearch"
+              clearable
+              @clear="handleSearch"
+              style="width: 230px; margin-right: 10px;margin: 0px;" 
+            />
+            <el-button type="primary" icon="Search" class="search" @click="handleSearch">查询</el-button> -->
+          <el-button 
+            type="primary" 
+            @click="generateVideo" 
+            :loading="isGenerating"
+          >
+            {{ isGenerating ? '生成中...' : '生成视频' }}
+          </el-button>
+          <el-button @click="resetForm">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+    
+    <!-- 视频播放对话框 -->
+    <el-dialog
+      v-model="dialogVisible"
+      title="视频播放"
+      width="80%"
+	  style="margin: 0px;margin-left: 10%;margin-top: 3%;"
+      center
+      destroy-on-close
+    >
+      <div class="dialog-video-preview">
+        <div v-if="!dialogVideoUrl" class="loading-text">加载中...</div>
+        <video 
+          :src="dialogVideoUrl" 
+          controls 
+          width="100%" 
+          height="auto"
+          v-else
+          autoplay
+        ></video>
+      </div>
+      <template #footer>
+        <el-button @click="dialogVisible = false">关闭</el-button>
+      </template>
+    </el-dialog>
+    
+    <!-- 历史记录 -->
+    <el-card class="mt-1">
+      <el-table :data="historyList"
+                :row-style="{ height: '20px' }"
+                :cell-style="{ padding: '0px' }" :header-row-style="{ height: '20px' }"
+                :header-cell-style="{ padding: '0px' }"
+                style="width: 100%;height: 40vh">
+        <el-table-column align="center" prop="id" label="ID" width="80" />
+        <el-table-column prop="prompt" label="提示词" width="500">
+          <template #default="scope">
+            <span :title="scope.row.prompt" class="text-ellipsis" style="display: inline-block; width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">{{ scope.row.prompt }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="model" label="模型" width="100" />
+        <el-table-column prop="seconds" label="时长" width="80" />
+        <el-table-column prop="size" label="分辨率" width="100" />
+        <el-table-column prop="sys_rq" label="创建时间" width="180" />
+        <el-table-column label="状态" width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.web_url ? 'success' : 'warning'">
+              {{ scope.row.web_url ? '已完成' : '生成中' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="300">
+            <template #default="scope">
+              <el-button 
+                size="small" 
+                @click="playHistoryVideo(scope.row)"
+                :disabled="!scope.row.web_url"
+              >
+                播放
+              </el-button>
+              <el-button 
+                size="small" 
+                type="primary" 
+                @click="refreshVideo(scope.row)"
+                v-if="!scope.row.web_url && scope.row.video_id"
+              >
+                重新获取视频
+              </el-button>
+              <!-- <el-button size="small" type="danger" @click="deleteHistoryVideo(scope.row.id)">删除</el-button> -->
+            </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页组件 -->
+      <div class="gva-pagination">
+          <el-pagination
+              v-model:current-page="page"
+              v-model:page-size="pageSize"
+              :page-sizes="[10, 30, 50, 100, 500, 1000]"
+              layout="total, sizes, prev, pager, next, jumper"
+              :total="total"
+              @size-change="handleSizeChange"
+              @current-change="handleCurrentChange">
+          </el-pagination>
+        </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue'
+import { ElMessage } from 'element-plus'
+import {Getvideolist,video,videoContent
+} from '@/api/mes/job'
+
+// 表单数据
+const form = reactive({
+  prompt: '',
+  model: 'sora-2',
+  seconds: 4,
+  size: '1280x720'
+})
+
+// 表单引用
+const formRef = ref()
+
+// 状态变量
+const isGenerating = ref(false)
+const videoUrl = ref('')
+const dialogVisible = ref(false)
+const dialogVideoUrl = ref('')
+const currentVideoItem = ref(null)
+const historyList = ref([])
+// 分页相关数据
+const page = ref(1)
+const pageSize = ref(30)
+const total = ref(0)
+// 搜索关键词
+const searchInfo = ref('')
+
+// 格式化视频URL
+const formatVideoUrl = (path) => {
+  if (!path) return ''
+  
+  // 避免重复拼接http://
+  if (path.startsWith('http://') || path.startsWith('https://')) {
+    return path
+  }
+  
+  const base = 'http://20.0.16.128:9093'
+  // 避免重复拼接斜杠
+  const normalizedPath = path.startsWith('/') ? path.substring(1) : path
+  const normalizedBase = base.endsWith('/') ? base : `${base}/`
+  
+  return `${normalizedBase}${normalizedPath}`
+}
+
+// 加载历史视频列表
+const loadVideoHistory = async () => {
+  try {
+    const params = {
+      page: page.value,
+      limit: pageSize.value
+    }
+    // 如果有搜索关键词,添加到请求参数中
+    if (searchInfo.value.trim()) {
+      params.search = searchInfo.value.trim()
+    }
+    
+    const res = await Getvideolist(params)
+    if (res.code === 0) {
+      historyList.value = Array.isArray(res.data.list) ? res.data.list : res.data
+      // 如果后端返回total,使用返回值,否则保持现有值
+      // 设置总数
+      total.value = res.count || 0
+    }
+  } catch (error) {
+    console.error('加载视频历史失败', error)
+    ElMessage.error('加载历史记录失败')
+  }
+}
+
+// 组件挂载时加载历史
+loadVideoHistory()
+
+// 生成视频
+const generateVideo = async () => {
+// console.log(form);
+// return false;
+  // 表单验证
+  if (!form.prompt) {
+    ElMessage.warning('请输入提示词')
+    return
+  }
+  
+  isGenerating.value = true
+  
+  try {
+    // 第一步:调用video接口生成视频ID
+    const videoIdRes = await video(form)
+    
+    if (videoIdRes.code === 0 && videoIdRes.data?.video_id) {
+      const videoId = videoIdRes.data.video_id
+      ElMessage.success('已提交视频生成请求,正在生成中...')
+      
+      // 第二步:使用videoContent接口根据ID生成视频
+      // 这里添加一个延迟,确保视频ID已经在后端系统中就绪
+      await new Promise(resolve => setTimeout(resolve, 1000))
+      
+      // 调用videoContent接口
+      const generateRes = await videoContent({ video_id: videoId })
+      
+      // 无论成功与否,都重新加载历史记录表格
+      await loadVideoHistory()
+      
+      if (generateRes.code === 0) {
+        // 如果视频已生成完成
+        if (generateRes.data && generateRes.data.web_url) {
+          ElMessage.success('视频生成成功')
+          
+          // 查找生成的视频项
+          const newVideoItem = historyList.value.find(item => item.video_id === videoId)
+          if (newVideoItem) {
+            // 自动打开视频播放对话框
+            playHistoryVideo(newVideoItem)
+          }
+        } else {
+          ElMessage.info('视频正在生成中,请稍后刷新查看')
+          
+          // 启动轮询检查进度
+          startCheckingProgress(videoId)
+        }
+      } else {
+        // 提取更详细的错误信息
+        let errorMsg = generateRes.msg || '未知错误'
+        if (generateRes.data && generateRes.data.error_message) {
+          try {
+            // 尝试解析JSON格式的错误信息
+            const errorData = JSON.parse(generateRes.data.error_message)
+            if (errorData.error && errorData.error.message) {
+              errorMsg += ' - ' + errorData.error.message
+            }
+          } catch (e) {
+            // 如果解析失败,直接使用原始错误信息
+            errorMsg += ' - ' + generateRes.data.error_message
+          }
+        }
+        
+        ElMessage.error('视频生成失败:' + errorMsg)
+      }
+    } else {
+      // 即使创建任务失败,也刷新表格数据
+      await loadVideoHistory()
+      
+      // 提取更详细的错误信息
+      let errorMsg = videoIdRes.msg || '未知错误'
+      if (videoIdRes.data && videoIdRes.data.error_message) {
+        try {
+          // 尝试解析JSON格式的错误信息
+          const errorData = JSON.parse(videoIdRes.data.error_message)
+          if (errorData.error && errorData.error.message) {
+            errorMsg += ' - ' + errorData.error.message
+          }
+        } catch (e) {
+          // 如果解析失败,直接使用原始错误信息
+          errorMsg += ' - ' + videoIdRes.data.error_message
+        }
+      }
+      
+      ElMessage.error('创建视频任务失败:' + errorMsg)
+    }
+  } catch (error) {
+    console.error('视频生成过程中发生错误', error)
+    // 发生异常也尝试刷新表格
+    try {
+      await loadVideoHistory()
+    } catch (e) {
+      console.error('刷新表格失败', e)
+    }
+    ElMessage.error('视频生成失败,请检查网络连接后重试')
+  } finally {
+    isGenerating.value = false
+  }
+}
+
+// 轮询检查视频生成进度
+let checkInterval = null
+const startCheckingProgress = (videoId) => {
+  if (!videoId) return
+  
+  // 清除之前的轮询
+  if (checkInterval) {
+    clearInterval(checkInterval)
+  }
+  
+  // 最大检查次数,避免无限轮询
+  let checkCount = 0
+  const maxCheckCount = 20 // 最多检查20次(60秒)
+  
+  // 每3秒检查一次
+  checkInterval = setInterval(async () => {
+    checkCount++
+    
+    if (checkCount > maxCheckCount) {
+      ElMessage.info('视频生成可能需要更长时间,请手动刷新查看')
+      clearInterval(checkInterval)
+      return
+    }
+    
+    try {
+      // 使用videoContent接口检查视频状态
+      const statusRes = await videoContent({ video_id: videoId, action: 'status' })
+      
+      if (statusRes.code === 0 && statusRes.data?.status === 'completed' && statusRes.data?.web_url) {
+        // 视频生成完成
+        ElMessage.success('视频生成完成')
+        
+        // 重新加载历史记录
+        await loadVideoHistory()
+        
+        // 查找对应的视频记录
+        const videoItem = historyList.value.find(item => item.video_id === videoId)
+        if (videoItem) {
+          // 自动打开视频播放对话框
+          playHistoryVideo(videoItem)
+        }
+        
+        clearInterval(checkInterval)
+      } else if (statusRes.code !== 0) {
+        console.error('检查视频状态失败', statusRes.msg)
+      }
+    } catch (error) {
+      console.error('检查视频进度失败', error)
+    }
+  }, 3000)
+}
+
+// 重置表单
+const resetForm = () => {
+  form.prompt = ''
+  form.model = 'sora-2'
+  form.seconds = 4
+  form.size = '1280x720'
+  videoUrl.value = ''
+}
+
+// 下载视频
+const downloadVideo = () => {
+  if (!videoUrl.value) return
+  
+  // 创建下载链接
+  const link = document.createElement('a')
+  link.href = videoUrl.value
+  link.download = `video_${Date.now()}.mp4`
+  document.body.appendChild(link)
+  link.click()
+  document.body.removeChild(link)
+  
+  ElMessage.success('视频下载中')
+}
+
+// 下载历史视频
+const downloadHistoryVideo = (row) => {
+  if (!row.web_url) {
+    ElMessage.warning('视频尚未生成完成')
+    return
+  }
+  
+  const videoUrl = formatVideoUrl(row.web_url)
+  const link = document.createElement('a')
+  link.href = videoUrl
+  link.download = `video_${row.video_id || Date.now()}.mp4`
+  document.body.appendChild(link)
+  link.click()
+  document.body.removeChild(link)
+  
+  ElMessage.success('视频下载中')
+}
+
+// 下载对话框中的视频
+const downloadDialogVideo = () => {
+  if (!currentVideoItem.value || !currentVideoItem.value.web_url) return
+  
+  downloadHistoryVideo(currentVideoItem.value)
+}
+
+// 重新生成
+const regenerateVideo = () => {
+  generateVideo()
+}
+
+// 播放历史视频
+const playHistoryVideo = (row) => {
+  if (!row.web_url) {
+    ElMessage.warning('视频尚未生成完成')
+    return
+  }
+  
+  // 设置当前视频项和URL
+  currentVideoItem.value = row
+  dialogVideoUrl.value = formatVideoUrl(row.web_url)
+  
+  console.log('正在播放视频:', dialogVideoUrl.value)
+  
+  // 显示对话框
+  dialogVisible.value = true
+  
+  // 填充表单
+  // form.prompt = row.prompt
+  // form.model = row.model
+  // form.seconds = row.seconds
+  // form.size = row.size
+}
+
+// 重新获取视频
+const refreshVideo = async (row) => {
+  if (!row.video_id) {
+    ElMessage.warning('视频ID不存在,无法重新获取')
+    return
+  }
+    ElMessage.info('正在重新获取视频...')
+    // 调用videoContent接口重新获取视频
+    const res = await videoContent({ video_id: row.video_id })
+    // 无论获取结果如何,都刷新表格数据
+    await loadVideoHistory()
+    if (res.code === 0) {
+      // 如果获取到了视频URL
+      if (res.data && res.data.web_url) {
+        ElMessage.success('视频获取成功')
+        
+        // 查找更新后的视频项
+        const updatedVideo = historyList.value.find(item => item.video_id === row.video_id)
+        if (updatedVideo && updatedVideo.web_url) {
+          // 自动播放获取到的视频
+          playHistoryVideo(updatedVideo)
+        }
+      } else {
+        ElMessage.info('视频仍在生成中,请稍后再试')
+      }
+    }
+}
+
+// 搜索处理
+const handleSearch = () => {
+  // 重置页码为1
+  page.value = 1
+  // 重新加载数据
+  loadVideoHistory()
+}
+
+// 分页大小变化处理
+const handleSizeChange = (size) => {
+  pageSize.value = size
+  // 重新加载数据
+  loadVideoHistory()
+}
+
+// 当前页码变化处理
+const handleCurrentChange = (current) => {
+  page.value = current
+  // 重新加载数据
+  loadVideoHistory()
+}
+
+// 删除历史视频
+const deleteHistoryVideo = async (id) => {
+  try {
+    // 这里应该调用实际的删除API
+    // const res = await deleteVideoApi({ id })
+    // if (res.code === 0) {
+      const index = historyList.value.findIndex(item => item.id === id)
+      if (index !== -1) {
+        historyList.value.splice(index, 1)
+        ElMessage.success('删除成功')
+      }
+    // }
+  } catch (error) {
+    console.error('删除视频失败', error)
+    ElMessage.error('删除失败,请重试')
+  }
+}
+</script>
+
+<style scoped lang="scss">
+
+::v-deep(.el-card__body){
+	padding: 0px;
+}
+.video-generation-container {
+  padding: 0px;
+  
+  .card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+  
+  .refresh-button {
+    margin-left: auto;
+  }
+}
+
+.el-form {
+  .el-form-item {
+    margin-bottom: 10px;
+    padding: 0px;
+  }
+}
+
+.el-table {
+  .el-button {
+    margin-right: 5px;
+  }
+}
+
+// 对话框视频样式
+.dialog-video-preview {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  min-height: 400px;
+  padding: 20px 0;
+  
+  video {
+    max-height: 600px;
+    max-width: 100%;
+    border-radius: 4px;
+  }
+  
+  .loading-text {
+    font-size: 16px;
+    color: #909399;
+  }
+}
+
+// 最新生成结果样式
+.video-result-preview {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 10px;
+  background-color: #fafafa;
+  border-radius: 4px;
+  
+  .video-result-info {
+    flex: 1;
+    p {
+      margin: 5px 0;
+      font-size: 14px;
+    }
+  }
+  
+  .video-result-actions {
+    display: flex;
+    gap: 10px;
+  }
+}
+
+// 响应式调整
+@media screen and (max-width: 768px) {
+  .dialog-video-preview {
+    min-height: 300px;
+    
+    video {
+      max-height: 400px;
+    }
+  }
+  
+  .video-result-preview {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 15px;
+    
+    .video-result-actions {
+      width: 100%;
+      justify-content: flex-start;
+    }
+  }
+}
+</style>