浏览代码

新增设计智能体

lushixing 2 月之前
父节点
当前提交
79009c4fd8

二进制
src/assets/image/design-arrow.png


二进制
src/assets/image/design-image-index.jpg


二进制
src/assets/image/design-image1.jpg


二进制
src/assets/image/design-image2.jpg


二进制
src/assets/image/design-image3.jpg


二进制
src/assets/image/design-line-video.mp4


二进制
src/assets/image/design-line1.jpg


二进制
src/assets/image/design-line2.jpg


二进制
src/assets/image/design-line3.jpg


二进制
src/assets/image/design-line4.jpg


二进制
src/assets/image/design-text1.jpg


二进制
src/assets/image/design-text2.jpg


+ 17 - 1
src/permission.js

@@ -14,10 +14,22 @@ router.beforeEach(async (to, from, next) => {
   // start progress bar
   NProgress.start();
   // set page title
-  document.title = getPageTitle(to.meta.title);
+  // 动态获取 id
+  const id = to.params.id
+
+  // 根据 id 设置 title
+  if (to.name === 'imagetextToImage' && id) {
+    let title = id == 1 ? '创意生图' : (id == 2 ? '图生图' : '线稿生成')
+    to.meta.title = title
+    document.title = getPageTitle(title)
+  } else {
+    document.title = getPageTitle(to.meta.title)
+  }
   // determine whether the user has logged in
   const hasToken = getToken();
 
+  
+
   if (hasToken) {
     if (to.path === '/login') {
       // if is logged in, redirect to the home page
@@ -48,6 +60,10 @@ router.beforeEach(async (to, from, next) => {
             { routerPath: "/videoCoverManager" },
             { routerPath: "/videoCoverManager/videoCoverIndex" },
             { routerPath: "/videoCoverManager/faceSwapVideoIndex" },
+            { routerPath: "/designAgent" },
+            { routerPath: "/designAgent/designAgentIndex" },
+            { routerPath: "/designAgent/chatCreation" },
+            { routerPath: "/designAgent/imagetextToImage" },
             { routerPath: "/musicLibraryManager" },
             { routerPath: "/musicLibraryManager/musicCategoryIndex" },
             { routerPath: "/musicLibraryManager/musicLibrary" },

+ 2 - 0
src/router/index.js

@@ -36,6 +36,7 @@ export const constantRoutes = [
 // import userAuthRouter from "./modules/userAuth";
 import oralVideoRouter from "./modules/oralVideo";
 import videoCoverManagerRouter from "./modules/videoCoverManager";
+import designAgentManager from "./modules/designAgentManager";
 import musicLibraryManager from "./modules/musicLibraryManager";
 import catwalkVideoRouter from "./modules/catwalkVideo";
 import faceSwapVideoRouter from "./modules/faceSwapVideo";
@@ -45,6 +46,7 @@ export const asyncRoutes = [
   oralVideoRouter,
   catwalkVideoRouter,
   faceSwapVideoRouter,
+  designAgentManager,
   videoCoverManagerRouter,
   musicLibraryManager,
   AIAssetSearchRouter,

+ 0 - 1
src/router/modules/AIAssetSearch.js

@@ -6,7 +6,6 @@ const AIAssetSearchRouter = {
   path: "/AIAssetSearch",
   component: Layout,
   redirect: "/AIAssetSearch/AIAssetSearchIndex",
-  name: "AIAssetSearch",
   meta: { title: "AI素材搜索管理", icon: "el-icon-s-shop" },
   children: [
     {

+ 0 - 1
src/router/modules/catwalkVideo.js

@@ -6,7 +6,6 @@ const catwalkVideoRouter = {
   path: "/catwalkVideo",
   component: Layout,
   redirect: "/catwalkVideo/catwalkVideoIndex",
-  name: "catwalkVideo",
   meta: { title: "走秀视频管理", icon: "el-icon-camera-solid" },
   children: [
     {

+ 33 - 0
src/router/modules/designAgentManager.js

@@ -0,0 +1,33 @@
+/** When your routing table is too long, you can split it into small modules **/
+
+import Layout from "@/layout";
+
+const designAgentManagerRouter = {
+  path: "/designAgent",
+  component: Layout,
+  redirect: "/designAgentManager/designAgentIndex",
+  meta: { title: "设计智能体", icon: "el-icon-s-shop" },
+  children: [
+    {
+      path: "designAgentIndex",
+      component: () => import("@/views/design-agent/index"),
+      name: "designAgentIndex",
+      meta: { title: "设计智能体" }
+    },
+    {
+      path: "chatCreation",
+      component: () => import("@/views/design-agent/chatCreation"),
+      name: "chatCreation",
+      hidden: true,
+      meta: { title: "智能体对话" }
+    },
+    {
+      path: "imagetextToImage",
+      component: () => import("@/views/design-agent/feature-mod-index"),
+      name: "imagetextToImage",
+      hidden: true,
+      meta: { title: "" }
+    }
+  ]
+};
+export default designAgentManagerRouter;

+ 0 - 1
src/router/modules/faceSwapVideo.js

@@ -6,7 +6,6 @@ const faceSwapVideoRouter = {
   path: "/faceSwapVideo",
   component: Layout,
   redirect: "/face-swap-video/faceSwapVideoIndex",
-  name: "faceSwapVideo",
   meta: { title: "视频换脸管理", icon: "el-icon-s-cooperation" },
   children: [
     {

+ 0 - 1
src/router/modules/musicLibraryManager.js

@@ -6,7 +6,6 @@ const musicLibraryManagerRouter = {
   path: "/musicLibraryManager",
   component: Layout,
   redirect: "/musicLibraryManager/musicLibraryIndex",
-  name: "musicLibraryManager",
   meta: { title: "音乐库管理", icon: "el-icon-s-claim" },
   children: [
     {

+ 0 - 1
src/router/modules/oralVideo.js

@@ -6,7 +6,6 @@ const oralVideoRouter = {
   path: "/oralVideo",
   component: Layout,
   redirect: "/oralVideo/oralVideoIndex",
-  name: "oralVideo",
   meta: { title: "口播视频管理", icon: "el-icon-video-camera-solid" },
   children: [
     {

+ 0 - 1
src/router/modules/trendingTermList.js

@@ -6,7 +6,6 @@ const trendingTermListRouter = {
   path: "/trendingTermList",
   component: Layout,
   redirect: "/trendingTermList/trendingTermListIndex",
-  name: "trendingTermList",
   meta: { title: "热词管理", icon: "el-icon-s-shop" },
   children: [
     {

+ 0 - 1
src/router/modules/userAuth.js

@@ -6,7 +6,6 @@ const userAuthRouter = {
   path: "/auth",
   component: Layout,
   redirect: "/auth/user",
-  name: "permissions",
   meta: { title: "权限管理", icon: "el-icon-user-solid" },
   children: [
     {

+ 0 - 1
src/router/modules/videoCoverManager.js

@@ -6,7 +6,6 @@ const videoCoverManagerRouter = {
   path: "/videoCoverManager",
   component: Layout,
   redirect: "/videoCoverManager/videoCoverIndex",
-  name: "videoCoverManager",
   meta: { title: "店铺信息管理", icon: "el-icon-s-shop" },
   children: [
     {

+ 75 - 0
src/utils/index.js

@@ -1,4 +1,5 @@
 //解析日期
+import { getToken } from './auth'
 export function parseTime(time, cFormat) {
   if (arguments.length === 0) {
     return null
@@ -333,3 +334,77 @@ export function getValueByKey(key, options = [], valueKey = 'value', labelKey =
   const target = options.find(item => item[valueKey] === key);
   return target ? target[labelKey] : '';
 }
+
+export function genCidHex16() {
+  const arr = new Uint8Array(8); // 8 bytes -> 16 hex chars
+  crypto.getRandomValues(arr);
+  return Array.from(arr, b => b.toString(16).padStart(2, '0')).join('');
+}
+
+/**
+ * SSE 流式请求,自动处理 heartbeat 和 JSON
+ * @param {string} url - 请求地址
+ * @param {Object} payload - 请求体
+ * @param {Object} options
+ * @param {function} [options.onChunk] - 每次接收分片回调
+ * @param {string} [options.token] - Bearer token
+ * @returns {Promise<Object|string>} - 返回对象或拼接文本
+ */
+export async function fetchStreamText(url, payload = {}, options = {}) {
+  const { onChunk, token = getToken() || '' } = options
+
+  const res = await fetch(url, {
+    method: 'POST',
+    headers: {
+      'Content-Type': 'application/json',
+      ...(token ? { 'Authorization': `Bearer ${token}` } : {})
+    },
+    body: JSON.stringify(payload)
+  })
+
+  if (!res.ok) throw new Error(`请求失败: ${res.status}`)
+  if (!res.body) return await res.json() // 如果没有流,直接解析 JSON
+
+  const reader = res.body.getReader()
+  const decoder = new TextDecoder('utf-8')
+  let fullText = ''
+
+  while (true) {
+    const { done, value } = await reader.read()
+    if (done) break
+
+    const chunk = decoder.decode(value, { stream: true })
+    const lines = chunk.split('\n').map(l => l.trim()).filter(Boolean)
+
+    for (const line of lines) {
+      // if (!line.startsWith('data:')) continue
+
+      let dataStr = line.replace(/^data:\s*/, '')
+      if (dataStr === 'heartbeat' || dataStr === '[DONE]') continue
+
+      let text = dataStr
+      try {
+        if (dataStr.startsWith('{') || dataStr.startsWith('[')) {
+          const parsed = JSON.parse(dataStr)
+          text = parsed.text || parsed.content || dataStr
+          // 如果你想要对象形式,也可以直接返回 parsed
+        }
+      } catch (e) {
+        text = dataStr
+      }
+
+      fullText += text
+      if (onChunk) onChunk(text)
+    }
+  }
+
+  // 尝试解析完整 JSON,如果是完整 JSON 就返回对象
+  try {
+    return JSON.parse(fullText)
+  } catch (e) {
+    return fullText
+  }
+}
+
+
+

+ 31 - 0
src/views/design-agent/chatCreation.vue

@@ -0,0 +1,31 @@
+<template>
+  <div class="cut-video-container">
+    <iframe
+      ref="iframeRef"
+      :src="iframeUrl"
+      frameborder="0"
+      width="100%"
+      height="100%"
+      allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+      allowfullscreen
+    ></iframe>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      iframeUrl: 'https://aids.gloria.com.cn:8443/chat/Q2zXZ4uwp3yN4Tmn',
+    }
+  }
+};
+</script>
+
+<style scoped>
+.cut-video-container {
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+}
+</style>

+ 1203 - 0
src/views/design-agent/design-agent.scss

@@ -0,0 +1,1203 @@
+.acss-1mnncja {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  .ant-image {
+    position: relative;
+    width: 100%;
+    height: 100%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    img {
+      display: block;
+      width: 100%;
+      height: 100%;
+      object-fit: contain;
+    }
+  }
+}
+.arrow-icon {
+  display: inline-flex;
+  align-items: center;
+  color: inherit;
+  font-style: normal;
+  line-height: 0;
+  text-align: center;
+  text-transform: none;
+  vertical-align: -0.125em;
+  text-rendering: optimizeLegibility;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  animation-duration: 0.8s;
+  animation-timing-function: linear;
+  animation-iteration-count: infinite;
+  transform: scale(0.75);
+
+  &.arrow-first {
+    animation-name: colorChangeFirst;
+  }
+
+  &.arrow-second {
+    animation-name: colorChangeSecond;
+    margin-left: -15px !important;
+  }
+  
+
+  svg {
+    display: inline-block;
+  }
+}
+.design-agent-block {
+  height: 100%;
+  * {
+    margin: 0;
+    list-style: none;
+  }
+  .index-block {
+    padding: 24px;
+    width: 100%;
+
+    .index-hdeader-block {
+      margin-bottom: 24px;
+      h1 {
+        font-size: 30px;
+        line-height: 36px;
+        color: rgb(80, 60, 55);
+      }
+
+      p {
+        display: flex;
+        gap: 4px;
+        line-height: 24px;
+        font-size: 16px;
+        color: rgb(154, 120, 110);
+        align-items: center;
+        padding: 0;
+        margin: 0;
+        margin-top: 4px;
+
+        svg {
+          width: 16px;
+          height: 16px;
+          flex: 0 0 16px;
+        }
+      }
+    }
+    .flex-grow {
+      max-width: 95rem;
+      margin: 0 auto;
+    }
+    .flex-grow-top {
+      display: flex;
+      gap: 32px;
+      margin-bottom: 48px;
+
+      .dialog-compose-mode,
+      .tool-direct-mode {
+        border: 2px solid;
+        transition-duration: 300ms;
+        border-color: #E1D6D0;
+        background-color: rgba(154, 120, 110, 0.05);
+        border-radius: 8px;
+        padding: 3rem 24px;
+        flex: 1;
+
+        &:hover {
+          box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1);
+        }
+      }
+      .dialog-compose-mode {
+        cursor: pointer;
+      }
+      .flex-grow-top_icon {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        background: linear-gradient(135deg, rgb(194, 140, 110), rgb(154, 120, 110));
+        border-radius: 16px;
+        width: 64px;
+        height: 64px;
+        margin: 0 auto;
+        margin-bottom: 16px;
+
+        svg {
+          width: 32px;
+          height: 32px;
+          stroke: #fff;
+          stroke-width: 2px;
+        }
+      }
+      .flex-grow-top_title {
+        font-size: 24px;
+        line-height: 32px;
+        text-align: center;
+        margin-top: 6px;
+        color: rgb(80, 60, 55);
+        font-weight: bold;
+        margin-bottom: 16px;
+      }
+      .flex-grow-top_desc {
+        color: rgb(154, 120, 110);
+        text-align: center;
+        font-size: 16px;
+        line-height: 24px;
+        margin-bottom: 24px;
+      }
+      .dialog-btns {
+        display: flex;
+        justify-content: center;
+      }
+      .dialog-btns-a {
+        background: linear-gradient(135deg, rgb(194, 140, 110), rgb(154, 120, 110));
+        font-size: 14px;
+        line-height: 20px;
+        padding: 8px 16px;
+        border-radius: 6px;
+        color: #fff;
+
+        &:hover {
+          box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1);
+        }
+      }
+      .tool-direction {
+        font-size: 14px;
+        line-height: 20px;
+        color: rgb(154, 120, 110);
+        text-align: center;
+      }
+    }
+    .flex-grow-bottom {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      flex-direction: column;
+      gap: 24px;
+      .tool-direct__title {
+        font-size: 1.875rem;
+        color: rgb(51, 51, 51);
+
+        span {
+          background: linear-gradient(107deg, rgb(255, 72, 97) 1%, rgb(255, 72, 97) 1%, rgb(150, 59, 255) 99%) text;
+          -webkit-text-fill-color: transparent;
+        }
+      }
+      .feature-mod-content {
+        margin: 0px auto;
+        height: 26.6875rem;
+        width: 90rem;
+        display: flex;
+        -webkit-box-align: center;
+        align-items: center;
+        -webkit-box-pack: justify;
+        justify-content: space-between;
+        flex-direction: column;
+
+        .feature-mod-content-main {
+          height: 12.5rem;
+          width: 100%;
+          display: grid;
+          grid-template-columns: repeat(3, 1fr);
+          grid-template-rows: repeat(1, 1fr);
+          gap: 0.75rem;
+        }
+        .feature-mod-content-main-item-wrapper {
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          height: 100%;
+          overflow: hidden;
+          border-radius: 8px;
+          border: 1px solid rgba(153, 153, 153, 0.08);
+          box-sizing: border-box;
+          padding: 20px 24px 20px 28px;
+          position: relative;
+          cursor: pointer;
+          
+          &.theme-pink {
+            background: linear-gradient(116deg, rgb(255, 242, 244) 3%, rgb(248, 243, 255) 98%);
+            .feature-mod-content-main-item-left-title-arrow {
+              color: rgb(155, 62, 248);
+            }
+          }
+          &.theme-blue {
+            background: linear-gradient(116deg, rgb(240, 249, 252) 2%, rgb(238, 237, 255) 98%);
+            .feature-mod-content-main-item-left-title-arrow {
+              color: rgb(92, 131, 238);
+            }
+          }
+          &.theme-yellow {
+            background: linear-gradient(116deg, rgb(253, 250, 236) 2%, rgb(255, 238, 217) 98%);
+            .feature-mod-content-main-item-left-title-arrow {
+              color: rgb(238, 140, 9);
+            }
+          }
+          &::after {
+            background-image: url('https://img.alicdn.com/imgextra/i1/O1CN011NMFSk1SlUrKFlWpV_!!6000000002287-2-tps-1176-600.png');
+            content: "";
+            position: absolute;
+            left: 0px;
+            top: 0px;
+            width: 100%;
+            height: 100%;
+            background-size: contain;
+            background-repeat: no-repeat;
+            background-position: center center;
+          }
+
+          .feature-mod-content-main-item {
+            display: flex;
+            z-index: 1;
+            height: 100%;
+            width: 100%;
+
+            .feature-mod-content-main-item-left-arrow {
+              width: 69px;
+              height: 55px;
+              position: absolute;
+              right: -6px;
+              z-index: 11;
+              bottom: 0px;
+            }
+
+            &.left-imgs-count-1 .feature-mod-content-main-item-left-imgs {
+              margin-top: 23px;
+
+              .feature-mod-content-main-item-left-imgs-img {
+                margin-left: -1.5rem;
+                margin-top: -1.25rem;
+                height: 8rem;
+                width: 13.5625rem;
+              }
+            }
+            &.left-imgs-count-3 .feature-mod-content-main-item-left-imgs {
+              margin-top: 16px;
+              width: 172px;
+              height: 86px;
+              display: flex;
+              flex-direction: row-reverse;
+              transform: translateX(-4px);
+
+              .feature-mod-content-main-item-left-imgs-img {
+                z-index: 2;
+
+                &:nth-child(1) {
+                  transform: rotate(16deg) translate(-4px, 10px);
+                }
+                &:nth-child(2) {
+                  transform: rotate(0deg);
+                }
+                &:nth-child(3) {
+                  transform: rotate(-16deg) translate(4px, 10px);
+                }
+              }
+            }
+            &.left-imgs-count-4 .feature-mod-content-main-item-left-imgs {
+              margin-top: 18px;
+              width: 172px;
+              height: 86px;
+              display: flex;
+              flex-direction: row;
+              transform: translateX(-4px);
+
+              .feature-mod-content-main-item-left-imgs-img {
+                z-index: 2;
+                
+                img {
+                  width: 56px;
+                  height: 69px;
+                }
+
+                &:nth-child(1) {
+                  transform: rotate(-20.3deg) translate(8px, 8px);
+                }
+                &:nth-child(2) {
+                  transform: rotate(-4.7deg) translate(-4px, -4px);
+                }
+                &:nth-child(3) {
+                  transform: rotate(8.5deg) translate(-20px, -1px);
+                }
+                &:nth-child(4) {
+                  transform: rotate(23.5deg) translate(-38px, 22px);
+                }
+              }
+            }
+          }
+
+          .feature-mod-content-main-item-left {
+            display: flex;
+            flex-direction: column;
+            align-items: stretch;
+            height: 100%;
+            width: 244px;
+            position: relative;
+          }
+          .feature-mod-content-main-item-left-title {
+            font-size: 20px;
+            font-weight: 500;
+            line-height: 26px;
+            height: 26px;
+            letter-spacing: normal;
+            background: linear-gradient(105deg, rgb(255, 128, 145) 0%, rgb(150, 59, 255) 99%) text;
+            text-align: left;
+            width: fit-content;
+          }
+          .feature-mod-content-main-item-left-title-arrow {
+            font-weight: bold;
+            display: none;
+          }
+          .feature-mod-content-main-item-left-desc {
+            margin-top: 4px;
+            font-size: 16px;
+            font-weight: normal;
+            line-height: 24px;
+            letter-spacing: normal;
+            color: rgba(0, 0, 0, 0.35);
+          }
+          .feature-mod-content-main-item-left-imgs {
+
+            .feature-mod-content-main-item-left-imgs-img {
+              transition: transform 0.5s cubic-bezier(0.25, 0.1, 0.25, 1);
+            }
+          }
+          .feature-mod-content-main-item-right {
+            display: flex;
+            flex: 1 1 0%;
+            height: 100%;
+            justify-content: flex-end;
+
+            .feature-mod-content-main-item-right-video {
+              display: flex;
+              background-color: rgb(255, 255, 255);
+              border-radius: 8px;
+              overflow: hidden;
+              border: 2px solid rgb(255, 255, 255);
+              width: 117px !important;
+              height: 160px !important;
+
+              video {
+                object-fit: cover;
+              }
+              .video-event-mask {
+                position: absolute;
+                inset: 0px;
+                width: 100%;
+                height: 100%;
+                z-index: 2;
+              }
+            }
+
+            .feature-mod-content-main-item-right-imgs-img {
+              transition: transform 0.3s;
+              background-color: rgb(255, 255, 255);
+              border-radius: 8px;
+              overflow: hidden;
+              border: 2px solid rgb(255, 255, 255);
+
+              img {
+                object-fit: cover;
+              }
+
+              &:nth-child(2) {
+                right: 51px;
+                bottom: 42px;
+                z-index: 2;
+              }
+            }
+
+            .feature-mod-content-main-item-right-imgs.count-2 .feature-mod-content-main-item-right-imgs-img {
+              width: 100px;
+              height: 134px;
+              box-shadow: rgba(43, 20, 111, 0.02) 0px 0.25rem 1.25rem 0px;
+              position: absolute;
+
+              &:nth-child(1) {
+                right: 24px;
+                bottom: 24px;
+              }
+              &:nth-child(2) {
+                right: 51px;
+                bottom: 42px;
+                z-index: 2;
+              }
+            }
+            .feature-mod-content-main-item-right-imgs.count-1 .feature-mod-content-main-item-right-imgs-img {
+              width: 124px;
+              height: 160px;
+              box-shadow: rgba(43, 20, 111, 0.05) 0px 4px 20px 0px;
+            }
+          }
+        }
+        .feature-mod-content-main-item-wrapper:hover {
+          .feature-mod-content-main-item-left-title-arrow {
+            display: inline-block;
+          }
+          .feature-mod-content-main-item.left-imgs-count-1 .feature-mod-content-main-item-left-imgs {
+            transform: translateY(-3px);
+          }
+          .feature-mod-content-main-item.left-imgs-count-3 .feature-mod-content-main-item-left-imgs-img {
+            &:nth-child(3) {
+              transform: rotate(-24deg) translate(2px, 10px);
+            }
+            &:nth-child(1) {
+              transform: rotate(24deg) translate(-2px, 10px);
+            }
+          }
+          .feature-mod-content-main-item.left-imgs-count-4 .feature-mod-content-main-item-left-imgs-img {
+            &:nth-child(1) {
+              transform: rotate(-26deg) translate(4px, 16px);
+            }
+            &:nth-child(2) {
+              transform: rotate(-7deg) translate(-5px, -2px);
+            }
+            &:nth-child(3) {
+              transform: rotate(11deg) translate(-18px, 2px);
+            }
+            &:nth-child(4) {
+              transform: rotate(26deg) translate(-30px, 28px);
+            }
+          }
+          .feature-mod-content-main-item-right-imgs.count-2 .feature-mod-content-main-item-right-imgs-img:nth-child(1) {
+            transform: rotate(4deg) translate(6px, 0px);
+          }
+          .feature-mod-content-main-item-right-imgs.count-2 .feature-mod-content-main-item-right-imgs-img:nth-child(2) {
+            transform: rotate(-5.8deg) translate(4px, 3px);
+          }
+          .feature-mod-content-main-item-right-imgs.count-1 .feature-mod-content-main-item-right-imgs-img:nth-child(1) {
+            transform: rotate(5deg) translate(4px, 0px);
+          }
+        }
+        .feature-mod-content-sub {
+          height: 12.5rem;
+          width: 100%;
+          display: grid;
+          grid-template-columns: repeat(3, 1fr);
+          grid-template-rows: repeat(1, 1fr);
+          gap: 0.75rem;
+
+          .feature-mod-content-sub-item-wrapper {
+            position: relative;
+
+            &:hover .feature-mod-content-sub-item {
+              transform: translateY(-3px);
+              box-shadow: rgba(0, 0, 0, 0.04) 0px 2px 20px 0px;
+
+              .feature-mod-content-sub-item-right-title-arrow {
+                display: inline-block;
+              }
+            }
+
+            .feature-mod-content-sub-item {
+              width: 100%;
+              height: 100%;
+              border-radius: 8px;
+              background: rgb(255, 255, 255);
+              box-sizing: border-box;
+              border: 1px solid rgb(237, 237, 237);
+              display: flex;
+              align-items: center;
+              padding: 1.5rem;
+              gap: 0.75rem;
+              transition: transform 0.3s;
+              cursor: pointer;
+            }
+            .feature-mod-content-sub-item-left {
+              display: flex;
+            }
+            .feature-mod-content-sub-item-right {
+              display: flex;
+              flex-direction: column;
+              align-items: stretch;
+              gap: 4px;
+            }
+            .feature-mod-content-sub-item-right-title {
+              font-size: 18px;
+              font-weight: 500;
+              line-height: 1.5rem;
+              height: 1.5rem;
+              color: rgb(51, 51, 51);
+            }
+            .feature-mod-content-sub-item-right-title-arrow {
+              font-weight: bold;
+              display: none;
+            }
+            .feature-mod-content-sub-item-right-desc {
+              font-size: 16px;
+              line-height: 1.5rem;
+              height: 1.5rem;
+              letter-spacing: normal;
+              color: rgb(153, 153, 153);
+            }
+          }
+        }
+      }
+    }
+  }
+  .tool-direct-black {
+    display: flex;
+    flex-direction: column;
+    padding: 24px;
+    width: 100%;
+    height: 100%;
+    &.chat-pages {
+      height: 100%;
+    }
+  }
+  .tools-header-block {
+    display: flex;
+    gap: 16px;
+    align-items: center;
+    margin-bottom: 24px;
+
+    .back {
+      width: 40px;
+      height: 40px;
+      background-color: white;
+      color: rgb(80, 60, 55);
+      box-shadow: rgba(154, 120, 110, 0.2) 0px 1px 3px;
+      border-radius: 6px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      cursor: pointer;
+
+      svg {
+        width: 16px;
+        height: 16px;
+      }
+    }
+  }
+  .header-block {
+    h1 {
+      font-size: 24px;
+      line-height: 30px;
+      color: rgb(80, 60, 55);
+      display: flex;
+      align-items: center;
+      gap: 10px;
+
+      svg {
+        width: 20px;
+        height: 20px;
+        color: rgb(154, 120, 110);
+      }
+    }
+
+    p {
+      display: flex;
+      gap: 4px;
+      line-height: 20px;
+      font-size: 14px;
+      color: rgb(154, 120, 110);
+      align-items: center;
+      padding: 0;
+      margin: 0;
+      margin-top: 4px;
+
+      svg {
+        width: 16px;
+        height: 16px;
+        flex: 0 0 16px;
+      }
+    }
+  }
+  .tool-direct-content-black {
+    flex: 1 1 0%;
+    height: calc(100% - 78px);
+
+    .tools-block {
+      height: 100%;
+    }
+
+    .chat-block {
+      width: 100%;
+      height: 100%;
+
+      iframe {
+        width: 100%;
+        height: 100%;
+      }
+    }
+  }
+  .tool-direct-content {
+    width: 100%;
+    height: 100%;
+    max-width: 100%;
+    margin: 0 auto;
+    display: flex;
+    gap: 24px;
+    flex: 1 1 0%;
+    flex-direction: row-reverse;
+
+    .tool-direct-left,
+    .tool-direct-right {
+      border: 1px solid #ae8878;
+      box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1);
+      background: rgba(255,255,255,0.8);
+      border-radius: 8px;
+      min-height: 282px;
+    }
+    .tool-direct-left {
+      position: relative;
+      display: flex;
+      flex-direction: column;
+      width: 500px;
+      flex: 0 0 500px;
+      .demo-ruleForm {
+        height: 100%;
+        padding-bottom: 120px;
+
+        .ruleFormContent {
+          overflow: hidden;
+          height: 100%;
+
+          /deep/ .el-scrollbar {
+            height: 100%;
+
+            .el-scrollbar__wrap {
+              padding: 24px;
+              overflow-x: hidden;
+            }
+          }
+        }
+      }
+      .tool-direct-left__title {
+        display: flex;
+        gap: 12px;
+        align-items: center;
+
+        h3 {
+          font-size: 24px;
+          line-height: 1;
+          color: rgb(80, 60, 55);
+        }
+
+        svg {
+          width: 20px;
+          height: 20px;
+          color: rgb(154, 120, 110);
+        }
+      }
+      .tool-direct-left__desc {
+        font-size: 14px;
+        color: rgb(154, 120, 110);
+        margin-top: 8px;
+      }
+      .tools-upload-black {
+        margin-top: 24px;
+        .tools-upload__title {
+          font-size: 14px;
+          line-height: 20px;
+          margin-bottom: 5px;
+        }
+      }
+      /deep/ .el-form-item + .el-form-item {
+        margin-top: 30px;
+      }
+      /deep/ .el-form-item__label {
+        line-height: 20px;
+
+        &::before {
+          display: none;
+        }
+      }
+      .tools-upload {
+        display: flex;
+        width: 100%;
+        height: 100%;
+        .img-group {
+          width: 100%;
+        }
+        /deep/ .el-carousel__indicators {
+          display: none;
+        }
+        .custom-file-list {
+          display: flex;
+          gap: 10px;
+          width: 100%;
+        }
+        .custom-file__btns {
+          position: absolute;
+          top: 0;
+          left: 0;
+          z-index: 10;
+          width: 100%;
+          height: 100%;
+          background: rgba(0, 0, 0, 0.5);
+          border-radius: 6px;
+          display: none;
+          flex-direction: column;
+          align-items: center;
+          justify-content: center;
+          gap: 10px;
+          transition: all .5s;
+        }
+        .picture-card-wrapper {
+          position: relative;
+          width: calc(50% - 5px);
+
+          &:hover .custom-file__btns{
+            display: flex;
+          }
+        }
+        /deep/ .el-carousel__arrow--left {
+          left: 0;
+        }
+        /deep/ .el-carousel__arrow--right {
+          right: 0;
+        }
+        .picture-card-image {
+          width: 100%;
+          object-fit: cover;
+          display: block;
+          border: 1px solid #ddd;
+          border-radius: 6px;
+          cursor: pointer;
+          aspect-ratio: 1/1;
+        }
+        .replace-btn {
+          font-size: 14px;
+          padding: 6px 20px;
+          background: rgba(0, 0, 0, 0.8);
+          border-color: rgba(0, 0, 0, 0.8);
+          color: #fff;
+
+          /deep/ span {
+            display: flex;
+            align-items: center;
+            gap: 6px;
+          }
+
+          svg {
+            width: 18px;
+            height: 18px;
+          }
+
+          &:hover {
+            background: #ae8878;
+            border-color: #ae8878;
+          }
+        }
+        .upload-demo {
+          width: 100%;
+
+          &.upload-demo__data {
+            width: 100px;
+            height: 100px;
+            flex: 0 0 100px;
+            margin-left: 10px;
+
+            /deep/ .el-upload {
+
+              .el-upload-dragger {
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                height: 100%;
+              }
+              .el-icon-plus {
+                font-size: 28px;
+              }
+            }
+          }
+        }
+        /deep/ .el-upload {
+          width: 100%;
+          height: 100%;
+
+          .el-upload-dragger {
+            width: 100%;
+            height: 240px;
+            border: 1px solid #ae8878;
+
+            .el-upload__info {
+              height: 100%;
+              padding: 20px 0;
+              .el-icon-upload {
+                color: #ae8877;
+                margin-top: 30px;
+              }
+              .el-upload__text,.el-upload__tip {
+                color: #ae8877;
+              }
+            }
+          }
+        }
+      }
+      .avatar-black {
+        position: relative;
+        width: 100%;
+        height: 240px;
+        margin: 0 auto;
+
+        img {
+          display: block;
+          object-fit: cover;
+          width: 100%;
+          height: 100%;
+          max-width: 50%;
+          margin: 0 auto;
+        }
+        .custom-file__btns {
+          position: absolute;
+          top: 0;
+          left: 0;
+          z-index: 10;
+          width: 100%;
+          height: 100%;
+          background: rgba(0, 0, 0, 0.5);
+          border-radius: 6px;
+          display: none;
+          flex-direction: column;
+          align-items: center;
+          justify-content: center;
+          gap: 10px;
+          transition: all .5s;
+
+          .replace-btn {
+            font-size: 14px;
+            padding: 6px 20px;
+            background: rgba(0, 0, 0, 0.8);
+            border-color: rgba(0, 0, 0, 0.8);
+            color: #fff;
+
+            /deep/ span {
+              display: flex;
+              align-items: center;
+              gap: 6px;
+            }
+
+            svg {
+              width: 18px;
+              height: 18px;
+            }
+
+            &:hover {
+              background: #ae8878;
+              border-color: #ae8878;
+            }
+          }
+        }
+        &:hover .custom-file__btns{
+          display: flex;
+        }
+      }
+      .tool-direct-left__submit {
+        position: relative;
+        /deep/ .el-form-item__label {
+          display: flex;
+        }
+        /deep/ .el-textarea__inner {
+          color: #ae8878;
+          border-color: #ae8878;
+        }
+        .clear-block {
+          position: absolute;
+          bottom: 11px;
+          right: 65px;
+          color: #ae8878;
+          padding: 5px;
+          cursor: pointer;
+          line-height: normal;
+        }
+      }
+      .label-title {
+        color: #ae8878;
+        display: flex;
+        align-items: center;
+        gap: 6px;
+
+        span {
+          display: flex;
+          align-items: center;
+          gap: 6px;
+          font-size: 16px;
+
+          .no {
+            display: block;
+            width: 18px;
+            height: 18px;
+            line-height: 16px;
+            text-align: center;
+            font-size: 12px;
+            border-radius: 50%;
+            border: 1px solid #ae8878;
+            color: #ae8878;
+            font-style: normal;
+          }
+        }
+      }
+      .tool-direct-left__imageRatio {
+        /deep/ .el-radio-group {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 20px;
+
+          .el-radio {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            width: 74px;
+            height: 36px;
+            background: #ae8878;
+            border: 1px solid #ae8878;
+            border-radius: 8px;
+            transition: all .5s;
+            &.is-checked {
+              background: #232323;;
+              border-color: #232323;
+            }
+            &:hover {
+              background:#bea092;
+              border-color: #bea092;
+            }
+          }
+          .el-radio__input {
+            width: 18px;
+            height: 12px;
+            border: 1px solid #fff;
+            border-radius: 2px;
+          }
+          .el-radio:nth-child(2) .el-radio__input {
+            width: 22px;
+          }
+          .el-radio:nth-child(3) .el-radio__input {
+            width: 14px;
+            height: 14px;
+          }
+          .el-radio:nth-child(4) .el-radio__input {
+            width: 12px;
+            height: 18px;
+          }
+          .el-radio:nth-child(5) .el-radio__input {
+            width: 12px;
+            height: 22px;
+          }
+          .el-radio__inner {
+            opacity: 0;
+          }
+          .el-radio__label {
+            color: #fff;
+            padding-left: 4px;
+          }
+        }
+      }
+      .image-ratio__custom {
+        display: flex;
+        align-items: center;
+        gap: 10px;
+        margin-top: 5px;
+        label {
+          white-space: nowrap;
+          color: #606266;
+        }
+      }
+      .tool-direct-left__imageSize {
+        display: flex;
+        align-items: center;
+        gap: 10px;
+      }
+      .el-form-item__btns {
+        position: absolute;
+        bottom: 0;
+        left: 0;
+        width: 100%;
+        padding: 2rem;
+        margin-top: 0;
+        box-shadow: 0 -4px 20px rgba(174, 136, 120, 0.2);
+      }
+      .tool-direct-left__btns {
+        width: 100%;
+        display: flex;
+        align-items: center;
+        gap: 12px;
+        justify-content: center;
+        font-size: 14px;
+        color: #fff;
+        min-height: 40px;
+        gap: 20px;
+
+        .clear {
+          width: 200px;
+
+          /deep/ .el-button {
+            width: 100%;
+            color: #1f1f1f;
+            background: #eee;
+            border-color: #eee;
+          }
+        }
+
+        .save {
+          width: 200px;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          border-radius: 4px;
+          cursor: pointer;
+          background: linear-gradient(135deg, rgb(194, 140, 110), rgb(154, 120, 110));
+          &:hover {
+            background: linear-gradient(135deg, rgb(194, 140, 110), rgb(154, 120, 110));
+            box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1);
+          }
+
+          /deep/ span {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            gap: 6px;
+          }
+          svg {
+            width: 16px;
+            height: 16px;
+            color: #fff;
+          }
+        }
+      }
+    }
+    .tool-direct-right {
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+      .tool-direct-right__title {
+        margin-bottom: 24px;
+        h3 {
+          font-size: 24px;
+          line-height: 1;
+          color: rgb(80, 60, 55);
+        }
+      }
+      .tool-direct-right__result {
+        height: 100%;
+        flex: 1 1 0%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+
+        .result-success,.preview-black__images,.images-preview {
+          height: 100%;
+        }
+      }
+      .result-empty {
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        color: #999;
+        font-size: 16px;
+        gap: 16px;
+        display: flex;
+        text-align: center;
+        line-height: 22px;
+        svg {
+          width: 64px;
+          height: 64px;
+          color: rgba(154, 120, 110, 0.5);
+        }
+      }
+      .tool-direct-right__loading {
+        font-size: 14px;
+        gap: 16px;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        color: rgb(154, 120, 110);
+        display: flex;
+
+        svg {
+          width: 48px;
+          height: 48px;
+          animation: spin 1s linear infinite;
+        }
+      }
+      .preview-black__images {
+        position: relative;
+        background: rgba(241,245,249,1);
+        border-radius: 8px;
+        overflow: hidden;
+
+        img {
+          display: block;
+          max-width: 100%;
+          max-height: 100%;
+          object-fit: cover;
+        }
+
+        .images-preview__search {
+          position: absolute;
+          top: 10px;
+          right: 10px;
+          width: 40px;
+          height: 40px;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1);
+          background: rgba(255,255,255,0.9);
+          border: 1px solid hsl(240,5.9%,90%);
+          border-radius: 6px;
+          cursor: pointer;
+          cursor: pointer;
+          /deep/ .el-image {
+            width: 100%;
+            height: 100%;
+            position: absolute;
+            top: 0;
+            left: 0;
+            z-index: 10;
+
+            .el-image__preview {
+              opacity: 0;
+            }
+          }
+          svg {
+            width: 20px;
+            height: 20px;
+          }
+        }
+
+        .images-preview__icon {
+          position: absolute;
+          bottom: 20px;
+          right: 20px;
+          gap: 8px;
+          display: none;
+          animation-duration: 300ms;
+
+          .icons {
+            width: 40px;
+            height: 40px;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1);
+            background: rgba(255,255,255,0.9);
+            border: 1px solid hsl(240,5.9%,90%);
+            border-radius: 6px;
+            cursor: pointer;
+
+            svg {
+              width: 16px;
+              height: 16px;
+            }
+          }
+        }
+
+        &:hover {
+          .images-preview__icon {
+            display: flex;
+          }
+        }
+      }
+    }
+  }
+}
+@keyframes spin{to{transform:rotate(360deg)}}
+@keyframes colorChangeFirst {
+  0%, 100% {opacity: 1;}
+  50% {opacity: 0.4;}
+}
+@keyframes colorChangeSecond {
+  0%, 100% {opacity: 0.4;}
+  50% {opacity: 1;}
+}

+ 701 - 0
src/views/design-agent/feature-mod-index.vue

@@ -0,0 +1,701 @@
+<template>
+  <div class="design-agent-block">
+    <symbol id="icon-aiyoujiantou" viewBox="0 0 1024 1024"><path d="M350.165333 97.834667a42.666667 42.666667 0 0 0-60.330666 60.330666L643.626667 512 289.834667 865.834667a42.666667 42.666667 0 0 0-2.496 57.621333l2.496 2.709333a42.666667 42.666667 0 0 0 60.330666 0l384-384a42.666667 42.666667 0 0 0 0-60.330666l-384-384z"></path></symbol>
+    <div class="tool-direct-black">
+      <div class="tools-header-block">
+        <header class="header-block">
+          <h1>
+            <svg
+                xmlns="http://www.w3.org/2000/svg"
+                width="24"
+                height="24"
+                viewBox="0 0 24 24"
+                fill="none"
+                stroke="currentColor"
+                stroke-width="2"
+                stroke-linecap="round"
+                stroke-linejoin="round"
+              ><path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z" /><path d="M20 3v4" /><path d="M22 5h-4" /><path d="M4 17v2" /><path d="M5 18H3" /></svg>
+            {{ pagesData.title }}
+          </h1>
+          <p>
+            {{ pagesData.desc }}
+          </p>
+        </header>
+      </div>
+      <div class="tool-direct-content-black">
+        <!-- <div class="chat-block" v-if="pages == 'chat'">
+          <iframe src="https://aids.gloria.com.cn:8443/chat/Q2zXZ4uwp3yN4Tmn" frameborder="0"></iframe>
+        </div> -->
+        <div class="tools-block">
+          <div class="tool-direct-content">
+          <div class="tool-direct-left">
+            <!-- <div class="tool-direct-left__title">
+              <svg
+                xmlns="http://www.w3.org/2000/svg"
+                width="24"
+                height="24"
+                viewBox="0 0 24 24"
+                fill="none"
+                stroke="currentColor"
+                stroke-width="2"
+                stroke-linecap="round"
+                stroke-linejoin="round"
+              ><path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z" /><path d="M20 3v4" /><path d="M22 5h-4" /><path d="M4 17v2" /><path d="M5 18H3" /></svg>
+              <h3>{{ pagesData.title }}</h3>
+            </div>
+            <div class="tool-direct-left__desc">{{ pagesData.desc }}</div> -->
+            <el-form :model="ruleForm" :rules="rules" ref="ruleForm" class="demo-ruleForm" label-position="top">
+              <div class="ruleFormContent">
+                <el-scrollbar>
+                  <el-form-item prop="imageList" required v-if="pagesData.applicationId == 2">
+                    <template #label>
+                      <div class="label-title">
+                        <span><em class="no">1</em> 上传图片</span>
+                      </div>
+                    </template>
+                    <div class="tools-upload">
+                      <!-- 自定义显示每个图片的重新上传按钮 -->
+                      <el-carousel :interval="3000" style="width: 340px;" height="165px" :autoplay="false" v-if="ruleForm.imageList.length">
+                        <el-carousel-item v-for="(group, index) in groupedImages" :key="index">
+                          <div class="img-group">
+                            <div class="custom-file-list" >
+                              <div v-for="(img, i) in group" :key="i" class="picture-card-wrapper">
+                                <img :src="img" class="picture-card-image" />
+                                <div class="custom-file__btns">
+                                  <el-button 
+                                    class="replace-btn" 
+                                    @click="replaceFile(index, i)">
+                                    <svg t="1760412251487" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6466" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M902.314667 206.741333a21.333333 21.333333 0 0 1 0 30.122667l-46.933334 47.146667-122.581333 123.178666a21.333333 21.333333 0 0 1-30.229333 0l-31.829334-31.957333a21.333333 21.333333 0 0 1 0-30.122667l42.666667-42.816c13.376-13.44 3.84-36.394667-15.146667-36.394666H375.189333c-46.933333 0-91.157333 18.389333-124.373333 51.733333a175.914667 175.914667 0 0 0-51.52 124.885333v91.712a21.333333 21.333333 0 0 1-21.333333 21.333334H132.970667a21.333333 21.333333 0 0 1-21.333334-21.333334v-91.818666c0-146.090667 118.037333-264.618667 263.530667-264.618667h323.008c18.986667 0 28.522667-22.933333 15.125333-36.373333l-42.666666-42.837334a21.333333 21.333333 0 0 1 0-30.101333l31.829333-31.978667a21.333333 21.333333 0 0 1 30.250667 0l122.581333 123.093334 47.018667 47.146666z m-97.941334 353.706667c0 47.146667-18.325333 91.52-51.541333 124.885333a174.464 174.464 0 0 1-124.373333 51.733334H325.653333c-18.986667 0-28.522667-22.954667-15.125333-36.394667l42.752-42.922667a21.333333 21.333333 0 0 0 0-30.122666l-31.829333-31.957334a21.333333 21.333333 0 0 0-30.229334 0l-122.602666 123.008-46.933334 47.146667a21.333333 21.333333 0 0 0 0 30.08l46.933334 47.146667 122.602666 123.093333a21.333333 21.333333 0 0 0 30.229334 0l31.829333-31.957333a21.333333 21.333333 0 0 0 0-30.101334l-42.453333-42.624c-13.397333-13.44-3.861333-36.394667 15.104-36.394666H628.48c145.493333 0 263.530667-118.528 263.530667-264.618667v-90.538667a21.333333 21.333333 0 0 0-21.333334-21.333333h-44.970666a21.333333 21.333333 0 0 0-21.333334 21.333333v90.538667z" p-id="6467" fill="#ffffff"></path></svg>
+                                    重新上传
+                                  </el-button>
+                                  <el-button 
+                                    class="replace-btn" 
+                                    @click="imgUploadDel(index, i)">
+                                    <svg t="1760412304801" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7509" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M853.333333 256H170.666667V853.333333a85.333333 85.333333 0 0 0 85.333333 85.333334h512A85.333333 85.333333 0 0 0 853.333333 853.333333V256zM85.333333 170.666667h170.666667V85.333333A85.333333 85.333333 0 0 1 341.333333 0h341.333334a85.333333 85.333333 0 0 1 85.333333 85.333333V170.666667h213.333333a42.666667 42.666667 0 0 1 0 85.333333H938.666667V853.333333a170.666667 170.666667 0 0 1-170.666667 170.666667h-512a170.666667 170.666667 0 0 1-170.666667-170.666667V256H42.666667a42.666667 42.666667 0 1 1 0-85.333333H85.333333zM341.333333 170.666667h341.333334V85.333333H341.333333V170.666667z m42.666667 256c23.552 0 42.666667 19.114667 42.666667 42.666666v256a42.666667 42.666667 0 0 1-85.333334 0v-256c0-23.552 19.114667-42.666667 42.666667-42.666666z m256 0c23.552 0 42.666667 19.114667 42.666667 42.666666v256a42.666667 42.666667 0 0 1-85.333334 0v-256c0-23.552 19.114667-42.666667 42.666667-42.666666z" fill="#ffffff" p-id="7510"></path></svg>
+                                    删除图片
+                                  </el-button>
+                                </div>
+                              </div>
+                            </div>
+                          </div>
+                        </el-carousel-item>
+                      </el-carousel>
+                      <el-upload
+                        ref="uploadRef"
+                        class="upload-demo"
+                        :class="{'upload-demo__data': ruleForm.imageList.length}"
+                        drag
+                        :action="action"
+                        :show-file-list="false" 
+                        :headers="{
+                          'Authorization': 'Bearer ' + token
+                        }"
+                        multiple
+                        :on-success="handleVideoSuccess" 
+                        :before-upload="beforeUploadVideo"
+                      >
+                        <div v-loading="uploading">
+                          <i class="el-icon-plus" v-if="ruleForm.imageList.length"></i>
+                          <div class="el-upload__info" v-else>
+                            <i class="el-icon-upload"></i>
+                            <div class="el-upload__text">点击或将图片拖拽到这里上传</div>
+                            <div class="el-upload__tip" slot="tip">(图片要求:支持JPG和PNG,最大为20M)</div>
+                          </div>
+                        </div>
+                      </el-upload>
+                    </div>
+                  </el-form-item>
+                  <el-form-item prop="imageUrl" required v-if="pagesData.applicationId == 3">
+                    <template #label>
+                      <div class="label-title">
+                        <span><em class="no">1</em> 上传图片</span>
+                      </div>
+                    </template>
+                    <div class="tools-upload">
+                      <el-upload
+                        class="upload-demo"
+                        drag
+                        :action="action" 
+                        :show-file-list="false" 
+                        :headers="{
+                          'Authorization': 'Bearer ' + token
+                        }"
+                        multiple 
+                        :on-success="handleVideoSuccess" 
+                        :before-upload="beforeUploadVideo">
+                        <div v-loading="uploading">
+                          <div v-if="ruleForm.imageUrl" class="avatar-black">
+                            <img :src="ruleForm.imageUrl" class="avatar">
+                            <div class="custom-file__btns">
+                              <el-button 
+                                class="replace-btn" 
+                                @click="replaceFile(index, i)">
+                                <svg t="1760412251487" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6466" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M902.314667 206.741333a21.333333 21.333333 0 0 1 0 30.122667l-46.933334 47.146667-122.581333 123.178666a21.333333 21.333333 0 0 1-30.229333 0l-31.829334-31.957333a21.333333 21.333333 0 0 1 0-30.122667l42.666667-42.816c13.376-13.44 3.84-36.394667-15.146667-36.394666H375.189333c-46.933333 0-91.157333 18.389333-124.373333 51.733333a175.914667 175.914667 0 0 0-51.52 124.885333v91.712a21.333333 21.333333 0 0 1-21.333333 21.333334H132.970667a21.333333 21.333333 0 0 1-21.333334-21.333334v-91.818666c0-146.090667 118.037333-264.618667 263.530667-264.618667h323.008c18.986667 0 28.522667-22.933333 15.125333-36.373333l-42.666666-42.837334a21.333333 21.333333 0 0 1 0-30.101333l31.829333-31.978667a21.333333 21.333333 0 0 1 30.250667 0l122.581333 123.093334 47.018667 47.146666z m-97.941334 353.706667c0 47.146667-18.325333 91.52-51.541333 124.885333a174.464 174.464 0 0 1-124.373333 51.733334H325.653333c-18.986667 0-28.522667-22.954667-15.125333-36.394667l42.752-42.922667a21.333333 21.333333 0 0 0 0-30.122666l-31.829333-31.957334a21.333333 21.333333 0 0 0-30.229334 0l-122.602666 123.008-46.933334 47.146667a21.333333 21.333333 0 0 0 0 30.08l46.933334 47.146667 122.602666 123.093333a21.333333 21.333333 0 0 0 30.229334 0l31.829333-31.957333a21.333333 21.333333 0 0 0 0-30.101334l-42.453333-42.624c-13.397333-13.44-3.861333-36.394667 15.104-36.394666H628.48c145.493333 0 263.530667-118.528 263.530667-264.618667v-90.538667a21.333333 21.333333 0 0 0-21.333334-21.333333h-44.970666a21.333333 21.333333 0 0 0-21.333334 21.333333v90.538667z" p-id="6467" fill="#ffffff"></path></svg>
+                                重新上传
+                              </el-button>
+                              <el-button 
+                                class="replace-btn" 
+                                @click.stop="imgUploadDel(index, i)">
+                                <svg t="1760412304801" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7509" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M853.333333 256H170.666667V853.333333a85.333333 85.333333 0 0 0 85.333333 85.333334h512A85.333333 85.333333 0 0 0 853.333333 853.333333V256zM85.333333 170.666667h170.666667V85.333333A85.333333 85.333333 0 0 1 341.333333 0h341.333334a85.333333 85.333333 0 0 1 85.333333 85.333333V170.666667h213.333333a42.666667 42.666667 0 0 1 0 85.333333H938.666667V853.333333a170.666667 170.666667 0 0 1-170.666667 170.666667h-512a170.666667 170.666667 0 0 1-170.666667-170.666667V256H42.666667a42.666667 42.666667 0 1 1 0-85.333333H85.333333zM341.333333 170.666667h341.333334V85.333333H341.333333V170.666667z m42.666667 256c23.552 0 42.666667 19.114667 42.666667 42.666666v256a42.666667 42.666667 0 0 1-85.333334 0v-256c0-23.552 19.114667-42.666667 42.666667-42.666666z m256 0c23.552 0 42.666667 19.114667 42.666667 42.666666v256a42.666667 42.666667 0 0 1-85.333334 0v-256c0-23.552 19.114667-42.666667 42.666667-42.666666z" fill="#ffffff" p-id="7510"></path></svg>
+                                删除图片
+                              </el-button>
+                            </div>
+                          </div>
+                          <div class="el-upload__info" v-else>
+                            <i class="el-icon-upload"></i>
+                            <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+                            <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过20M</div>
+                          </div>
+                        </div>
+                      </el-upload>
+                    </div>
+                  </el-form-item>
+                  <el-form-item prop="screenDescription" class="tool-direct-left__submit">
+                    <template #label>
+                      <div class="label-title">
+                        <span>
+                          <em class="no">{{pagesData.applicationId == 1 ? '1' : '2'}}</em> 画面描述{{ pagesData.applicationId == 3 ? '(选填)' : '' }}
+                        </span>
+                        <el-tooltip 
+                          class="item" 
+                          effect="dark" 
+                          content="请详细描述您想要的服装款式、风格、颜色、材质等" 
+                          placement="top"
+                        >
+                          <i class="el-icon-info" style="color: #ccc;cursor: pointer;" />
+                        </el-tooltip>
+                      </div>
+                    </template>
+                    <el-input
+                      type="textarea"
+                      :rows="5"
+                      placeholder="例如:一件适合夏季穿着的波西米亚风格长裙,采用丝绸面料,以佩斯利和花纹为主,土色调为橙色和蓝色.."
+                      :maxlength="1000"
+                      show-word-limit
+                      v-model="ruleForm.screenDescription">
+                    </el-input>
+                    <span class="clear-block" v-if="ruleForm.screenDescription"  @click.stop="clearDescription()">清除</span>
+                  </el-form-item>
+                  <template v-if="pagesData.applicationId == 2">
+                    <el-form-item>
+                      <template #label>
+                        <div class="label-title">
+                          <span><em class="no">3</em> 图片比例(选填)</span>
+                        </div>
+                      </template>
+                      <div class="tool-direct-left__imageRatio">
+                        <div class="image-ratio__block">
+                          <el-radio-group v-model="ruleForm.imageRatioList">
+                            <el-radio label="3:2"></el-radio>
+                            <el-radio label="16:9"></el-radio>
+                            <el-radio label="1:1"></el-radio>
+                            <el-radio label="2:3"></el-radio>
+                            <el-radio label="9:16"></el-radio>
+                          </el-radio-group>
+                        </div>
+                      </div>
+                    </el-form-item>
+                    <el-form-item>
+                      <template #label>
+                        <div class="label-title">
+                          <span><em class="no">4</em> 图片尺寸(选填)</span>
+                        </div>
+                      </template>
+                      <div class="tool-direct-left__imageSize">
+                        <el-select v-model="ruleForm.imageSizeSelect" placeholder="请选择" size="small">
+                          <el-option
+                            v-for="item in imageSizes"
+                            :key="item.value"
+                            :label="item.label"
+                            :value="item.value">
+                          </el-option>
+                        </el-select>
+                        <el-button type="primary" size="small" @click="handleCustom">自定义</el-button>
+                      </div>
+                      <div class="image-ratio__custom" v-if="hasCustom">
+                        <el-input-number :controls="false" v-model="ruleForm.imageSize.width" size="small"></el-input-number>
+                        X
+                        <el-input-number :controls="false" v-model="ruleForm.imageSize.height" size="small"></el-input-number>
+                      </div>
+                    </el-form-item>
+                  </template>
+                </el-scrollbar>
+              </div>
+              <el-form-item class="el-form-item__btns">
+                <div class="tool-direct-left__btns">
+                  <el-button class="save" @click="submitForm()" type="primary" :loading="comfirmLoading">
+                    生成图片
+                  </el-button>
+                  <div class="clear" @click="resetForm()">
+                    <el-button>清空</el-button>
+                  </div>
+                </div>
+              </el-form-item>
+            </el-form>
+          </div>
+          <div
+            class="tool-direct-right"
+            flex="1 ~ col"
+            v-loading="viewLoading"
+          >
+            <!-- <div class="tool-direct-right__title">
+              <h3>生成结果</h3>
+            </div> -->
+            <div
+              class="tool-direct-right__result"
+              flex="1 ~ col"
+              h-full
+            > 
+              <div
+                v-if="comfirmLoading"
+                class="tool-direct-right__loading"
+                flex="1 ~ col"
+              >
+                <svg
+                  xmlns="http://www.w3.org/2000/svg"
+                  width="24"
+                  height="24"
+                  viewBox="0 0 24 24"
+                  fill="none"
+                  stroke="currentColor"
+                  stroke-width="2"
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  style="color: rgb(154, 120, 110);"
+                ><path d="M21 12a9 9 0 1 1-6.219-8.56" /></svg>
+                AI正在为您生成图片...
+              </div>
+              <template v-else>
+                <div class="result-success" v-if="resultImage">
+                  <div class="preview-black__images">
+                    <div class="images-preview">
+                      <img
+                        :src="resultImage"
+                        alt=""
+                      >
+                    </div>
+                    <el-tooltip class="item" effect="dark" content="预览" placement="top">
+                      <div class="images-preview__search">
+                          <el-image
+                            :src="resultImage"
+                            :preview-src-list="srcList"
+                          ></el-image>
+                          <svg t="1759203455323" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4663" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M928 886.4l-160-160c128-150.4 120-377.6-20.8-520C596.8 56 353.6 56 204.8 206.4c-72 72-112 169.6-112 272s40 198.4 112 272c72 72 169.6 112 272 112 91.2 0 179.2-32 248-91.2l160 160c12.8 12.8 32 12.8 44.8 0 11.2-12.8 11.2-32-1.6-44.8zM249.6 705.6c-60.8-60.8-94.4-140.8-94.4-225.6s33.6-166.4 94.4-225.6c62.4-62.4 144-92.8 225.6-92.8s163.2 30.4 225.6 92.8c124.8 124.8 124.8 328 0 452.8C640 768 560 801.6 475.2 801.6c-84.8-3.2-164.8-35.2-225.6-96z" fill="#333333" p-id="4664"></path></svg>
+                      </div>
+                    </el-tooltip>
+                    <div class="images-preview__icon">
+                      <el-tooltip class="item" effect="dark" content="保存到我的作品" placement="top">
+                        <div class="like-icons icons" @click="saveUserWork">
+                          <svg
+                            xmlns="http://www.w3.org/2000/svg"
+                            width="24"
+                            height="24"
+                            viewBox="0 0 24 24"
+                            fill="none"
+                            stroke="#EF4444"
+                            stroke-width="2"
+                            stroke-linecap="round"
+                            stroke-linejoin="round"
+                          ><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z" /></svg>
+                        </div>
+                      </el-tooltip>
+                      <el-tooltip class="item" effect="dark" content="下载" placement="top">
+                        <div class="download-icon icons" @click="handleDownload">
+                          <svg
+                            xmlns="http://www.w3.org/2000/svg"
+                            width="24"
+                            height="24"
+                            viewBox="0 0 24 24"
+                            fill="none"
+                            stroke="currentColor"
+                            stroke-width="2"
+                            stroke-linecap="round"
+                            stroke-linejoin="round"
+                          ><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /><polyline points="7 10 12 15 17 10" /><line
+                            x1="12"
+                            x2="12"
+                            y1="15"
+                            y2="3"
+                          /></svg>
+                        </div>
+                      </el-tooltip>
+                    </div>
+                  </div>
+                </div>
+                <div
+                  v-else
+                  class="result-empty"
+                  flex="1 ~ col"
+                >
+                  <svg t="1760405750612" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4580" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.1953125" height="200"><path d="M512.016 1024C229.232 1024 0.016 794.784 0.016 512 0.016 229.216 229.232 0 512.016 0 794.784 0 1024 229.216 1024 512 1024 794.784 794.784 1024 512.016 1024ZM512.016 64C264.976 64 64.016 264.96 64.016 512 64.016 759.024 264.976 960 512.016 960 759.04 960 960 759.024 960 512 960 264.96 759.04 64 512.016 64ZM510.336 833.456C509.056 833.456 507.744 833.488 506.448 833.488 310.992 833.488 229.024 657.12 225.616 649.552 218.336 633.424 225.488 614.496 241.584 607.216 257.712 599.968 276.576 607.088 283.888 623.088 286.64 629.12 352.928 769.488 506.576 769.488 507.584 769.488 508.576 769.456 509.584 769.456 672.896 767.552 738.368 624.768 739.024 623.344 746.176 607.216 765.024 599.872 781.264 607.152 797.392 614.336 804.672 633.248 797.456 649.408 794.176 656.8 714.208 831.056 510.336 833.456ZM671.504 479.84C636.224 479.84 607.664 451.232 607.664 415.984 607.664 380.768 636.224 352.176 671.504 352.176 706.768 352.176 735.344 380.768 735.344 415.984 735.344 451.232 706.768 479.84 671.504 479.84ZM351.504 479.84C316.224 479.84 287.664 451.232 287.664 415.984 287.664 380.768 316.224 352.176 351.504 352.176 386.768 352.176 415.344 380.768 415.344 415.984 415.344 451.232 386.768 479.84 351.504 479.84Z" p-id="4581" fill="#ae8878"></path></svg>
+                  等您好久了 <br>
+                  在右侧工作区生成图片吧~
+                </div>
+              </template>
+            </div>
+          </div>
+        </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+
+import { api } from "@/api/api";
+import { getToken } from '@/utils/auth'
+import downloadUtil from "@/utils/downloadUtil";
+import { genCidHex16, fetchStreamText } from '@/utils/index'
+import request from '@/utils/request'
+export default {
+  components: {
+  },
+  data() {
+    return {
+      action: api.fileUrl,
+      uploading: false,
+      comfirmLoading: false,
+      viewLoading: false,
+      resultImage: '',
+      pagesData: {},
+      pagesId: 1,
+      replaceIndex: null,
+      ruleForm: {
+        imageUrl: '',
+        imageList: [],
+        screenDescription: '',
+        imageRatioList: '',
+        imageSizeSelect: '',
+        imageSize: {}
+      },
+      rules: {
+        imageUrl: [
+          { validator: (rule, value, callback) => this.checkImage(rule, value, callback), trigger: "change" }
+        ],
+        imageList: [
+          { validator: (rule, value, callback) => this.checkImageList(rule, value, callback), trigger: "change" }
+        ],
+        screenDescription: [
+          { 
+            validator: (rule, value, callback) => {
+              // 根据条件动态判断是否必填
+              if (this.pagesData.applicationId != 3 && !value) {
+                callback(new Error('请输入画面描述'))
+              } else if (value && value.length < 3) {
+                callback(new Error('画面描述至少需要 3 个字符'))
+              } else {
+                callback()
+              }
+            },
+            trigger: ['blur', 'change']
+          }
+        ]
+      },
+      hasCustom: false,
+      srcList: []
+    };
+  },
+  //页面创建的时候执行
+  mounted() {
+    const id = this.$route.params.id;
+    this.clearFormData();
+    if (id == 1) {
+      this.pagesData = {
+        title: '创意生图',
+        applicationId: id, // 1:文生图 2:图生图 3:图片生成线稿
+        desc: '通过详细的文字描述,AI将为您生成符合要求的服装设计方案。'
+      }
+    }
+    if (id == 2) {
+      this.pagesData = {
+        title: '图生图',
+        applicationId: id, // 1:文生图 2:图生图 3:图片生成线稿
+        desc: '上传参考图片,AI将基于图片内容创作新的服装设计。'
+      }
+    }
+    if (id == 3) {
+      this.pagesData = {
+        title: '线稿生成',
+        applicationId: id, // 1:文生图 2:图生图 3:图片生成线稿
+        desc: '上传确定好的服装设计图,AI将提取静物轮廓生成专业的线稿。'
+      }
+    }
+  },
+  computed: {
+    token() {
+      return getToken();
+    },
+    imageSizes() {
+      return [
+        {label: '1080×1350', value: '1080×1350'},
+        {label: '1200×1500', value: '1200×1500'},
+        {label: '1920×1080', value: '1920×1080'},
+        {label: '2000×2000', value: '2000×2000'}
+      ]
+    },
+    groupedImages() {
+      const result = []
+      for (let i = 0; i < this.ruleForm.imageList.length; i += 2) {
+        result.push(this.ruleForm.imageList.slice(i, i + 2))
+      }
+      return result
+    }
+  },
+  methods: {
+    handleCustom() {
+      this.hasCustom = !this.hasCustom
+      if (!this.hasCustom) {
+        this.ruleForm.imageSize = {}
+      }
+    },
+    checkImage(rule, value, callback) {
+      if (!this.ruleForm.imageUrl) {
+        callback(new Error('请上传图片!'));
+      } else {
+        callback();
+      }
+    },
+    checkImageList(rule, value, callback) {
+      if (!this.ruleForm.imageList.length) {
+        callback(new Error('请至少上传一张图片!'));
+      } else {
+        callback();
+      }
+    },
+    submitForm() {
+      this.$refs['ruleForm'].validate(async (valid) => {
+        if (valid) {
+          this.comfirmLoading = true;
+          let payload = {
+            sessionId: `${Date.now() + 10}_${genCidHex16()}`,
+            applicationId: this.pagesData.applicationId,
+            prompt: this.ruleForm.screenDescription
+          }
+          let ajaxName = 'textMessage'
+          if (this.pagesData.applicationId == 2) {
+            // 图生图
+            ajaxName = 'imageMessage'
+            let imageRatio = []
+            if (this.ruleForm.imageRatioList) {
+              imageRatio = this.ruleForm.imageRatioList.trim().split(':').map(s => Number(s.trim()))
+            }
+            let imageSize = []
+            if (this.ruleForm.imageSizeSelect) {
+              imageSize = this.ruleForm.imageSizeSelect.split(/[×xX*]/).map(Number)
+            }
+            if (this.ruleForm.imageSize.height && this.ruleForm.imageSize.width) {
+              imageSize = [this.ruleForm.imageSize.width, this.ruleForm.imageSize.height]
+            }
+            payload = {
+              sessionId: `${Date.now() + 10}_${genCidHex16()}`,
+              applicationId: this.pagesData.applicationId,
+              prompt: this.ruleForm.screenDescription,
+              images: this.ruleForm.imageList,
+              ratio: imageRatio,
+              imageSize: imageSize
+            }
+          }
+
+          if (this.pagesData.applicationId == 3) {
+            ajaxName = 'generateSketch'
+            payload = {
+              sessionId: `${Date.now() + 10}_${genCidHex16()}`,
+              applicationId: this.pagesData.applicationId,
+              prompt: this.ruleForm.screenDescription,
+              image: this.ruleForm.imageUrl
+            }
+          }
+          try {
+            const result = await fetchStreamText(`/app/ai/send/${ajaxName}`, payload, {
+              onChunk: (chunk) => {
+                console.log('实时分片:', chunk)
+                // this.replyText += chunk // Vue 可实时更新聊天内容
+              }
+            })
+            try {
+              if (result && typeof result == 'string') {
+                console.log('完整文本:', result)
+                const data = JSON.parse(result)
+                if (result.code == 200) {
+                  this.resultImage = data.image
+                  this.srcList = [data.image]
+                } else {
+                  this.$message.error(data.msg || data.errorContent || '请求出错,请联系管理员!');
+                }
+              } else {
+                console.log('JSON 对象12', result)
+                if (result.code == 200) {
+                  this.resultImage = result.image
+                  this.srcList = [result.image]
+                } else {
+                  this.$message.error(result.msg || result.errorContent || '请求出错,请联系管理员!');
+                }
+              }
+            } catch (e) {
+              console.error('报错:', e)
+            }
+          } catch (e) {
+            console.error('请求错误:', e)
+          } finally {
+            this.comfirmLoading = false
+          }
+        }
+      });
+    },
+    clearFormData() {
+      this.$nextTick(() => {
+        this.ruleForm = {
+          imageUrl: '',
+          imageList: [],
+          screenDescription: '',
+          imageRatioList: '',
+          imageSizeSelect: '',
+          imageSize: {}
+        }
+        this.$refs.ruleForm && this.$refs.ruleForm.resetFields();
+      })
+    },
+    resetForm() {
+      this.$confirm("确定要清空所有选项吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.clearFormData()
+        this.$notify({
+          title: "成功",
+          message: "操作成功",
+          type: "success",
+          duration: 3000
+        });
+      });
+    },
+    replaceFile(groupIndex, itemIndex) {
+      this.replaceIndex = groupIndex * 2 + itemIndex
+
+      // 清空上传队列
+      this.$refs.uploadRef.uploadFiles = []
+
+      // 手动触发上传框选择文件
+      const input = this.$refs.uploadRef.$el.querySelector('input[type=file]')
+      input.click()
+
+      // 在 handleSuccess 中会替换对应文件
+    },
+    beforeUploadVideo(file) {
+      this.uploading = true;
+      const isLt10M = file.size / 1024 / 1024 < 200;
+      const imagesTypes = ['image/png','image/jpeg']
+      if (!imagesTypes.includes(file.type)) {
+        this.uploading = false;
+        this.$message.error('图片只能是JPG、PNG格式!');
+        return false;
+      }
+      if (!isLt10M) {
+        this.$message.error('上传文件大小不能超过20MB哦!');
+        return false;
+      }
+      return true
+    },
+    handleVideoSuccess(res, file) {
+      this.uploading = false
+      this.$refs.ruleForm.clearValidate(['imageList']);
+      this.$refs.ruleForm.clearValidate(['imageUrl']);
+
+      if (this.pagesData.applicationId == 2) {
+        if (this.replaceIndex !== null) {
+          // 用新图片替换原有 URL
+          if (res.code == 200) {
+            this.$set(this.ruleForm.imageList, this.replaceIndex, res.data.url)
+          }
+          this.replaceIndex = null
+        } else {
+          // 新增上传
+          if (res.code == 200) {
+            this.ruleForm.imageList.push(res.data.url)
+          } else {
+            this.$message.error('上传失败,请重新上传!');
+          }
+        }
+      } else {
+        if (res.code == 200) {
+          this.ruleForm.imageUrl = res.data.url
+        } else {
+          this.$message.error('上传失败,请重新上传!');
+        }
+      }
+    },
+    imgUploadDel(groupIndex, itemIndex) {
+      //删除
+      this.$confirm("确定要删除吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        if (this.pagesData.applicationId == 2) {
+          const index = groupIndex * 2 + itemIndex
+          this.ruleForm.imageList.splice(index, 1);
+        } else {
+          this.ruleForm.imageUrl = ''
+        }
+        
+        this.$notify({
+          title: "成功",
+          message: "删除成功",
+          type: "success",
+          duration: 3000
+        });
+      });
+    },
+    clearDescription() {
+      this.$refs.ruleForm.clearValidate(['description']);
+      this.ruleForm.screenDescription = ''
+    },
+    openPreview() {
+      this.$refs.imgRef.$el.click()
+    },
+    // 视频下载
+    async handleDownload() {
+      const match = this.resultImage.match(/\/files\/b\/[^\/]+\/([^\/.]+)\./)
+      if (match) {
+        this.viewLoading = true
+        const fileName = match[1]
+        try {
+          const res = await downloadUtil.fileDownload(this.resultImage, fileName);
+          if (res) {
+            this.$message.success("下载成功");
+          }
+        } catch (error) {
+          this.$message.error(error.message);
+        } finally {
+          this.viewLoading = false
+        }
+      }
+    },
+    saveUserWork() {
+      this.viewLoading = true
+      request({
+        url: '/userWork/add',
+        method: 'post',
+        data: {
+          applicationId: this.pagesData.applicationId,
+          image: this.resultImage
+        }
+      }).then(res => {
+        if (res.code == 200) {
+          this.$message.success(res.msg || '操作成功!');
+        }
+      }).finally(() => {
+        this.viewLoading = false
+      })
+    }
+  }
+};
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+@import "@/styles/layout.scss";
+@import "./design-agent.scss";
+</style>

+ 437 - 0
src/views/design-agent/index.vue

@@ -0,0 +1,437 @@
+<template>
+  <div class="design-agent-block">
+    <symbol id="icon-aiyoujiantou" viewBox="0 0 1024 1024"><path d="M350.165333 97.834667a42.666667 42.666667 0 0 0-60.330666 60.330666L643.626667 512 289.834667 865.834667a42.666667 42.666667 0 0 0-2.496 57.621333l2.496 2.709333a42.666667 42.666667 0 0 0 60.330666 0l384-384a42.666667 42.666667 0 0 0 0-60.330666l-384-384z"></path></symbol>
+    <div class="index-block">
+      <div class="flex-grow">
+        <div class="flex-grow-top">
+          <div
+            class="dialog-compose-mode"
+            @click="gotoChat"
+          >
+            <div class="flex-grow-top_icon">
+              <svg
+                xmlns="http://www.w3.org/2000/svg"
+                width="24"
+                height="24"
+                viewBox="0 0 24 24"
+                fill="none"
+                stroke="currentColor"
+              ><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" /></svg>
+            </div>
+            <div class="flex-grow-top_title">对话创作模式</div>
+            <div class="flex-grow-top_desc">与AI设计助手自由对话,通过自然语言描述您的创意想法, 智能体将理解并帮您实现设计愿景。</div>
+            <div class="dialog-btns">
+              <a
+                class="dialog-btns-a"
+                href="javascript:;"
+              >开始对话创作</a>
+            </div>
+          </div>
+          <div class="tool-direct-mode">
+            <div class="flex-grow-top_icon">
+              <svg
+                xmlns="http://www.w3.org/2000/svg"
+                width="24"
+                height="24"
+                viewBox="0 0 24 24"
+                fill="none"
+                stroke="currentColor"
+              ><path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z" /></svg>
+            </div>
+            <div class="flex-grow-top_title">工具直达模式</div>
+            <div class="flex-grow-top_desc">直接选择专业设计工具,快速开始特定类型的创作任务, 适合有明确设计目标的用户。</div>
+            <div class="tool-direction">↓ 选择下方工具开始创作 ↓</div>
+          </div>
+        </div>
+        <div class="flex-grow-bottom">
+          <h2 class="tool-direct__title">一站式智能工具,<span class="mod-title-highlight">效率转化</span>全提升</h2>
+          <div class="feature-mod-content">
+            <div class="feature-mod-content-main">
+              <div class="feature-mod-content-main-item-wrapper theme-pink" @click="gotoTools('1')">
+                <div class="feature-mod-content-main-item left-imgs-count-1">
+                  <div class="feature-mod-content-main-item-left">
+                    <div class="feature-mod-content-main-item-left-title">
+                      创意生图
+                      <span class="feature-mod-content-main-item-left-title-arrow">
+                        <span role="img" class="anticon arrow-icon arrow-first">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                        <span role="img" class="anticon arrow-icon arrow-second">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                      </span>
+                    </div>
+                    <div class="feature-mod-content-main-item-left-desc">
+                      随心创作想要的设计图
+                    </div>
+                    <div class="feature-mod-content-main-item-left-imgs">
+                      <div class="feature-mod-content-main-item-left-imgs-img">
+                        <div class="acss-1mnncja image-container" style="width: 100%; height: 100%;">
+                          <div class="ant-image">
+                            <img class="ant-image-img" src="https://img.alicdn.com/imgextra/i2/O1CN014muJba1xs8gueCksl_!!6000000006498-2-tps-868-512.png_640x640q90s150.jpg_.webp" alt="创意生图">
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="feature-mod-content-main-item-right">
+                    <div class="feature-mod-content-main-item-right-imgs count-2">
+                      <div class="feature-mod-content-main-item-right-imgs-img">
+                        <div class="acss-1mnncja image-container" style="width: 100%; height: 100%;">
+                          <div class="ant-image">
+                            <img class="ant-image-img" src="@/assets/image/design-text1.jpg" alt="创意生图">
+                          </div>
+                        </div>
+                      </div>
+                      <div class="feature-mod-content-main-item-right-imgs-img">
+                        <div class="acss-1mnncja image-container" style="width: 100%; height: 100%;">
+                          <div class="ant-image">
+                            <img class="ant-image-img" src="@/assets/image/design-text2.jpg" alt="创意生图">
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+              <div class="feature-mod-content-main-item-wrapper theme-blue" @click="gotoTools('2')">
+                <div class="feature-mod-content-main-item left-imgs-count-3">
+                  <div class="feature-mod-content-main-item-left">
+                    <div class="feature-mod-content-main-item-left-title">
+                      图生图
+                      <span class="feature-mod-content-main-item-left-title-arrow">
+                        <span role="img" class="anticon arrow-icon arrow-first">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                        <span role="img" class="anticon arrow-icon arrow-second">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                      </span>
+                    </div>
+                    <div class="feature-mod-content-main-item-left-desc">
+                      随心创作想要的设计图
+                    </div>
+                    <div class="feature-mod-content-main-item-left-imgs">
+                      <div class="feature-mod-content-main-item-left-imgs-img">
+                        <div class="acss-1mnncja image-container" style="width: 100%; height: 100%;">
+                          <div class="ant-image">
+                            <img class="ant-image-img" src="@/assets/image/design-image3.jpg" alt="图生图">
+                          </div>
+                        </div>
+                      </div>
+                      <div class="feature-mod-content-main-item-left-imgs-img">
+                        <div class="acss-1mnncja image-container" style="width: 100%; height: 100%;">
+                          <div class="ant-image">
+                            <img class="ant-image-img" src="@/assets/image/design-image2.jpg" alt="图生图">
+                          </div>
+                        </div>
+                      </div>
+                      <div class="feature-mod-content-main-item-left-imgs-img">
+                        <div class="acss-1mnncja image-container" style="width: 100%; height: 100%;">
+                          <div class="ant-image">
+                            <img class="ant-image-img" src="@/assets/image/design-image1.jpg" alt="图生图">
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                    <img class="feature-mod-content-main-item-left-arrow" src="@/assets/image/design-arrow.png">
+                  </div>
+                  <div class="feature-mod-content-main-item-right">
+                    <div class="feature-mod-content-main-item-right-imgs count-1">
+                      <div class="feature-mod-content-main-item-right-imgs-img">
+                        <div class="acss-1mnncja image-container" style="width: 100%; height: 100%;">
+                          <div class="ant-image">
+                            <img class="ant-image-img" src="@/assets/image/design-image-index.jpg" alt="图生图">
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+              <div class="feature-mod-content-main-item-wrapper theme-yellow" @mouseenter="playVideo($event)" @mouseleave="pauseVideo($event)" @click="gotoTools('3')">
+                <div class="feature-mod-content-main-item left-imgs-count-4">
+                  <div class="feature-mod-content-main-item-left">
+                    <div class="feature-mod-content-main-item-left-title">
+                      线稿生成
+                      <span class="acss-xpsi7w feature-mod-content-main-item-left-title-arrow">
+                        <span role="img" class="anticon arrow-icon arrow-first">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                        <span role="img" class="anticon arrow-icon arrow-second">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                      </span>
+                    </div>
+                    <div class="feature-mod-content-main-item-left-desc">
+                      一键转为专业的设计线稿
+                    </div>
+                    <div class="feature-mod-content-main-item-left-imgs">
+                      <div class="feature-mod-content-main-item-left-imgs-img">
+                        <div class="acss-1mnncja image-container" style="width: 100%; height: 100%;">
+                          <div class="ant-image">
+                            <img class="ant-image-img" src="@/assets/image/design-line1.jpg" alt="线稿生成">
+                          </div>
+                        </div>
+                      </div>
+                      <div class="feature-mod-content-main-item-left-imgs-img">
+                        <div class="acss-1mnncja image-container" style="width: 100%; height: 100%;">
+                          <div class="ant-image">
+                            <img class="ant-image-img" src="@/assets/image/design-line2.jpg" alt="线稿生成">
+                          </div>
+                        </div>
+                      </div>
+                      <div class="feature-mod-content-main-item-left-imgs-img">
+                        <div class="acss-1mnncja image-container" style="width: 100%; height: 100%;">
+                          <div class="ant-image">
+                            <img class="ant-image-img" src="@/assets/image/design-line3.jpg" alt="线稿生成">
+                          </div>
+                        </div>
+                      </div>
+                      <div class="feature-mod-content-main-item-left-imgs-img">
+                        <div class="acss-1mnncja image-container" style="width: 100%; height: 100%;">
+                          <div class="ant-image">
+                            <img class="ant-image-img" src="@/assets/image/design-line4.jpg" alt="线稿生成">
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                    <img class="feature-mod-content-main-item-left-arrow" src="@/assets/image/design-arrow.png">
+                  </div>
+                  <div class="feature-mod-content-main-item-right">
+                    <div class="acss-sxg5vc video-player loaded feature-mod-content-main-item-right-video"
+                    style="width: 100%; height: 100%;">
+                      <video controlslist="nodownload" loop="" style="width: 100%; height: 100%;">
+                        <source src="@/assets/image/design-line-video.mp4">
+                          Your browser does not support the video tag.
+                      </video>
+                      <div class="video-event-mask">
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+            <div class="feature-mod-content-sub">
+              <div class="feature-mod-content-sub-item-wrapper">
+                <div class="feature-mod-content-sub-item">
+                  <div class="feature-mod-content-sub-item-left">
+                    <div class="acss-1mnncja image-container" style="width: 92px; height: 64px;">
+                      <div class="ant-image">
+                        <img class="feature-mod-content-sub-item-left-img" src="//img.alicdn.com/imgextra/i2/O1CN012r1h0D1CmqAKOEwPN_!!6000000000124-2-tps-1104-768.png_640x640q90s150.jpg_.webp" alt="搭配融图" width="92" height="64"></div>
+                    </div>
+                  </div>
+                  <div class="feature-mod-content-sub-item-right">
+                    <div class="feature-mod-content-sub-item-right-title">
+                      搭配融图
+                      <span class="acss-xpsi7w feature-mod-content-sub-item-right-title-arrow">
+                        <span role="img" class="anticon arrow-icon arrow-first">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                        <span role="img" class="anticon arrow-icon arrow-second">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                      </span>
+                    </div>
+                    <div class="feature-mod-content-sub-item-right-desc">
+                      智能搭配得爆款套图
+                    </div>
+                  </div>
+                </div>
+              </div>
+              <div class="feature-mod-content-sub-item-wrapper">
+                <div class="feature-mod-content-sub-item">
+                  <div class="feature-mod-content-sub-item-left">
+                    <div class="acss-1mnncja image-container" style="width: 92px; height: 64px;">
+                      <div class="ant-spin ant-spin-spinning css-h46z68">
+                        <div class="ant-image">
+                          <img class="feature-mod-content-sub-item-left-img" src="//img.alicdn.com/imgextra/i2/O1CN01CL4n2X1wtE0qDFuwT_!!6000000006365-2-tps-1104-768.png_640x640q90s150.jpg_.webp" alt="换模特换背景" width="92" height="64">
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="feature-mod-content-sub-item-right ant-flex css-h46z68 ant-flex-align-stretch ant-flex-vertical">
+                    <div class="feature-mod-content-sub-item-right-title">
+                      换模特换背景
+                      <span class="acss-xpsi7w feature-mod-content-sub-item-right-title-arrow">
+                        <span role="img" class="anticon arrow-icon arrow-first">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                        <span role="img" class="anticon arrow-icon arrow-second">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                      </span>
+                    </div>
+                    <div class="feature-mod-content-sub-item-right-desc">
+                      模特和背景随心替换
+                    </div>
+                  </div>
+                </div>
+              </div>
+              <div class="feature-mod-content-sub-item-wrapper">
+                <div class="feature-mod-content-sub-item">
+                  <div class="feature-mod-content-sub-item-left">
+                    <div class="acss-1mnncja image-container" style="width: 92px; height: 64px;">
+                      <div class="ant-spin ant-spin-spinning css-h46z68">
+                        <div class="ant-image">
+                          <img class="feature-mod-content-sub-item-left-img" src="//img.alicdn.com/imgextra/i1/O1CN01y9T3yU1CJWomIrrgJ_!!6000000000060-2-tps-1104-768.png_640x640q90s150.jpg_.webp" alt="商品换背景" width="92" height="64">
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="feature-mod-content-sub-item-right ant-flex css-h46z68 ant-flex-align-stretch ant-flex-vertical">
+                    <div class="feature-mod-content-sub-item-right-title">
+                      商品换背景
+                      <span class="acss-xpsi7w feature-mod-content-sub-item-right-title-arrow">
+                        <span role="img" class="anticon arrow-icon arrow-first">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                        <span role="img" class="anticon arrow-icon arrow-second">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                      </span>
+                    </div>
+                    <div class="feature-mod-content-sub-item-right-desc">
+                      智能抠图换景,让商品适配不同营销场景
+                    </div>
+                  </div>
+                </div>
+              </div>
+              <div class="feature-mod-content-sub-item-wrapper">
+                <div class="feature-mod-content-sub-item">
+                  <div class="feature-mod-content-sub-item-left">
+                    <div class="acss-1mnncja image-container" style="width: 92px; height: 64px;">
+                      <div class="ant-spin ant-spin-spinning css-h46z68">
+                        <div class="ant-image">
+                          <img class="feature-mod-content-sub-item-left-img" src="//img.alicdn.com/imgextra/i2/O1CN01Dm96Cr1LZP5X2apVG_!!6000000001313-2-tps-1104-768.png_640x640q90s150.jpg_.webp" alt="定向换色" width="92" height="64">
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="feature-mod-content-sub-item-right">
+                    <div class="feature-mod-content-sub-item-right-title">
+                      定向换色
+                      <span class="acss-xpsi7w feature-mod-content-sub-item-right-title-arrow">
+                        <span role="img" class="anticon arrow-icon arrow-first">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                        <span role="img" class="anticon arrow-icon arrow-second">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                      </span>
+                    </div>
+                    <div class="feature-mod-content-sub-item-right-desc">
+                      颜色快速替换,轻松做多色设计稿
+                    </div>
+                  </div>
+                </div>
+              </div>
+              <div class="feature-mod-content-sub-item-wrapper">
+                <div class="feature-mod-content-sub-item">
+                  <div class="feature-mod-content-sub-item-left">
+                    <div class="acss-1mnncja image-container" style="width: 92px; height: 64px;">
+                      <div class="ant-spin ant-spin-spinning css-h46z68">
+                        <div class="ant-image">
+                          <img class="feature-mod-content-sub-item-left-img" src="//img.alicdn.com/imgextra/i2/O1CN01WTLmcM1SZaYfPgPUu_!!6000000002261-2-tps-1104-768.png_640x640q90s150.jpg_.webp" alt="面料上身" width="92" height="64">
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="feature-mod-content-sub-item-right">
+                    <div class="feature-mod-content-sub-item-right-title">
+                      面料上身
+                      <span class="acss-xpsi7w feature-mod-content-sub-item-right-title-arrow">
+                        <span role="img" class="anticon arrow-icon arrow-first">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                        <span role="img" class="anticon arrow-icon arrow-second">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                      </span>
+                    </div>
+                    <div class="feature-mod-content-sub-item-right-desc">
+                      面料随心套,预览真实上身效果
+                    </div>
+                  </div>
+                </div>
+              </div>
+              <div class="feature-mod-content-sub-item-wrapper">
+                <div class="feature-mod-content-sub-item">
+                  <div class="feature-mod-content-sub-item-left">
+                    <div class="acss-1mnncja image-container" style="width: 92px; height: 64px;">
+                      <div class="ant-spin ant-spin-spinning css-h46z68">
+                        <div class="ant-image">
+                          <img class="feature-mod-content-sub-item-left-img" src="//img.alicdn.com/imgextra/i3/O1CN01w4XdbW1GST0hNoYRl_!!6000000000621-2-tps-1104-768.png_640x640q90s150.jpg_.webp" alt="图案上身" width="92" height="64">
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="feature-mod-content-sub-item-right">
+                    <div class="feature-mod-content-sub-item-right-title">
+                      图案上身
+                      <span class="acss-xpsi7w feature-mod-content-sub-item-right-title-arrow">
+                        <span role="img" class="anticon arrow-icon arrow-first">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                        <span role="img" class="anticon arrow-icon arrow-second">
+                          <svg width="1em" height="1em" fill="currentColor"><use xlink:href="#icon-aiyoujiantou"></use></svg>
+                        </span>
+                      </span>
+                    </div>
+                    <div class="feature-mod-content-sub-item-right-desc">
+                      图案快速应用到服装
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    
+  </div>
+</template>
+
+<script>
+export default {
+  components: {
+  },
+  data() {
+    return {
+    };
+  },
+  methods: {
+    playVideo(e) {
+      const video = e.currentTarget.querySelector("video");
+      if (video) {
+        video.play().catch(err => {
+          console.warn("视频播放失败:", err);
+        });
+      }
+    },
+    pauseVideo(e) {
+      const video = e.currentTarget.querySelector("video");
+      if (video) {
+        video.pause();
+      }
+    },
+    gotoChat() {
+      this.$router.push({
+        name: "chatCreation"
+      });
+    },
+    gotoTools(id) {
+      this.$router.push({
+        name: 'imagetextToImage',
+        params: { id: id }
+      })
+    }
+  }
+};
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+@import "@/styles/layout.scss";
+@import "./design-agent.scss";
+</style>

+ 1 - 1
vue.config.js

@@ -5,7 +5,7 @@ const defaultSettings = require("./src/settings.js");
 function resolve(dir) {
   return path.join(__dirname, dir);
 }
-const name = defaultSettings.title || "歌莉娅AI口播视频管理平台"; // 标题
+const name = defaultSettings.title || "歌莉娅AI营销平台"; // 标题
 const port = process.env.port || process.env.npm_config_port || 9557; // 开发接口
 
 // 所有配置项描述 查看: https://cli.vuejs.org/config/