Pārlūkot izejas kodu

本地登录-需注释-暂存

armg 1 dienu atpakaļ
vecāks
revīzija
fa899c5007
100 mainītis faili ar 22541 papildinājumiem un 0 dzēšanām
  1. 2 0
      .browserslistrc
  2. 12 0
      .env
  3. 6 0
      .env.development
  4. 5 0
      .env.production
  5. 15 0
      .eslintrc.js
  6. 21 0
      .gitignore
  7. 20 0
      babel.config.js
  8. 13695 0
      package-lock.json
  9. 52 0
      package.json
  10. 1 0
      public/WW_verify_SaQNya1DWfAzbRfr.txt
  11. BIN
      public/favicon.ico
  12. 30 0
      public/index.html
  13. BIN
      public/smart.png
  14. 10 0
      src/App.vue
  15. 280 0
      src/api/indexAI.js
  16. BIN
      src/assets/AIDesign/AIIcon.png
  17. BIN
      src/assets/AIDesign/bg.png
  18. BIN
      src/assets/AIDesign/deepSlotProcesses/blackFitting.jpg
  19. BIN
      src/assets/AIDesign/deepSlotProcesses/doubleDeepSlot.jpg
  20. BIN
      src/assets/AIDesign/design-robot.png
  21. BIN
      src/assets/AIDesign/diagnoseTit.png
  22. BIN
      src/assets/AIDesign/diagnosis-printer.png
  23. BIN
      src/assets/AIDesign/european.jpg
  24. BIN
      src/assets/AIDesign/five-element-planet.png
  25. BIN
      src/assets/AIDesign/house-image.jpg
  26. BIN
      src/assets/AIDesign/loding.gif
  27. BIN
      src/assets/AIDesign/magnifyingGlassIcon.png
  28. BIN
      src/assets/AIDesign/modern.png
  29. BIN
      src/assets/AIDesign/newChinese.png
  30. BIN
      src/assets/AIDesign/nothing.png
  31. BIN
      src/assets/AIDesign/nothing1.png
  32. BIN
      src/assets/AIDesign/picture.png
  33. BIN
      src/assets/AIDesign/projectIcon.png
  34. BIN
      src/assets/AIDesign/project_action_loading.png
  35. BIN
      src/assets/AIDesign/project_action_null.png
  36. BIN
      src/assets/AIDesign/project_action_num_0.png
  37. BIN
      src/assets/AIDesign/project_btn_left_icon.png
  38. BIN
      src/assets/AIDesign/project_checked.png
  39. BIN
      src/assets/AIDesign/railings/iron.png
  40. BIN
      src/assets/AIDesign/railings/ironRailings.png
  41. BIN
      src/assets/AIDesign/railings/railings.png
  42. BIN
      src/assets/AIDesign/rightjt.png
  43. BIN
      src/assets/AIDesign/splitWays/crossGrid.jpg
  44. BIN
      src/assets/AIDesign/splitWays/doubleHorizontal.png
  45. BIN
      src/assets/AIDesign/splitWays/flat.jpg
  46. BIN
      src/assets/AIDesign/splitWays/singleHorizontal.jpg
  47. BIN
      src/assets/AIDesign/splitWays/workGrid.jpg
  48. BIN
      src/assets/AIDesign/stoneColors/GS-GZ-01.jpg
  49. BIN
      src/assets/AIDesign/stoneColors/GS-GZ-04.jpg
  50. BIN
      src/assets/AIDesign/stoneColors/LYC-001.jpg
  51. BIN
      src/assets/AIDesign/stoneColors/LYC-009.jpg
  52. BIN
      src/assets/AIDesign/stoneColors/LYC-020.jpg
  53. BIN
      src/assets/AIDesign/stoneColors/LYC-602.jpg
  54. BIN
      src/assets/AIDesign/stoneColors/LYD-001.jpg
  55. BIN
      src/assets/AIDesign/stoneColors/LYD-002.jpg
  56. BIN
      src/assets/AIDesign/stoneColors/LYD-003.jpg
  57. BIN
      src/assets/AIDesign/stoneColors/LYD-004.jpg
  58. BIN
      src/assets/AIDesign/stoneColors/LYD-005.jpg
  59. BIN
      src/assets/AIDesign/stoneColors/MSS001.jpg
  60. BIN
      src/assets/AIDesign/stoneColors/MSS002.jpg
  61. BIN
      src/assets/AIDesign/stoneColors/QHG-001.jpg
  62. BIN
      src/assets/AIDesign/tabL.png
  63. BIN
      src/assets/AIDesign/tabR.png
  64. BIN
      src/assets/AIDesign/top-bg.png
  65. BIN
      src/assets/AIDesign/traditionalChinese.jpg
  66. 65 0
      src/assets/iconfont/iconfont.css
  67. BIN
      src/assets/iconfont/iconfont.eot
  68. 62 0
      src/assets/iconfont/iconfont.svg
  69. BIN
      src/assets/iconfont/iconfont.ttf
  70. BIN
      src/assets/iconfont/iconfont.woff
  71. BIN
      src/assets/images/err.png
  72. 70 0
      src/components/headerOnline.vue
  73. 22 0
      src/components/index.ts
  74. 3 0
      src/layout/components/footer.vue
  75. 13 0
      src/layout/components/header.vue
  76. 31 0
      src/layout/index.vue
  77. 131 0
      src/main.ts
  78. 119 0
      src/router/index.ts
  79. 4 0
      src/store/index.ts
  80. 147 0
      src/styles/index.scss
  81. 23 0
      src/types/global.d.ts
  82. 8 0
      src/types/index.d.ts
  83. 13 0
      src/types/shims-tsx.d.ts
  84. 18 0
      src/utils/clickStatefrom.js
  85. 18 0
      src/utils/cookies.ts
  86. 6 0
      src/utils/errorCode.js
  87. 72 0
      src/utils/index.ts
  88. 52 0
      src/utils/magnetLogAdd.js
  89. 64 0
      src/utils/request.ts
  90. 92 0
      src/utils/requestAI.js
  91. 128 0
      src/utils/wecomLogin.ts
  92. 1888 0
      src/views/AIDesign/design.vue
  93. 779 0
      src/views/AIDesign/diagnose.vue
  94. 562 0
      src/views/AIDesign/diagnoseHistory.vue
  95. 882 0
      src/views/AIDesign/diagnoseResult.vue
  96. 536 0
      src/views/AIDesign/history.vue
  97. 342 0
      src/views/AIDesign/index.vue
  98. 1377 0
      src/views/AIDesign/insideDesign.vue
  99. 865 0
      src/views/AIDesign/result.vue
  100. 0 0
      src/views/errorPage/index.vue

+ 2 - 0
.browserslistrc

@@ -0,0 +1,2 @@
+> 1%
+last 2 versions

+ 12 - 0
.env

@@ -0,0 +1,12 @@
+VUE_APP_PublicTitle=AI设计
+VUE_APP_publicPath=/
+#  DIS小程序appid:gh_4eaccc0824ca
+VUE_APP_BASE_DISID6=wx818da06b25f30cf5
+
+#企业微信 
+# 应用appID
+VUE_APP_APPID=ww5444eb205d75e730
+# 应用agentID
+VUE_APP_AGENTID=1000400
+
+

+ 6 - 0
.env.development

@@ -0,0 +1,6 @@
+VUE_APP_BASE_API=/api/
+VUE_APP_AIDESIGN_API=''
+devtool=cheap-module-eval-source-map
+VUE_APP_AIDESIGN=https://aidesigntest.nipponpaint.com.cn/
+# 应用地址
+VUE_APP_AUTHURL=https://aidesigntest.nipponpaint.com.cn

+ 5 - 0
.env.production

@@ -0,0 +1,5 @@
+VUE_APP_BASE_API=https://suishenbang.nipponpaint.com.cn/wxportal-api/
+VUE_APP_AIDESIGN_API='https://aidesign.nipponpaint.com.cn/'
+devtool=cheap-module-source-map
+# 应用地址
+VUE_APP_AUTHURL=https://aidesign.nipponpaint.com.cn

+ 15 - 0
.eslintrc.js

@@ -0,0 +1,15 @@
+module.exports = {
+  root: true,
+  env: {
+    node: true
+  },
+  extends: ["plugin:vue/essential", "@vue/prettier", "@vue/typescript"],
+  rules: {
+    //  "no-console": process.env.NODE_ENV === "production" ? "error" : "off",
+    "no-console": 0,
+    "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off"
+  },
+  parserOptions: {
+    parser: "@typescript-eslint/parser"
+  }
+};

+ 21 - 0
.gitignore

@@ -0,0 +1,21 @@
+.DS_Store
+node_modules
+/dist
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

+ 20 - 0
babel.config.js

@@ -0,0 +1,20 @@
+module.exports = {
+  presets: ["@vue/cli-plugin-babel/preset"],
+  plugins: [
+    [
+      "import",
+      {
+        libraryName: "vant",
+        libraryDirectory: "es",
+        style: true
+      }
+    ],
+    [
+      "component",
+      {
+        libraryName: "element-ui",
+        styleLibraryName: "theme-chalk"
+      }
+    ]
+  ]
+};

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 13695 - 0
package-lock.json


+ 52 - 0
package.json

@@ -0,0 +1,52 @@
+{
+  "name": "furniture-vue",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "@vant/touch-emulator": "^1.4.0",
+    "axios": "^0.19.0",
+    "core-js": "^3.4.3",
+    "html2canvas": "^1.4.1",
+    "js-cookie": "^2.2.1",
+    "js-md5": "^0.7.3",
+    "qs": "^6.14.0",
+    "vant": "^2.12.54",
+    "vue": "^2.6.10",
+    "vue-class-component": "^7.0.2",
+    "vue-property-decorator": "^8.5.1",
+    "vue-router": "^3.1.3",
+    "vuex": "^3.1.2",
+    "vuex-module-decorators": "^0.11.0"
+  },
+  "devDependencies": {
+    "@types/js-cookie": "^2.2.4",
+    "@types/js-md5": "^0.4.2",
+    "@types/lodash": "^4.14.155",
+    "@types/qs": "^6.9.0",
+    "@vue/cli-plugin-babel": "^4.1.0",
+    "@vue/cli-plugin-eslint": "^4.1.0",
+    "@vue/cli-plugin-router": "^4.1.0",
+    "@vue/cli-plugin-typescript": "^4.1.0",
+    "@vue/cli-plugin-vuex": "^4.1.0",
+    "@vue/cli-service": "^4.1.0",
+    "@vue/eslint-config-prettier": "^5.0.0",
+    "@vue/eslint-config-typescript": "^4.0.0",
+    "babel-plugin-component": "^1.1.1",
+    "babel-plugin-import": "^1.13.0",
+    "element-ui": "^2.13.2",
+    "eslint": "^5.16.0",
+    "eslint-plugin-prettier": "^3.1.1",
+    "eslint-plugin-vue": "^5.0.0",
+    "prettier": "^1.19.1",
+    "sass": "^1.23.7",
+    "sass-loader": "^8.0.0",
+    "ts-import-plugin": "^1.6.6",
+    "typescript": "~3.5.3",
+    "vue-template-compiler": "^2.6.10"
+  }
+}

+ 1 - 0
public/WW_verify_SaQNya1DWfAzbRfr.txt

@@ -0,0 +1 @@
+SaQNya1DWfAzbRfr

BIN
public/favicon.ico


+ 30 - 0
public/index.html

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html lang="zh">
+
+<head>
+  <meta charset="utf-8" />
+  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+  <!--<meta name="viewport" content="width=device-width,initial-scale=1.0" />-->
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
+  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
+  <meta http-equiv="Pragma" content="no-cache" />
+  <meta http-equiv="Expires" content="0" />
+  <script>
+      window.__APP_VERSION__ = "<%= htmlWebpackPlugin.options.version %>";
+  </script>
+  <!--<link rel="icon" href="<%= BASE_URL %>favicon.ico" />-->
+  <script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
+  <script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
+  <title>&#65279</title>
+</head>
+
+<body>
+  <noscript>
+    <strong>We're sorry but govservice-vue doesn't work properly without JavaScript
+      enabled. Please enable it to continue.</strong>
+  </noscript>
+  <div id="app"></div>
+  <!-- built files will be auto injected -->
+</body>
+
+</html>

BIN
public/smart.png


+ 10 - 0
src/App.vue

@@ -0,0 +1,10 @@
+<template>
+  <div id="app">
+    <router-view />
+  </div>
+</template>
+<style scoped>
+#app {
+  height: 100%;
+}
+</style>

+ 280 - 0
src/api/indexAI.js

@@ -0,0 +1,280 @@
+import request from '@/utils/requestAI'
+/**
+ * 公共工具函数:获取并校验登录凭证(guidInfo 和 AIToken)
+ * @returns {Object} { loginMark, token } - 校验后的凭证
+ * @throws {Error} 缺少凭证或格式错误时抛出异常
+ */
+const getAuthCredentials = () => {
+    const guidInfoStr = window.localStorage.getItem('guidInfo');
+    const AIToken = window.localStorage.getItem('AIToken');
+    // 校验凭证是否存在
+    if (!guidInfoStr) throw new Error('未获取到 guidInfo,请先登录');
+    // 解析并校验 guidInfo 格式
+    let guidInfo;
+    try {
+        guidInfo = JSON.parse(guidInfoStr);
+    } catch (error) {
+        throw new Error('guidInfo 格式错误,请重新登录');
+    }
+    // 校验 guid 是否存在
+    if (!guidInfo && !guidInfo.guid) throw new Error('guidInfo 中缺少 guid 参数,请重新登录');
+    // 返回校验后的凭证
+    return {
+        loginMark: guidInfo.guid,
+        token: AIToken
+    };
+};
+
+// 企微认证
+export function wecomAuth() {
+    const { loginMark } = getAuthCredentials();
+    let query = new FormData();
+    query.append('loginMark', loginMark);
+    query.append("wxId", process.env.VUE_APP_APPID);
+    // query.append("code", query.code);
+    // 本地登录-需注释
+    query.append("code", 'QWert!@345');
+    return request({
+        url: '/aidesign/wecom/auth',
+        method: 'post',
+        data: query
+    })
+}
+
+
+// 提交设计
+export function CreateDesign(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/outside/CreateDesign',
+        method: 'post',
+        data: query
+    })
+}
+// 查询列表
+export function GetDesignList(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/outside/GetDesignList',
+        method: 'post',
+        data: query
+    })
+}
+//删除实体
+export function DeleteEntity(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/outside/DeleteEntity',
+        method: 'post',
+        data: query
+    })
+}
+// 获取实体
+export function GetEntity(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/outside/GetEntity',
+        method: 'post',
+        data: query
+    })
+}
+// 获取未读状态
+export function GetReadState(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/outside/GetReadState',
+        method: 'post',
+        data: query
+    })
+}
+// 设置生图历史已读状态
+
+export function UpdateReadState(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/outside/UpdateReadState',
+        method: 'post',
+        data: query
+    })
+}
+
+//获取关联项目列表
+export function GetProjectlist(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/outside/GetProjectlist',
+        method: 'post',
+        data: query
+    })
+}
+
+//获取风格选项列表
+export function GetDictList(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/GetBaseInfo',
+        method: 'post',
+        data: query
+    })
+}
+
+/**
+ * 内墙部分
+ */
+// 内墙提交设计
+export function insideCreateDesign(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/inside/CreateDesign',
+        method: 'post',
+        data: query
+    })
+}
+// 内墙查询列表
+export function insideGetDesignList(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/inside/GetDesignList',
+        method: 'post',
+        data: query
+    })
+}
+
+//内墙删除实体
+export function insideDeleteEntity(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/inside/DeleteEntity',
+        method: 'post',
+        data: query
+    })
+}
+// 内墙获取实体
+export function insideGetEntity(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/inside/GetEntity',
+        method: 'post',
+        data: query
+    })
+}
+
+// 内墙获取未读状态
+export function insideGetReadState(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/inside/GetReadState',
+        method: 'post',
+        data: query
+    })
+}
+
+// 内墙设置生图历史已读状态
+export function insideUpdateReadState(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/inside/UpdateReadState',
+        method: 'post',
+        data: query
+    })
+}
+
+
+
+// 一键诊断-提交设计
+export function diagCreateDesign(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/diag/CreateDesign',
+        method: 'post',
+        data: query
+    })
+}
+
+
+// 一键诊断-查询列表
+export function diagGetDesignList(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/diag/GetDesignList',
+        method: 'post',
+        data: query
+    })
+}
+//一键诊断-删除实体
+export function diagDeleteEntity(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/diag/DeleteEntity',
+        method: 'post',
+        data: query
+    })
+}
+// 一键诊断-获取实体
+export function diagGetEntity(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/diag/GetEntity',
+        method: 'post',
+        data: query
+    })
+}
+// 一键诊断-获取未读状态
+export function diagGetReadState(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/diag/GetReadState',
+        method: 'post',
+        data: query
+    })
+}
+// 一键诊断-设置生图历史已读状态
+
+export function diagUpdateReadState(query) {
+    const auth = getAuthCredentials();
+    query.append('loginMark', auth.loginMark);
+    query.append('token', auth.token);
+    return request({
+        url: '/aidesign/diag/UpdateReadState',
+        method: 'post',
+        data: query
+    })
+}

BIN
src/assets/AIDesign/AIIcon.png


BIN
src/assets/AIDesign/bg.png


BIN
src/assets/AIDesign/deepSlotProcesses/blackFitting.jpg


BIN
src/assets/AIDesign/deepSlotProcesses/doubleDeepSlot.jpg


BIN
src/assets/AIDesign/design-robot.png


BIN
src/assets/AIDesign/diagnoseTit.png


BIN
src/assets/AIDesign/diagnosis-printer.png


BIN
src/assets/AIDesign/european.jpg


BIN
src/assets/AIDesign/five-element-planet.png


BIN
src/assets/AIDesign/house-image.jpg


BIN
src/assets/AIDesign/loding.gif


BIN
src/assets/AIDesign/magnifyingGlassIcon.png


BIN
src/assets/AIDesign/modern.png


BIN
src/assets/AIDesign/newChinese.png


BIN
src/assets/AIDesign/nothing.png


BIN
src/assets/AIDesign/nothing1.png


BIN
src/assets/AIDesign/picture.png


BIN
src/assets/AIDesign/projectIcon.png


BIN
src/assets/AIDesign/project_action_loading.png


BIN
src/assets/AIDesign/project_action_null.png


BIN
src/assets/AIDesign/project_action_num_0.png


BIN
src/assets/AIDesign/project_btn_left_icon.png


BIN
src/assets/AIDesign/project_checked.png


BIN
src/assets/AIDesign/railings/iron.png


BIN
src/assets/AIDesign/railings/ironRailings.png


BIN
src/assets/AIDesign/railings/railings.png


BIN
src/assets/AIDesign/rightjt.png


BIN
src/assets/AIDesign/splitWays/crossGrid.jpg


BIN
src/assets/AIDesign/splitWays/doubleHorizontal.png


BIN
src/assets/AIDesign/splitWays/flat.jpg


BIN
src/assets/AIDesign/splitWays/singleHorizontal.jpg


BIN
src/assets/AIDesign/splitWays/workGrid.jpg


BIN
src/assets/AIDesign/stoneColors/GS-GZ-01.jpg


BIN
src/assets/AIDesign/stoneColors/GS-GZ-04.jpg


BIN
src/assets/AIDesign/stoneColors/LYC-001.jpg


BIN
src/assets/AIDesign/stoneColors/LYC-009.jpg


BIN
src/assets/AIDesign/stoneColors/LYC-020.jpg


BIN
src/assets/AIDesign/stoneColors/LYC-602.jpg


BIN
src/assets/AIDesign/stoneColors/LYD-001.jpg


BIN
src/assets/AIDesign/stoneColors/LYD-002.jpg


BIN
src/assets/AIDesign/stoneColors/LYD-003.jpg


BIN
src/assets/AIDesign/stoneColors/LYD-004.jpg


BIN
src/assets/AIDesign/stoneColors/LYD-005.jpg


BIN
src/assets/AIDesign/stoneColors/MSS001.jpg


BIN
src/assets/AIDesign/stoneColors/MSS002.jpg


BIN
src/assets/AIDesign/stoneColors/QHG-001.jpg


BIN
src/assets/AIDesign/tabL.png


BIN
src/assets/AIDesign/tabR.png


BIN
src/assets/AIDesign/top-bg.png


BIN
src/assets/AIDesign/traditionalChinese.jpg


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 65 - 0
src/assets/iconfont/iconfont.css


BIN
src/assets/iconfont/iconfont.eot


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 62 - 0
src/assets/iconfont/iconfont.svg


BIN
src/assets/iconfont/iconfont.ttf


BIN
src/assets/iconfont/iconfont.woff


BIN
src/assets/images/err.png


+ 70 - 0
src/components/headerOnline.vue

@@ -0,0 +1,70 @@
+<script src="../../vue.config.js"></script>
+<template>
+  <div class="header">
+    <van-nav-bar :title="pagetitle" left-arrow @click-left="returnPage" @click-right="toHome">
+      <template #right>
+        <van-icon v-if="showRightIcon" name="wap-home-o" size="26" />
+      </template>
+    </van-nav-bar>
+  </div>
+</template>
+<script lang="ts">
+import { Component, Vue, Watch, Prop } from "vue-property-decorator";
+@Component
+export default class extends Vue {
+  @Prop({
+    type: String,
+    required: true,
+    default: " "
+  })
+  pagetitle!: string;
+
+  @Prop({
+    type: Boolean, 
+    required: false,
+    default: true
+  })
+  showRightIcon!: boolean; 
+
+  @Watch("$route")
+  routechange(to: any, from: any) {
+    // if (to.path == "/home" && to.query.userId) {
+    //   let baseUrl: string = "";
+    //   window.location.href = baseUrl;
+    // }
+  }
+  async created() {
+  }
+  async returnPage() {
+    let that = this;
+    if (window.history.length < 1) {
+        that.$router.push({ path: "/" });
+        return false;
+    } else {
+        this.$router.go(-1);
+    }
+    }
+  toHome() {
+    this.$router.replace('/');
+  }
+}
+</script>
+<style lang="scss">
+.header {
+  /*height: 50px;*/
+  /*line-height: 50px;*/
+  /*text-align: center;*/
+  /*background: #fff;*/
+  border-bottom: 1px solid #f8f8f8;
+
+  .van-nav-bar__title {
+    font-size: 20px;
+    color: #333;
+  }
+
+  .van-icon {
+    font-size: 20px;
+    color: #333 !important;
+  }
+}
+</style>

+ 22 - 0
src/components/index.ts

@@ -0,0 +1,22 @@
+import Vue from "vue";
+import { upperFirst, camelCase } from "lodash";
+
+const requireComponent = require.context("./", false, /\w+\.vue$/);
+
+requireComponent.keys().forEach(fileName => {
+  // 获取组件配置
+  const componentConfig = requireComponent(fileName);
+
+  // 获取组件的 PascalCase 命名
+  const componentName = upperFirst(
+    camelCase(
+      // 获取和目录深度无关的文件名
+      fileName
+        .split("/")
+        .pop()!
+        .replace(/\.\w+$/, "")
+    )
+  );
+  // 全局注册组件
+  Vue.component(componentName, componentConfig.default || componentConfig);
+});

+ 3 - 0
src/layout/components/footer.vue

@@ -0,0 +1,3 @@
+<template>
+  <div>footer</div>
+</template>

+ 13 - 0
src/layout/components/header.vue

@@ -0,0 +1,13 @@
+<template>
+  <div class="header">工具箱</div>
+</template>
+<style lang="scss" scoped>
+.header {
+  height: 50px;
+  line-height: 50px;
+  font-size: 18px;
+  color: #fff;
+  text-align: center;
+  background: #e8151c;
+}
+</style>

+ 31 - 0
src/layout/index.vue

@@ -0,0 +1,31 @@
+<template>
+  <div class="container">
+    <keep-alive>
+      <router-view class="flex1" />
+    </keep-alive>
+  </div>
+</template>
+<script lang="ts">
+import { Component, Vue, Watch } from "vue-property-decorator";
+import axios from "axios";
+declare let wx: any;
+@Component({
+  components: {
+  }
+})
+export default class extends Vue {
+  userInfo: any = {};
+  @Watch("$route")
+  routechange(to: any, from: any) { }
+  created() { }
+  //判断是否微信环境
+  is_weixn() {
+    let ua: any = navigator.userAgent.toLowerCase();
+    if (ua.match(/MicroMessenger/i) == "micromessenger") {
+      return true;
+    } else {
+      return false;
+    }
+  }
+}
+</script>

+ 131 - 0
src/main.ts

@@ -0,0 +1,131 @@
+import Vue from "vue";
+import App from "./App.vue";
+import router from "./router";
+import store from "./store";
+import "@vant/touch-emulator";
+import "./styles/index.scss";
+import qs from 'qs';
+Vue.prototype.$qs = qs;
+import request from "./utils/request";
+import preventClick from "./utils/clickStatefrom";
+import "./assets/iconfont/iconfont.css";
+import magnetlogadd from "./utils/magnetLogAdd.js";
+Vue.prototype.$magnetlogadd = magnetlogadd;
+import "@/components";
+Vue.use(preventClick);
+import ElDialog from "element-ui/lib/dialog";
+import "element-ui/lib/theme-chalk/dialog.css";
+import ElButton from "element-ui/lib/button";
+import "element-ui/lib/theme-chalk/button.css";
+import ElInput from "element-ui/lib/input";
+import "element-ui/lib/theme-chalk/input.css";
+import ElForm from "element-ui/lib/form";
+import "element-ui/lib/theme-chalk/form.css";
+import ElFormItem from "element-ui/lib/form-item";
+import "element-ui/lib/theme-chalk/form-item.css";
+import ElRow from "element-ui/lib/row";
+import "element-ui/lib/theme-chalk/row.css";
+import ElCol from "element-ui/lib/col";
+import "element-ui/lib/theme-chalk/col.css";
+import ElSelect from "element-ui/lib/select";
+import "element-ui/lib/theme-chalk/select.css";
+import ElOption from "element-ui/lib/option";
+import "element-ui/lib/theme-chalk/option.css";
+import ElCollapse from "element-ui/lib/collapse";
+import "element-ui/lib/theme-chalk/collapse.css";
+import ElCollapseItem from "element-ui/lib/collapse-item";
+import "element-ui/lib/theme-chalk/collapse-item.css";
+import ElImage from "element-ui/lib/image";
+import "element-ui/lib/theme-chalk/image.css";
+Vue.component("el-dialog", ElDialog);
+Vue.component("el-button", ElButton);
+Vue.component("el-select", ElSelect);
+Vue.component("el-option", ElOption);
+Vue.component("el-input", ElInput);
+Vue.component("el-form", ElForm);
+Vue.component("el-form-item", ElFormItem);
+Vue.component("el-row", ElRow);
+Vue.component("el-col", ElCol);
+Vue.component('el-collapse', ElCollapse);
+Vue.component('el-collapse-item', ElCollapseItem);
+Vue.component('el-image', ElImage);
+
+import {
+  Swipe,
+  SwipeItem,
+  Col,
+  Row,
+  Form,
+  Field,
+  Button,
+  Toast,
+  PullRefresh,
+  Loading,
+  RadioGroup,
+  Radio,
+  NavBar,
+  Icon,
+  Popup,
+  Dialog,
+  NoticeBar,
+  Tab,
+  Tabs,
+  List,
+  Cell,
+  CellGroup,
+  Grid,
+  GridItem,
+  Image,
+  Uploader,
+  Empty,
+  Checkbox,
+  CheckboxGroup,
+  ActionSheet,
+  Search,
+  Overlay
+} from "vant";
+
+[
+  request,
+  Swipe,
+  SwipeItem,
+  Col,
+  Row,
+  Form,
+  Field,
+  Button,
+  Toast,
+  PullRefresh,
+  Loading,
+  NavBar,
+  RadioGroup,
+  Radio,
+  Icon,
+  ElDialog,
+  Popup,
+  Dialog,
+  NoticeBar,
+  Tab,
+  Tabs,
+  List,
+  Cell,
+  CellGroup,
+  Grid,
+  GridItem,
+  Image,
+  Uploader,
+  Empty,
+  Checkbox,
+  CheckboxGroup,
+  ActionSheet,
+  Search,
+  Overlay
+].forEach(x => Vue.use(x));
+
+Vue.config.productionTip = false;
+Vue.prototype.$title = process.env.VUE_APP_PublicTitle;
+new Vue({
+  router,
+  store,
+  render: h => h(App)
+}).$mount("#app");

+ 119 - 0
src/router/index.ts

@@ -0,0 +1,119 @@
+import Vue from "vue";
+import VueRouter from "vue-router";
+import layout from "@/layout/index.vue";
+import { checkLoginStatus, initGuidInfo, doWecomLogin, getQyCode } from '@/utils/wecomLogin.ts';
+Vue.use(VueRouter);
+
+const router = new VueRouter({
+  mode: process.env.NODE_ENV !== "development" ? "history" : "history",
+  base: process.env.BASE_URL,
+  scrollBehavior(to, from, savedPosition) {
+    if (savedPosition) {
+      return savedPosition;
+    } else {
+      return { x: 0, y: 0 };
+    }
+  },
+  routes: [
+    {
+      path: "/",
+      component: layout,
+      redirect: "/AIDesign",
+      children: [
+        {
+          path: "/AIDesign",
+          component: () => import("../views/AIDesign/index.vue"),
+          meta: { requiresAuth: true } // 标记需要登录的页面
+        },
+        {
+          path: "/login",
+          component: () => import("../views/login/index.vue"),
+          meta: { title: "登录" }
+        },
+        {
+          path: "/error/:code",
+          component: () => import("../views/errorPage/index.vue")
+        },
+        {
+          path: "/error",
+          component: () => import("../views/errorPage/weixinerr.vue")
+        },
+        //设计页
+        {
+          path: "/AIDesign/design",
+          component: () => import("../views/AIDesign/design.vue")
+        },
+        //结果页
+        {
+          path: "/AIDesign/result",
+          component: () => import("../views/AIDesign/result.vue"),
+          meta: { requiresAuth: true } // 标记需要登录的页面
+        },
+        //历史页
+        {
+          path: "/AIDesign/history",
+          component: () => import("../views/AIDesign/history.vue")
+        },
+        //内墙-设计页
+        {
+          path: "/AIDesign/insideDesign",
+          component: () => import("../views/AIDesign/insideDesign.vue")
+        },
+        //一键诊断-生成页
+        {
+          path: "/AIDesign/diagnose",
+          component: () => import("../views/AIDesign/diagnose.vue")
+        },
+        //一键诊断-历史页
+        {
+          path: "/AIDesign/diagnoseHistory",
+          component: () => import("../views/AIDesign/diagnoseHistory.vue")
+        },
+        //一键诊断-结果页
+        {
+          path: "/AIDesign/diagnoseResult",
+          component: () => import("../views/AIDesign/diagnoseResult.vue"),
+          meta: { requiresAuth: true } // 标记需要登录的页面
+        }
+      ]
+    },
+  ]
+});
+// 全局前置守卫:只对需要登录的页面进行登录校验
+router.beforeEach((to, from, next) => {
+  if (!to.meta || (to.meta && !to.meta.requiresAuth)) {
+    next();
+    return;
+  }
+  try {
+    initGuidInfo();
+    const isLoggedIn = checkLoginStatus();
+    if (isLoggedIn) {
+      next();
+      return;
+    }
+    const code = to.query.code as string;
+    if (code) {
+      doWecomLogin(code)
+        .then(() => {
+          console.log(`登录成功,即将进入 ${to.path}`);
+        })
+        .catch(() => {
+          next({ path: "/error" });
+        });
+    } else {
+      // console.log(`访问 ${to.path} 需登录,正在跳转到授权页面`);
+      // getQyCode();
+      // 本地登录-需注释
+      doWecomLogin('')
+        .then(() => {
+          console.log(`模拟登录成功,即将进入 ${to.path}`);
+        })
+    }
+  } catch (error) {
+    console.error("登录校验过程异常:", error);
+    next({ path: "/error" });
+  }
+});
+
+export default router;

+ 4 - 0
src/store/index.ts

@@ -0,0 +1,4 @@
+import Vue from "vue";
+import Vuex from "vuex";
+Vue.use(Vuex);
+export default new Vuex.Store({});

+ 147 - 0
src/styles/index.scss

@@ -0,0 +1,147 @@
+html {
+  height: 100%;
+
+  @media screen and (max-width: 1400px) {
+    font-size: 62.5%;
+  }
+
+  @media screen and (min-width: 1400px) {
+    font-size: 75%;
+  }
+  // ai设计板块
+  @media screen and (min-width: 900px) {
+    .AI-Design-container {
+      max-width: 900px;
+      padding: 0;
+      margin: 0 auto;
+      overflow: hidden;
+      width:100%;
+    }
+  }
+  body {
+    padding: 0;
+    margin: 0;
+    height: 100%;
+    font-family: "Microsoft YaHei";
+    * {
+      padding: 0;
+      margin: 0;
+      outline: none;
+      list-style-image: none;
+    }
+    .container {
+      width: 100%;
+      //height: 100%;
+      display: flex;
+      flex-flow: column nowrap;
+      overflow: hidden;
+      box-sizing: border-box;
+      color: #333;
+      font-size: 16px;
+    }
+    .fankui-btn-mm{
+      width: 40px;
+      height: 40px;
+      border-radius: 50%;
+      position: fixed;
+      bottom: 50px;
+      right: 50px;
+      z-index: 100;
+      .img{
+        width: 60px;
+        height: 60px;
+      }
+    }
+
+    .flex1 {
+      display: flex;
+      flex-grow: 1;
+    }
+
+    .flex0 {
+      display: flex;
+      flex-shrink: 0;
+    }
+
+    .fixed {
+      position: fixed;
+    }
+
+    .relative {
+      position: relative;
+    }
+
+    .absolute {
+      position: absolute;
+    }
+
+    .flexRow {
+      display: flex;
+      flex-flow: row nowrap !important;
+      flex-shrink: 0;
+    }
+
+    .flexCol {
+      display: flex;
+      flex-flow: column nowrap !important;
+    }
+
+    .flexCenter {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+    }
+
+    .flexWarp {
+      display: flex;
+      flex-flow: row wrap !important;
+    }
+    .jCenter {
+      display: flex;
+      justify-content: center;
+    }
+
+    .aCenter {
+      display: flex;
+      align-items: center;
+    }
+
+    .jcsb {
+      justify-content: space-between;
+    }
+    .oHidden {
+      overflow: hidden;
+    }
+
+    .oScroll {
+      overflow: scroll;
+    }
+
+    .oxScroll {
+      overflow-x: scroll;
+    }
+
+    .oyScroll {
+      overflow-y: scroll;
+    }
+    .fontWhite{
+      color: #FFF;
+    }
+    .fontBlack{
+      color: #333;
+    }
+    .mt10{
+      margin-top: 10px;
+    }
+    .contentDiv{
+      padding: 10px 15px;
+      box-sizing: border-box;
+      background: #F5F5F5;
+    }
+    .login{
+      .van-field__error-message{
+        display: none;
+      }
+    }
+  }
+}

+ 23 - 0
src/types/global.d.ts

@@ -0,0 +1,23 @@
+declare module "*.vue" {
+  import Vue from "vue";
+  export default Vue;
+}
+interface IAny {
+  [index: string]: any;
+}
+interface IError {
+  msg: string;
+  code: number;
+}
+interface IBaseResult<T = any> extends IError {
+  data: T;
+}
+interface IRequest {
+  <T = any>(url: string, data?: any): Promise<IResult<T>>;
+}
+
+interface IResult<T> extends Array<IError | null | T> {
+  0: IError | null;
+  1: T;
+  length: 2;
+}

+ 8 - 0
src/types/index.d.ts

@@ -0,0 +1,8 @@
+import "vue";
+declare module "vue/types/vue" {
+  interface Vue {
+    $post: IRequest;
+    $get: IRequest;
+    $title: string;
+  }
+}

+ 13 - 0
src/types/shims-tsx.d.ts

@@ -0,0 +1,13 @@
+import Vue, { VNode } from "vue";
+
+declare global {
+  namespace JSX {
+    // tslint:disable no-empty-interface
+    interface Element extends VNode {}
+    // tslint:disable no-empty-interface
+    interface ElementClass extends Vue {}
+    interface IntrinsicElements {
+      [elem: string]: any;
+    }
+  }
+}

+ 18 - 0
src/utils/clickStatefrom.js

@@ -0,0 +1,18 @@
+//clickStatefrom.js文件
+export default {
+  install(Vue) {
+    // 防止重复点击
+    Vue.directive("preventClick", {
+      inserted(el, binding) {
+        el.addEventListener("click", () => {
+          if (!el.disabled) {
+            el.disabled = true;
+            setTimeout(() => {
+              el.disabled = false;
+            }, 6000);
+          }
+        });
+      }
+    });
+  }
+};

+ 18 - 0
src/utils/cookies.ts

@@ -0,0 +1,18 @@
+import Cookies from "js-cookie";
+
+const TokenKey = "Token";
+export const auth = {
+  getToken: () => Cookies.get(TokenKey),
+  setToken: (token: string) => Cookies.set(TokenKey, token),
+  removeToken: () => Cookies.remove(TokenKey)
+};
+
+export const login = {
+  get: () => {
+    const x = Cookies.get("Login") || "/user";
+    login.remove();
+    return x;
+  },
+  set: (value: string) => Cookies.set("Login", value),
+  remove: () => Cookies.remove("Login")
+};

+ 6 - 0
src/utils/errorCode.js

@@ -0,0 +1,6 @@
+export default {
+  '401': '认证失败,无法访问系统资源',
+  '403': '当前操作没有权限',
+  '404': '访问资源不存在',
+  'default': '系统未知错误,请反馈给管理员'
+}

+ 72 - 0
src/utils/index.ts

@@ -0,0 +1,72 @@
+import router from "../router";
+export const dateFormat = (fmt: string, x: Date | string) => {
+  const date = typeof x === "string" ? new Date(x) : x;
+  let ret;
+  let opt: IAny = {
+    "Y+": date.getFullYear().toString(), // 年
+    "M+": (date.getMonth() + 1).toString(), // 月
+    "d+": date.getDate().toString(), // 日
+    "h+": date.getHours().toString(), // 时
+    "m+": date.getMinutes().toString(), // 分
+    "s+": date.getSeconds().toString() // 秒
+  };
+  for (let k in opt) {
+    ret = new RegExp("(" + k + ")").exec(fmt);
+    if (ret) {
+      fmt = fmt.replace(
+        ret[1],
+        ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, "0")
+      );
+    }
+  }
+  return fmt;
+};
+
+export const RegAccount = /^[a-zA-Z0-9]{9,16}$/;
+
+export const Dateformat = (t: string | Date, format: string) => {
+  let fmt = format;
+  let ret;
+  const date = typeof t === "string" ? new Date(t) : t;
+  const opt: IAny = {
+    "Y+": date.getFullYear().toString(), // 年
+    "m+": (date.getMonth() + 1).toString(), // 月
+    "d+": date.getDate().toString(), // 日
+    "H+": date.getHours().toString(), // 时
+    "M+": date.getMinutes().toString(), // 分
+    "S+": date.getSeconds().toString() // 秒
+    // 有其他格式化字符需求可以继续添加,必须转化成字符串
+  };
+  for (let k in opt) {
+    ret = new RegExp("(" + k + ")").exec(fmt);
+    if (ret) {
+      fmt = fmt.replace(
+        ret[1],
+        ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, "0")
+      );
+    }
+  }
+  return fmt;
+};
+
+export const getWecomType = (agentFrom: string) => {
+  switch (agentFrom) {
+    case 'ssb':
+      return 0;
+    case 'hbs':
+      return 1;
+    case 'stoneLikePaint':
+      return 2;
+    case 'goldShop':
+      return 3;
+    case 'dg':
+      return 4;
+    default:
+      return 0; // 默认为0
+  }
+}
+
+export const toLBHome = () => {
+  router.replace('/');
+}
+

+ 52 - 0
src/utils/magnetLogAdd.js

@@ -0,0 +1,52 @@
+//埋点
+import axios from "axios";
+
+let magnetLogAdd = {};
+
+magnetLogAdd.setLog = (magnetName,callback) => {
+    let isMobile = '';
+    if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
+        isMobile = '0';
+    }else {
+        isMobile = '1';
+    }
+    let userInfo = JSON.parse(window.localStorage.getItem("userInfoV1"));
+    let agentFrom = window.localStorage.getItem('agentFrom');
+    if (agentFrom != undefined){
+        if (agentFrom == 'hbs'){
+            magnetName = '好邦手' + magnetName;
+        }
+        if (agentFrom == 'ssb'){
+            magnetName = '随身邦' + magnetName;
+        }
+        if (agentFrom == 'stoneLikePaint'){
+            magnetName = '服务商随身邦' + magnetName;
+        }
+        if (agentFrom == 'goldShop'){
+            magnetName = '金牌店随身邦' + magnetName;
+        }
+    }
+    let obj = {
+        userId: userInfo.userId,
+        userName: userInfo.userName,
+        orgCode: userInfo.sysUserExt.orgCode,
+        orgName: userInfo.sysUserExt.orgName,
+        level: userInfo.sysUserExt.salesLevel,
+        whatEnd: isMobile,
+        magnetName: magnetName
+    };
+    if(agentFrom == 'stoneLikePaint' || agentFrom == 'goldShop'){
+        // let loginTypeList = userInfo.loginTypeList?userInfo.loginTypeList:[];
+        // let shopList = [];
+        // loginTypeList.forEach(function (item) {
+        //     if (item.shopType == agentFrom) {
+        //         shopList = item.shopList;
+        //         return
+        //     }
+        // });
+        // obj.level = shopList.length>0?shopList[0].sales_level:''
+    };
+    // axios.post(`${process.env.VUE_APP_BASE_API}/wxportal/magnetLogAdd`,obj,{timeout:5000}).finally(callback);
+}
+
+export default magnetLogAdd;

+ 64 - 0
src/utils/request.ts

@@ -0,0 +1,64 @@
+import Vue from "vue";
+import axios from "axios";
+
+// import md5 from "js-md5";
+
+const instance = axios.create({
+  baseURL: process.env.VUE_APP_BASE_API,
+  timeout: 30000,
+  withCredentials: true
+});
+// const appKey = "cd72c223-923f-44a3-aede-b9f07dcd56b8";
+// const plat = "steelfurniture";
+// const v = "1.0";
+instance.interceptors.request.use(
+  ({ headers: { timestamp = Date.now(), token = "", ...h }, ...x }) => ({
+    headers: {
+      timestamp,
+      // appKey,
+      // plat,
+      // v,
+      // sign: md5(`timestamp${timestamp}plat${plat}v${v}appKey${appKey}`),
+      token,
+      ...h
+    },
+    ...x
+  })
+);
+
+instance.interceptors.response.use(
+  x => x,
+  err => ({
+    data: {
+      code: -100,
+      data: err
+    }
+  })
+);
+const getResult: <T>(x: IBaseResult) => IResult<T> = <T>({
+  data,
+  code,
+  msg
+}: IBaseResult<T>) => {
+  if (code === 0) return [null, data];
+  // Message.error(getErrMsg(code));
+  return [{ code, msg }, (data || {}) as T];
+};
+export const post: IRequest = async <T>(url: string, params: any) => {
+    params.datedate= new Date().getTime();
+    const { data } = await instance.post<IBaseResult<T>>(url, params);
+  return getResult<T>(data);
+};
+export const get: IRequest = async <T>(url: string, params: any) => {
+    params.datedate= new Date().getTime();
+    const {data} = await instance.get<IBaseResult<T>>(url, {params});
+    return getResult<T>(data);
+};
+export default {
+  install(vue: typeof Vue) {
+    Object.assign(vue.prototype, {
+      $get: get,
+      $post: post
+    });
+  }
+};

+ 92 - 0
src/utils/requestAI.js

@@ -0,0 +1,92 @@
+/**
+ * 封装的axios的工具类
+ * 负责请求的公共配置,以及请求拦截,响应拦截,错误处理,网络不佳处理
+ */
+import axios from 'axios'
+import { Toast } from 'vant';
+import errorCode from '@/utils/errorCode'
+
+axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
+const service = axios.create({
+    baseURL: process.env.VUE_APP_AIDESIGN_API + '/standard',
+    timeout: 180000,
+    // withCredentials: true
+});
+// request拦截器
+service.interceptors.request.use(config => {
+    if (config.data instanceof FormData) {
+        // 若未手动设置 Content-Type,则删除默认值(让浏览器自动添加正确的 multipart 头)
+        if (!config.headers['Content-Type']) {
+            delete config.headers['Content-Type'];
+        }
+    }
+    return config
+}, error => {
+    Promise.reject(error)
+})
+
+// 响应拦截器
+service.interceptors.response.use(res => {
+    const code = res.data.code || 200;
+    const msg = errorCode[code] || res.data.msg || errorCode['default']
+    if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
+        return res.data
+    }
+    if (code === 401) {
+        console.log(msg)
+    } else if (code === 500) {
+        Toast(msg);
+        return Promise.reject(new Error(msg))
+    } else if (code !== 200 && code !== 204) {
+        Toast(msg);
+        return Promise.reject('error')
+    } else if (code === 410) {
+        let url, appid, agentid;
+        url = encodeURIComponent(process.env.VUE_APP_AUTHURL);
+        appid = process.env.VUE_APP_APPID;
+        agentid = process.env.VUE_APP_AGENTID;
+        window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${url}&response_type=code&scope=snsapi_base&state=&agentid=${agentid}#wechat_redirect&t=${new Date().getTime()}`;
+    } else {
+        return res.data
+    }
+},
+    error => {
+        console.log('完整错误信息:', error);
+        console.log('错误配置:', error.config);
+        // 1. 获取设备及企业微信信息
+        const userAgent = navigator.userAgent; // 核心信息
+        // console.log("userAgent=", userAgent)
+        // 解析userAgent中的关键信息(可选,方便阅读)
+        const isiOS = /iPhone|iPad|iPod/i.test(userAgent);
+        const isAndroid = /Android/i.test(userAgent);
+        const wxworkVersion = (userAgent.match(/wxwork\/(\d+\.\d+\.\d+)/) || [])[1]; // 企业微信版本号
+        const systemVersion = isiOS ? (userAgent.match(/OS (\d+_\d+)/) || [])[1].replace(/_/g, '.') : (userAgent.match(/Android (\d+\.\d+)/) || [])[1]; // Android版本(如13.0)
+        // iOS版本(如16.5)
+        // 2. 打印/记录设备信息
+        console.log('设备信息:', {
+            userAgent: userAgent, // 原始字符串(用于完整分析)
+            system: isiOS ? 'iOS' : isAndroid ? 'Android' : '未知',
+            systemVersion: systemVersion || '未知',//系统版本
+            wxworkVersion: wxworkVersion || '未知', // 企业微信版本
+            networkType: (navigator.connection && navigator.connection.effectiveType) ||
+                (navigator.connection && navigator.connection.type) ||
+                '未知',
+            timestamp: new Date().toLocaleString() // 报错时间
+        });
+        // console.log('err' + error)
+        let { message } = error;
+        if (message == "Network Error") {
+            message = "网络异常,请切换网络后重试";
+            console.log('触发网络错误的请求URL:', error.config.url);
+        }
+        else if (message.includes("timeout")) {
+            message = "系统接口请求超时";
+        }
+        else if (message.includes("Request failed with status code")) {
+            message = "系统接口" + message.substr(message.length - 3) + "异常";
+        }
+        Toast(message);
+        return Promise.reject(error)
+    }
+)
+export default service

+ 128 - 0
src/utils/wecomLogin.ts

@@ -0,0 +1,128 @@
+
+import { wecomAuth } from "@/api/indexAI";
+import router from '@/router'; // 导入你的路由实例
+// 企业微信登录相关类型定义(无变化,无需可选链)
+export interface GuidInfo {
+    guid: string;
+    time: number; // 时间戳(毫秒)
+}
+
+export interface LastCode {
+    code: string;
+}
+
+export interface WecomAuthResponse {
+    StatusCode: number;
+    Data: {
+        token: string; // AIToken
+    };
+    Message?: string;
+}
+
+
+// 登录中状态锁(避免并发登录请求)
+let isLogging = false;
+
+/**
+ * 校验是否已登录(AIToken 存在 + guidInfo 未过期)
+ * @returns {boolean} 是否已登录
+ */
+export const checkLoginStatus = (): boolean => {
+    const AIToken = window.localStorage.getItem('AIToken');
+    const guidInfoStr = window.localStorage.getItem('guidInfo');
+    if (!AIToken) return false;
+    if (!guidInfoStr) return false;
+    return true;
+    // try {
+    //     const guidInfo: GuidInfo = JSON.parse(guidInfoStr);
+    //     const currentTime = new Date().getTime();
+    //     const expireTime = 1000 * 60 * 60 * 12; // 12 小时过期
+    //     return guidInfo && guidInfo.guid && (currentTime - guidInfo.time) < expireTime;
+    // } catch (error) {
+    //     return false;
+    // }
+};
+
+/**
+ * 初始化 guidInfo
+ */
+export const initGuidInfo = (): void => {
+    let guidInfo = JSON.parse(window.localStorage.getItem("guidInfo"));
+    const currentTime = new Date().getTime();
+    const guid = getGuid();
+    const guidTime = new Date().getTime();
+    const newGuidInfo: GuidInfo = { guid, time: guidTime };
+    // 有缓存但过期-存储
+    if (guidInfo && (currentTime - guidInfo.time) >= (1000 * 60 * 60 * 12)) {
+        window.localStorage.setItem("guidInfo", JSON.stringify(newGuidInfo));
+        window.localStorage.removeItem('lastCode');
+    } else if (!guidInfo) {
+        // 无缓存-存储
+        window.localStorage.setItem('guidInfo', JSON.stringify(newGuidInfo));
+    }
+    console.log("guidInfo=", window.localStorage.getItem('guidInfo'))
+};
+/**
+ * 企业微信登录核心流程(获取 code → 兑换 AIToken)
+ * @param code 企业微信授权返回的 code
+ * @returns {Promise<void>}
+ */
+export const doWecomLogin = async (code: string): Promise<void> => {
+    if (isLogging) return; // 正在登录中,忽略重复调用
+    isLogging = true;
+    try {
+        const lastCodeStr = window.localStorage.getItem('lastCode');
+        const lastCode: LastCode | null = lastCodeStr ? JSON.parse(lastCodeStr) : null;
+        // 同一 code 不重复请求
+        if (lastCode && lastCode.code === code) {
+            isLogging = false;
+            return;
+        }
+
+        // 存储当前 code,避免重复使用
+        window.localStorage.setItem('lastCode', JSON.stringify({ code }));
+
+        // 调用接口兑换 AIToken
+        const res: WecomAuthResponse = await wecomAuth({ code });
+        if (res.StatusCode === 200 && res.Data && res.Data.token) {
+            // 登录成功:存储 AIToken
+            window.localStorage.setItem('AIToken', res.Data.token);
+            isLogging = false;
+            // 重新跳转目标页面(此时登录状态已满足)
+            router.push(router.currentRoute.fullPath);
+        } else if (res.StatusCode === 403) {
+            // 无权限 → 跳错误页
+            isLogging = false;
+            router.push('/error');
+        } else if (res.StatusCode === 410) {
+            // 需重新获取 code → 清除缓存并重定向
+            isLogging = false;
+            window.localStorage.clear();
+            getQyCode(); // 你的获取企业微信二维码/授权链接的函数
+        } else {
+            isLogging = false;
+            // 兼容写法:判断 res.Message 是否存在(去掉 ?.)
+            throw new Error(res.Message ? res.Message : '登录失败');
+        }
+    } catch (error) {
+        isLogging = false;
+        console.error('企业微信登录失败:', error);
+        // 登录失败可提示用户或重试
+        alert('登录失败,请刷新页面重试');
+    }
+};
+
+export const getGuid = () => {
+    return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+        let r = Math.random() * 16 | 0,
+            v = c == 'x' ? r : (r & 0x3 | 0x8);
+        return v.toString(16);
+    });
+}
+export const getQyCode = () => {
+    let url, appid, agentid;
+    url = encodeURIComponent(process.env.VUE_APP_AUTHURL);
+    appid = process.env.VUE_APP_APPID;
+    agentid = process.env.VUE_APP_AGENTID;
+    window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${url}&response_type=code&scope=snsapi_base&state=&agentid=${agentid}#wechat_redirect&t=${new Date().getTime()}`;
+}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1888 - 0
src/views/AIDesign/design.vue


+ 779 - 0
src/views/AIDesign/diagnose.vue

@@ -0,0 +1,779 @@
+<template>
+    <div class="design-container AI-Design-container">
+        <div class="header">
+            <van-nav-bar title="一键诊断" left-arrow @click-left="returnPage" @click-right="toHome">
+                <template #right>
+                    <van-icon name="wap-home-o" color="#333" size="26" />
+                </template>
+            </van-nav-bar>
+        </div>
+        <div class="container">
+            <!-- 历史诊断 -->
+            <div class="history-section">
+                <div class="history-header" @click="viewHistory">
+                    <van-icon name="clock-o" color="#EC8868" />
+                    <span>历史诊断</span>
+                    <span v-if="!readState" class="badge-dot"></span>
+                </div>
+            </div>
+            <div class="diagnoseBox">
+                <img src="../../assets/AIDesign/diagnoseTit.png" class="diagnoseTitBg">
+                <!-- 图片选择 -->
+                <div class="image-selection">
+                    <div class="image-placeholder">
+                        <div v-if="selectedImage" class="selected-image-preview">
+                            <img :src="selectedImage" alt="预览图片" class="preview-image"
+                                @click="imgClick(selectedImage)" />
+                        </div>
+                        <div v-else class="placeholder">
+                            <p class="placeholder-text">请上传一张待诊断的{{ wallType == "outside" ? "外墙" : "内墙" }}房屋照片</p>
+                            <p class="placeholder-text-tit">(避免模糊、光线不佳)</p>
+                        </div>
+                        <div class="image-buttons">
+                            <!-- 原生上传按钮 -->
+                            <div class="upload-container">
+                                <input type="file" accept="image/*" class="native-upload-input"
+                                    @change="handleFileChange">
+                                <button class="image-btn">
+                                    <van-icon name="photo" size="20" />
+                                    <span>选择图片</span>
+                                </button>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+
+
+                <!-- 文字描述 -->
+                <div class="decInfo">
+                    <van-icon name="play" color="#2484F2" size="26" class="triangle" />
+                    <p>上传照片一键诊断空鼓、脱落、开裂等墙面问题,生成可视化报告,推荐工艺及产品整体解决方案。</p>
+                </div>
+                <!-- 一键诊断按钮 -->
+                <div class="generate-section">
+                    <van-button v-show="AIBtnDisabled" type="primary" block color="#2484F2" disabled loading
+                        loading-type="spinner" loading-text="一键诊断"></van-button>
+                    <!-- <van-button v-show="!AIBtnDisabled" type="primary" block @click="generateDesign"
+                        :color="selectedImage ? '#2484F2':'#7F7F7F'" >一键诊断</van-button> -->
+                    <van-button v-show="!AIBtnDisabled" type="primary" block @click="generateDesign"
+                        color="#2484F2">一键诊断</van-button>
+                    <div class="btn-note">*AI建议仅作参考,请结合专业人员现场复核</div>
+                </div>
+            </div>
+        </div>
+        <van-dialog v-model="dialogShow" :show-confirm-button="false">
+            <div class="dialog-box">
+                <div class="dialog-content">{{ dialogContent }}</div>
+                <div class="dialog-btn" @click="dialogShow = false">知道了</div>
+            </div>
+        </van-dialog>
+    </div>
+</template>
+
+<script lang="ts">
+import { Component, Vue } from "vue-property-decorator";
+import { diagCreateDesign, diagGetEntity, diagGetReadState, diagUpdateReadState } from "@/api/indexAI";
+import { ImagePreview } from 'vant';
+import { Dialog } from 'vant';
+import { getWecomType , toLBHome } from '@/utils/index';
+declare let wx: any;
+import axios from "axios";
+
+@Component
+export default class extends Vue {
+    private serviceCodeArray = [];
+    private selectedImage: string | null = null;  // 存储选择的图片
+    private readState = true;
+    private AIBtnDisabled = false;
+    private dialogShow = false;
+    private dialogContent = '';
+    private wallType = '';
+    created() {
+        // this.getServiceCode();
+    }
+    activated() {
+        // 初始化数据
+        this.initialize();
+        this.GetReadStateFn();
+        if (this.$route.query.F_id) {
+            this.GetEntityData(this.$route.query.F_id);
+        }
+    }
+    initialize() {
+        this.serviceCodeArray = [];
+        this.selectedImage = null;
+        this.readState = true;
+        this.AIBtnDisabled = false;
+        this.dialogShow = false;
+        this.dialogContent = '';
+        this.wallType = this.$route.query.wallType || 'outside';
+        this.Userfile1 = null;
+        this.oldf_id = null;
+        sessionStorage.removeItem("diagnoseSelectedImage")
+    }
+    private getServiceCode() {
+        let that = this;
+        const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
+        let serviceCodeArray = [];
+        if (userInfo.loginTypeList.length > 0) {
+            userInfo.loginTypeList.forEach(item => {
+                if (item.shopType == 'stoneLikePaint') {
+                    item.shopList.forEach(childItem => {
+                        serviceCodeArray.push(childItem.shop_code);
+                    })
+                }
+            })
+        }
+        that.serviceCodeArray = serviceCodeArray;
+    }
+    // 处理文件选择(对应 beforeRead + afterRead)
+    handleFileChange(e) {
+        const file = e.target.files[0]; // 获取选中的文件
+        if (!file) return; // 未选择文件直接返回
+
+        // 1. 校验文件类型(对应 beforeRead 的类型检查)
+        if (!file.type.match('image.*')) {
+            this.$toast('请选择图片文件');
+            this.clearInput(e.target); // 清除选择,避免重复触发同一文件
+            return;
+        }
+        let FileSize = (file.size / 1024 / 1024).toFixed(2);
+        // 2. 校验文件大小(对应 beforeRead 的大小检查)
+        const maxSize = 20 * 1024 * 1024; // 10MB
+        if (file.size > maxSize) {
+            this.$toast('图片大小不能超过10MB');
+            this.clearInput(e.target);
+            return;
+        }
+
+        // 3. 处理选中的文件(对应 afterRead)
+        this.handleAfterRead(file);
+
+        // 清除 input 值,确保同一文件能被再次选择
+        this.clearInput(e.target);
+    }
+    // 处理校验通过后的文件(对应 afterRead)
+    handleAfterRead(file) {
+        // 生成图片预览(如果需要,和 van-uploader 的 content 类似)
+        const reader = new FileReader();
+        reader.onload = (event) => {
+            this.selectedImage = event.target.result; // 预览图的 base64
+        };
+        reader.readAsDataURL(file); // 转换为 base64
+
+        this.Userfile1 = file; // 保存原始文件对象(用于后续上传)
+    }
+    // 清除 input 值(解决同一文件无法重复选择的问题)
+    clearInput(input) {
+        input.value = '';
+    }
+
+    private generateDesign() {
+        let that = this;
+        if (!this.Userfile1 && !this.oldf_id) {
+            this.$toast.fail('请选择图片');
+            return;
+        }
+        const formData = new FormData();
+        // const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
+        // let serviceCodeArray = [];
+        // if (userInfo.loginTypeList.length > 0) {
+        //     userInfo.loginTypeList.forEach(item => {
+        //         if (item.shopType == 'stoneLikePaint') {
+        //             item.shopList.forEach(childItem => {
+        //                 serviceCodeArray.push(childItem.shop_code);
+        //             })
+        //         }
+        //     })
+        // }
+        // // 用户企微ID
+        // formData.append('WXuserid', userInfo.loginName);
+        // // 企微类型
+        // const agentFrom = window.localStorage.getItem('agentFromAI');
+        // const wecomType = getWecomType(agentFrom);
+        // formData.append('wecomType', 5);
+        // // 服务商代码
+        // if (serviceCodeArray.length > 0) {
+        //     formData.append('serivceCode', serviceCodeArray.join(','));
+        // }
+        // // 姓名
+        // formData.append('userName', userInfo.userName);
+        // const customerCode = userInfo.sysUserExt && userInfo.sysUserExt.customerCode ? userInfo.sysUserExt.customerCode : '';
+        // // 经销商代码
+        // formData.append('distributorCode', customerCode);
+        // //原服务商用户、新增经销商用户
+        // // 大区
+        // formData.append('regionName', userInfo.officeName || '');
+        // // 公司名称
+        // formData.append('companyName', userInfo.companyName || '');
+        // // 员工号
+        // let employeeID = userInfo.sysUserExt && userInfo.sysUserExt.sapEmployeeId ? userInfo.sysUserExt.sapEmployeeId : '';
+        // formData.append('employeeID', employeeID);
+        // // 立邦员工,返回新增字段(hbs立邦员工);
+        // if (agentFrom === 'hbs') {
+        //     //销售部及ID---立邦员工取值orgName和orgCode
+        //     formData.append('salesDepartment', userInfo.sysUserExt && userInfo.sysUserExt.orgName ? userInfo.sysUserExt.orgName : '');
+        //     formData.append('salesDepartmentCode', userInfo.sysUserExt && userInfo.sysUserExt.orgCode ? userInfo.sysUserExt.orgCode : '');
+        // } else {
+        //     //销售部---原服务商用户、新增经销商用户
+        //     formData.append('salesDepartment', userInfo.subOfficeName || '');
+        //     // 销售部ID
+        //     formData.append('salesDepartmentCode', userInfo.subOfficeCode || '');
+        // }
+        // 样式图片
+        if (this.Userfile1) {
+            formData.append('Userfile1', this.Userfile1);
+        } else {
+            formData.append('oldf_id', this.oldf_id);
+        }
+        // 0外墙 1内墙
+        const Entrytype = this.wallType === 'inside' ? 1 : 0;
+        formData.append('Entrytype', Entrytype);
+        that.AIBtnDisabled = true;
+        // 遍历打印
+        // formData.forEach((value, key) => {
+        //     console.log(`key: ${key}, value: ${value}`);
+        // });
+        diagCreateDesign(formData).then(response => {
+            if (response.StatusCode == 200) {
+                that.AIBtnDisabled = false;
+                sessionStorage.setItem("diagnoseSelectedImage", that.selectedImage)
+                that.$router.push({
+                    path: '/AIDesign/diagnoseResult',
+                    query: {
+                        F_id: response.Data.F_ID,
+                        wallType: that.wallType,
+                    }
+                });
+
+            } else if (response.StatusCode == 410) {
+                that.dialogContent = response.Info;
+                that.AIBtnDisabled = false;
+                that.dialogShow = true;
+            } else {
+                that.AIBtnDisabled = false;
+                that.$toast(response.Info);
+            }
+        })
+            .catch((err) => {
+                that.AIBtnDisabled = false;//ai生成按钮
+            })
+    }
+    imgClick(url) {
+        ImagePreview([url]);
+    }
+
+    GetReadStateFn() {
+        const formData = new FormData();
+        // const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
+        // formData.append('WXuserid', userInfo.loginName);
+        // 0外墙 1内墙
+        const Entrytype = this.wallType === 'inside' ? 1 : 0;
+        formData.append('Entrytype', Entrytype);
+        diagGetReadState(formData).then(response => {
+            if (response.StatusCode == 200) {
+                this.readState = response.Data.readState;
+            }
+        });
+    }
+
+    UpdateReadStateFn() {
+        const formData = new FormData();
+        // const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
+        // formData.append('WXuserid', userInfo.loginName);
+        // 0外墙 1内墙
+        const Entrytype = this.wallType === 'inside' ? 1 : 0;
+        formData.append('Entrytype', Entrytype);
+        diagUpdateReadState(formData).then(response => { });
+    }
+
+    GetEntityData(F_id) {
+        const formData = new FormData();
+        formData.append('F_id', F_id);
+        diagGetEntity(formData).then(response => {
+            if (response.StatusCode == 200) {
+                if (response.Data) {
+                    if (response.Data.F_UserFilePath) {
+                        this.selectedImage = response.Data.F_UserFilePath;
+                    }
+                    this.oldf_id = response.Data.F_ID;
+                }
+            }
+        })
+    }
+    // 添加一个新的辅助方法用于将图片URL转换为File对象
+    private async urlToFile(url: string, filename: string): Promise<File> {
+        try {
+            const response = await fetch(url);
+            const blob = await response.blob();
+            return new File([blob], filename, { type: blob.type });
+        } catch (error) {
+            console.error('图片转换失败:', error);
+            this.$toast('图片加载失败');
+            throw error;
+        }
+    }
+    private viewHistory() {
+        this.UpdateReadStateFn();
+        // 实现查看历史生成逻辑
+        this.$router.push({ path: '/AIDesign/diagnoseHistory', query: { wallType: this.wallType } });
+    }
+    returnPage() {
+        this.$router.push({ path: "/AiDesign" });
+    }
+    toHome() {
+        toLBHome()
+    }
+}
+</script>
+
+<style scoped lang="scss">
+.design-container {
+    /* margin: 0 auto;
+  max-width: 750px; */
+    background-color: rgb(247, 247, 247);
+    min-height: 100vh;
+    flex-direction: column;
+    // overflow: hidden;
+}
+
+.container {
+    // padding: 0 16px;
+    height: 100%;
+}
+
+.top-nav {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 16px 20px;
+    background-color: white;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    position: sticky;
+    top: 0;
+    z-index: 10;
+}
+
+.back-btn,
+.more-btn {
+    width: 40px;
+    height: 40px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    cursor: pointer;
+}
+
+.title {
+    font-size: 15px;
+    font-weight: bold;
+    color: #333;
+}
+
+.history-section {
+    margin: 20px 0 10px;
+    padding: 0 16px;
+    height: 46px;
+}
+
+.history-header {
+    display: flex;
+    align-items: center;
+    gap: 12px;
+    padding: 12px 16px;
+    background-color: #ffffff;
+    border-radius: 8px;
+    font-size: 14px;
+}
+
+.icon-clock {
+    font-size: 12px;
+    margin-right: 8px;
+}
+
+.history-header span {
+    font-weight: 500;
+    color: #EC8868;
+}
+
+.history-header .badge-dot {
+    width: 5px;
+    height: 5px;
+    background-color: #ff4d4f;
+    border-radius: 50%;
+}
+
+.history-content {
+    padding: 20px;
+    border-radius: 8px;
+    background-color: white;
+    text-align: center;
+    // border: 1px dashed #ddd;
+}
+
+.no-history {
+    color: #999;
+    font-size: 12px;
+}
+
+.diagnoseBox {
+    width: 100%;
+    flex: 1;
+    margin: 0 auto;
+    text-align: center;
+    // border-radius: 40px 40px 0 0;
+    // background: linear-gradient(180deg, rgb(250, 250, 250), rgb(247, 247, 247));
+    // border-top: 2px solid #ffffff;
+
+    .image-selection {
+        text-align: center;
+        padding: 0 16px;
+    }
+
+    .image-placeholder {
+        position: relative;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        align-items: center;
+        height: 180px;
+        margin-bottom: 48px;
+        background-color: #ffffff;
+        border-radius: 8px;
+        padding: 10px;
+        padding-bottom: 50px;
+
+        .placeholder {
+            margin-top: 30px;
+        }
+    }
+
+    .selected-image-preview {
+        width: 100%;
+        height: 100%;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+    }
+
+    .preview-image {
+        max-width: 100%;
+        max-height: 100%;
+        object-fit: contain;
+    }
+
+    .placeholder-text {
+        color: #999;
+        font-size: 15px;
+        text-align: center;
+        margin-bottom: 20px;
+        margin-top: 10px;
+    }
+
+    .placeholder-text-tit {
+        color: #999;
+        font-size: 15px;
+        text-align: center;
+        margin-bottom: 20px;
+        margin-top: -10px;
+    }
+
+    .image-buttons {
+        position: absolute;
+        bottom: 10px;
+        display: flex;
+        // gap: 16px;
+        width: 130px;
+        justify-content: center;
+    }
+
+    .image-btn {
+        width: 13rem;
+        padding: 8px 16px;
+        text-align: center;
+        border: none;
+        border-radius: 8px;
+        background-color: rgba(36, 132, 242, 1);
+        color: white;
+        font-size: 16px;
+        height: 3.2rem;
+        line-height: 3.2rem;
+        cursor: pointer;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        gap: 5px;
+        transition: all 0.2s ease;
+
+        i {
+            margin-top: 3px;
+        }
+    }
+
+    .diagnoseTitBg {
+        width: 228px;
+        height: auto;
+        // padding: 18px 0;
+    }
+
+}
+
+
+.design-option {
+    margin: 20px 0;
+}
+
+.option-title {
+    font-size: 15px;
+    font-weight: 600;
+    color: #333;
+    margin-bottom: 12px;
+}
+
+/* 修改为grid布局,实现2x2排列 */
+.option-grid {
+    display: grid;
+    grid-template-columns: repeat(2, 1fr);
+    gap: 10px;
+}
+
+.option-item {
+    padding: 10px;
+    border: 1px solid #ddd;
+    border-radius: 8px;
+    background-color: white;
+    text-align: center;
+    cursor: pointer;
+    transition: all 0.2s ease;
+}
+
+.option-item:hover {
+    transform: translateY(-2px);
+    // box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+}
+
+.option-item.active {
+    border-color: #E96337;
+    /* background-color: #fff8e6; */
+}
+
+.style-image {
+    width: 141px;
+    height: 100px;
+    object-fit: cover;
+    border-radius: 4px;
+    margin-bottom: 8px;
+}
+
+.style-name {
+    font-size: 12px;
+    color: #666;
+}
+
+/* 仿石漆电子色卡特殊样式 - 横向滚动 */
+.stone-colors-grid {
+    display: flex;
+    overflow-x: auto;
+    gap: 12px;
+    padding: 4px;
+    scroll-behavior: smooth;
+    cursor: grab;
+    user-select: none;
+    /* 防止拖拽时选中文本 */
+}
+
+.stone-colors-grid::-webkit-scrollbar {
+    display: none;
+    /* 隐藏滚动条 */
+}
+
+.stone-colors-grid .option-item {
+    width: 50px;
+    height: 80px;
+    flex: 0 0 auto;
+    /* 防止压缩 */
+}
+
+.color-sample {
+    width: 50px;
+    height: 50px;
+    background-size: cover;
+    background-position: center;
+    border-radius: 4px;
+    margin-bottom: 8px;
+}
+
+.color-code {
+    font-size: 12px;
+    color: #666;
+}
+
+.process-icon,
+.split-icon,
+.railing-icon {
+    width: 50px;
+    height: 50px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-bottom: 8px;
+    font-size: 15px;
+}
+
+.split-icon,
+.railing-icon {
+    background-size: contain;
+    background-repeat: no-repeat;
+    background-position: center;
+}
+
+.frame-icon {
+    width: 50px;
+    height: 50px;
+    border-radius: 4px;
+    margin-bottom: 8px;
+}
+
+.tile-color {
+    width: 50px;
+    height: 50px;
+    border-radius: 4px;
+    margin-bottom: 8px;
+}
+
+.process-name,
+.split-name,
+.frame-name,
+.railing-name,
+.tile-name {
+    font-size: 12px;
+    color: #666;
+}
+
+.decInfo {
+    position: relative;
+    padding: 0 20px;
+    margin-bottom: 50px;
+
+    .triangle {
+        position: absolute;
+        top: 0;
+        left: 0;
+    }
+
+    p {
+        padding: 0 10px;
+        line-height: 27.5px;
+        font-size: 15px;
+        text-align: left;
+    }
+
+
+}
+
+.generate-section {
+    // position: fixed;
+    // bottom: 5vh;
+    // left: 5%;
+    width: 90%;
+    margin: 0 auto 50px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    gap: 8px;
+}
+
+
+.btn-text {
+    font-size: 16px;
+    font-weight: bold;
+}
+
+.btn-note {
+    font-size: 12px;
+    color: #999;
+    text-align: center;
+    line-height: 1.2;
+}
+
+.header {
+    /*height: 50px;*/
+    /*line-height: 50px;*/
+    /*text-align: center;*/
+    /*background: #fff;*/
+    border-bottom: 1px solid #f8f8f8;
+
+    .van-nav-bar__title {
+        font-size: 20px;
+        color: #333;
+    }
+
+    .van-icon {
+        font-size: 20px;
+        color: #333 !important;
+    }
+}
+
+.dialog-box {
+    flex-direction: column;
+    display: flex;
+    box-sizing: border-box;
+    position: relative;
+
+    .dialog-content {
+        padding: 20px 20px 10px 20px;
+    }
+
+    .dialog-btn {
+        height: 44px;
+        line-height: 44px;
+        text-align: center;
+        margin: 20px;
+        font-size: 16px;
+        color: #FFFFFF;
+        background-color: #2484F2;
+        border-radius: 10px;
+    }
+}
+
+::v-deep .van-button__loading+.van-button__text {
+    margin-left: 10px;
+}
+
+::v-deep .van-button--block {
+    border-radius: 8px;
+    font-size: 16px;
+}
+
+/* 样式调整:隐藏原生 input,按钮样式保持不变 */
+.upload-container {
+    position: relative;
+    display: inline-block;
+
+    .native-upload-input {
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100%;
+        opacity: 0;
+        cursor: pointer;
+        z-index: 1;
+    }
+
+    .image-btn {
+        padding: 8px 16px;
+        border: none;
+        border-radius: 8px;
+        background-color: #2484F2;
+        color: white;
+        font-size: 12px;
+        cursor: pointer;
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        transition: all 0.2s ease;
+        font-size: 16px;
+    }
+}
+</style>

+ 562 - 0
src/views/AIDesign/diagnoseHistory.vue

@@ -0,0 +1,562 @@
+<template>
+    <div class="resout-container AI-Design-container">
+        <div class="header">
+            <van-nav-bar title="历史诊断" left-arrow @click-left="returnPage" @click-right="toHome">
+                <template #right>
+                    <van-icon name="wap-home-o" color="#333" size="26" />
+                </template>
+            </van-nav-bar>
+        </div>
+        <div class="container">
+            <van-button v-show="Object.keys(groupedImages).length > 0" class="selecBtn" size="small"
+                @click="selectImage">
+                {{ isLongPressing ? "取消" : "选择" }}
+            </van-button>
+
+            <!-- 图片列表 -->
+            <div class="image-groups" v-if="Object.keys(groupedImages).length > 0">
+                <div v-for="(group, date) in groupedImages" :key="date" class="image-group">
+                    <div class="group-header">{{ formatDate(date) }}</div>
+                    <div class="image-grid">
+                        <div v-for="image in group" :key="image.F_ID" class="image-item" @click="toResultPage(image)">
+                            <div v-if="image.StateCode == 2" class="result-image-box">
+                                <van-image lazy-load :src="image.F_UserFilePath" class="house-image" alt="AI设计图"
+                                    fit="cover" radius="5px" />
+                                <p class="WallFinishing" v-if="image.F_WallFinishing">{{ image.F_WallFinishing }}</p>
+                                <p class="WallFinishing"
+                                    v-else-if="image.WallRepairAnalysis && image.WallRepairAnalysis.wallFinishing">{{
+                                        image.WallRepairAnalysis.wallFinishing }}</p>
+                            </div>
+                            <div v-else class="loading-state">
+                                <img v-if="image.StateCode != 3 && image.StateCode != 4"
+                                    src="@/assets/AIDesign/loding.gif" style="width: 50px;">
+                                <p class="loading-text" v-if="image.StateCode == 3 || image.StateCode == 4">生成失败</p>
+                                <p class="loading-text" v-else>图片正在生成中</p>
+                            </div>
+                            <div class="select-indicator" v-if="isLongPressing && image.StateCode == 2">
+                                <div class="select-indicator-circle">
+                                    <span v-if="selectedImages.includes(getImageIndex(image))"
+                                        class="icon-select selected"></span>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+            <!-- 加载状态 -->
+            <div v-if="isLoadingMore" class="loading-more">
+                <van-loading size="20px" />
+                <span class="loading-text">加载更多...</span>
+            </div>
+
+            <van-empty v-else-if="!isLoding && Object.keys(groupedImages).length === 0">
+                <p>暂无数据</p>
+            </van-empty>
+
+            <!-- 已加载全部数据提示 -->
+            <div v-if="!hasMore && !isLoding && Object.keys(groupedImages).length !== 0" class="load-all">
+                已加载全部数据
+            </div>
+
+            <!-- 删除按钮 -->
+            <button class="delete-button" @click="deleteImage" v-if="selectedImages.length > 0">
+                删除图片({{ selectedImages.length }})
+            </button>
+        </div>
+    </div>
+</template>
+
+<script lang="ts">
+import { Component, Vue } from "vue-property-decorator";
+import { diagGetDesignList, diagDeleteEntity } from "@/api/indexAI";
+import { Lazyload, Loading } from 'vant';
+import { toLBHome } from '@/utils/index';
+
+Vue.use(Lazyload);
+Vue.use(Loading);
+
+interface ImageItem {
+    F_ID: string;
+    BaseUrl: string;
+    F_ResultFilePath: string;
+    CreateDate: string;
+    StateCode: number;
+}
+
+@Component
+export default class Resout extends Vue {
+    private images: ImageItem[] = [];
+    private selectedImages: number[] = [];
+    private pressTimer: number | null = null;
+    private isLongPressing = false;
+    private isLoding = true;
+
+    // 分页参数
+    private pagination = {
+        rows: 10, // 每页加载10条,适合移动端
+        page: 1,  // 当前页码
+        sidx: "CreateDate",
+        sord: "desc",
+        records: 0, // 总记录数
+        total: 0    // 总页数
+    };
+
+    // 滚动加载相关状态
+    private isLoadingMore = false; // 是否正在加载更多
+    private hasMore = true; // 是否还有更多数据
+    private isProcessing = false; // 防止重复加载的锁
+    private wallType = '';
+    activated() {
+        // 初始化数据
+        this.initialize();
+        this.getDataInfioList();
+        // 监听滚动事件
+        window.addEventListener('scroll', this.handleScroll);
+    }
+
+    deactivated() {
+        clearTimeout(this.pressTimer);
+        this.pressTimer = null;
+        // 移除滚动监听
+        window.removeEventListener('scroll', this.handleScroll);
+    }
+    initialize() {
+        clearTimeout(this.pressTimer);
+        this.images = [];
+        this.wallType = this.$route.query.wallType || 'outside';
+        this.pagination.page = 1;
+        this.selectedImages = [];
+        this.pressTimer = null;
+        this.isLongPressing = false;
+        this.isLoding = true;
+        this.isLoadingMore = false;
+        this.hasMore = true;
+        this.isProcessing = false; // 防止重复加载的锁
+    }
+
+    // 处理滚动事件
+    private handleScroll() {
+        // 防止重复触发加载
+        if (this.isProcessing || !this.hasMore || this.isLoadingMore) return;
+
+        // 获取滚动相关参数
+        const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
+        const clientHeight = document.documentElement.clientHeight || window.innerHeight;
+        const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
+
+        // 当滚动到距离底部200px时触发加载
+        if (scrollTop + clientHeight >= scrollHeight - 200) {
+            this.loadMoreData();
+        }
+    }
+
+    // 加载更多数据
+    private loadMoreData() {
+        if (this.pagination.page >= this.pagination.total) {
+            this.hasMore = false;
+            return;
+        }
+
+        this.isProcessing = true;
+        this.isLoadingMore = true;
+        this.pagination.page += 1;
+
+        // 延迟执行,优化用户体验
+        setTimeout(() => {
+            this.getDataInfioList(true);
+        }, 300);
+    }
+
+    // 按日期分组逻辑
+    get groupedImages(): Record<string, ImageItem[]> {
+        if (!this.images || this.images.length === 0) return {};
+
+        const groups: Record<string, ImageItem[]> = {};
+        this.images.forEach(image => {
+            const date = image.CreateDate.split('T')[0];
+            if (!groups[date]) {
+                groups[date] = [];
+            }
+            groups[date].push(image);
+        });
+
+        // 按日期倒序排列
+        const sortedGroups: Record<string, ImageItem[]> = {};
+        Object.keys(groups)
+            .sort((a, b) => new Date(b).getTime() - new Date(a).getTime())
+            .forEach(key => {
+                sortedGroups[key] = groups[key];
+            });
+        return sortedGroups;
+    }
+
+    // 获取数据列表 - 支持加载更多
+    getDataInfioList(isLoadMore = false): void {
+        const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
+        // 0外墙 1内墙
+        const Entrytype = this.wallType === 'inside' ? 1 : 0;
+        const queryJson = {
+            // WXuserid: userInfo.loginName,
+            Entrytype
+        };
+        const formData = new FormData();
+        formData.append("pagination", JSON.stringify(this.pagination));
+        formData.append("queryJson", JSON.stringify(queryJson));
+
+        diagGetDesignList(formData).then((res) => {
+            if (res.StatusCode == 200) {
+                // 加载更多时合并数据,否则替换数据
+                this.images = isLoadMore ? [...this.images, ...res.Data.rows] : res.Data.rows;
+                // 更新分页信息
+                this.pagination.records = res.Data.records;
+                this.pagination.total = res.Data.total;
+
+                // 判断是否还有更多数据
+                this.hasMore = this.pagination.page < this.pagination.total;
+            } else {
+                this.$toast.fail(res.Info);
+            }
+
+            // 重置加载状态
+            this.isLoding = false;
+            this.isLoadingMore = false;
+            this.isProcessing = false;
+        }).catch(() => {
+            // 错误处理
+            this.isLoding = false;
+            this.isLoadingMore = false;
+            this.isProcessing = false;
+            this.$toast.fail('加载失败,请重试');
+        });
+    }
+
+    // 其他原有方法保持不变...
+    returnPage() {
+        this.$router.push({ path: '/AIDesign/diagnose', query: { wallType: this.wallType } });
+    }
+    toHome() {
+        toLBHome()
+    }
+    // 去结果页面
+    toResultPage(image) {
+        if (this.isLongPressing && image.StateCode == 2) {
+            this.toggleSelect(this.getImageIndex(image));
+        } else {
+            this.$router.push({
+                path: '/AIDesign/diagnoseResult',
+                query: {
+                    F_id: image.F_ID,
+                    wallType: this.wallType
+                }
+            });
+        }
+    }
+    getImageIndex(image: ImageItem): number {
+        return this.images.findIndex((item: ImageItem) => item.F_ID === image.F_ID);
+    }
+
+    formatDate(dateString: string): string {
+        const date = new Date(dateString);
+        const today = new Date();
+        const yesterday = new Date(today);
+        yesterday.setDate(yesterday.getDate() - 1);
+
+        if (date.toDateString() === today.toDateString()) {
+            return '今天';
+        }
+
+        if (date.toDateString() === yesterday.toDateString()) {
+            return '昨天';
+        }
+
+        if (date.getFullYear() === today.getFullYear()) {
+            return `${date.getMonth() + 1}月${date.getDate()}日`;
+        }
+
+        return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`;
+    }
+
+    selectImage() {
+        this.selectedImages = [];
+        this.isLongPressing = !this.isLongPressing;
+    }
+
+    handleTouchStart(index: number, event: Event): void {
+        event.preventDefault();
+        this.pressTimer = window.setTimeout(() => {
+            this.isLongPressing = true;
+            this.toggleSelect(index);
+        }, 500);
+    }
+
+    handleTouchEnd(index: number): void {
+        if (this.pressTimer) {
+            clearTimeout(this.pressTimer);
+            this.pressTimer = null;
+        }
+
+        if (!this.isLongPressing) {
+            this.toggleSelect(index);
+        } else {
+            const F_ID = this.images[index].F_ID;
+            this.$router.push({
+                path: '/AIDesign/diagnoseResult',
+                query: {
+                    F_id: F_ID,
+                    wallType: this.wallType
+                }
+            });
+        }
+        this.isLongPressing = false;
+    }
+
+    toggleSelect(index: number): void {
+        const idx = this.selectedImages.indexOf(index);
+        if (idx === -1) {
+            this.selectedImages.push(index);
+        } else {
+            this.selectedImages.splice(idx, 1);
+        }
+    }
+
+    saveImage(): void {
+        this.selectedImages.forEach((index) => {
+            if (index < 0 || index >= this.images.length) return;
+            const image = this.images[index];
+            if (!image) return;
+            const imageUrl = image.BaseUrl + image.F_ResultFilePath;
+            this.downloadImage(imageUrl, `ai-design-${image.F_ID}.png`);
+        });
+    }
+
+    downloadImage(imageUrl: string, filename: string): void {
+        fetch(imageUrl).then(response => response.blob()).then(blob => {
+            const blobUrl = URL.createObjectURL(blob);
+            const link = document.createElement('a');
+            link.href = blobUrl;
+            link.download = `ai-design-${new Date().getTime()}.png`;
+            link.style.display = 'none';
+            document.body.appendChild(link);
+            link.click();
+            document.body.removeChild(link);
+            URL.revokeObjectURL(blobUrl);
+        }).catch(error => {
+            console.error('图片下载失败:', error);
+            this.$toast.fail('图片下载失败');
+        });
+    }
+
+    deleteImage(): void {
+        const F_ids = this.selectedImages.map(index => this.images[index].F_ID);
+        const formData = new FormData();
+        formData.append("F_ids", JSON.stringify(F_ids));
+
+        diagDeleteEntity(formData).then((res) => {
+            if (res.StatusCode == 200) {
+                this.$toast.success("删除成功");
+                // 重新加载第一页数据
+                this.pagination.page = 1;
+                this.getDataInfioList();
+                this.selectedImages = [];
+            } else {
+                this.$toast.fail(res.Info);
+            }
+        });
+    }
+
+    beforeDestroy() {
+        if (this.pressTimer) {
+            clearTimeout(this.pressTimer);
+        }
+        window.removeEventListener('scroll', this.handleScroll);
+    }
+}
+</script>
+
+<style scoped lang="scss">
+/* 原有样式保持不变,增加以下样式 */
+// 加载更多样式
+.loading-more {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 20px 0;
+    color: #666;
+
+    .loading-text {
+        margin-left: 8px;
+        font-size: 14px;
+    }
+}
+
+// 加载完成提示
+.load-all {
+    text-align: center;
+    padding: 15px 0;
+    color: #999;
+    font-size: 14px;
+}
+
+/* 其他原有样式... */
+.resout-container {
+    background-color: #f8f9fa;
+    min-height: 100vh;
+    flex-direction: column;
+}
+
+.container {
+    padding: 20px;
+    position: relative;
+
+    .selecBtn {
+        font-size: 14px;
+        width: 50px;
+        position: absolute;
+        right: 20px;
+        top: 14px;
+        border-radius: 8px;
+        background-color: #2484F2;
+        color: #fff;
+    }
+}
+
+.image-groups {
+    flex: 1;
+}
+
+.image-group {
+    margin-bottom: 24px;
+}
+
+.group-header {
+    font-size: 16px;
+    font-weight: 500;
+    color: #333;
+    margin-bottom: 12px;
+    padding-left: 8px;
+}
+
+.image-grid {
+    display: grid;
+    //grid-template-columns: repeat(2, 1fr);
+    //gap: 16px;
+}
+
+.image-item {
+    position: relative;
+    cursor: pointer;
+    margin-bottom: 20px;
+
+    .result-image-box {
+        display: flex;
+        align-items: center;
+
+        .house-image {
+            height: 90px;
+            width: 90px;
+            margin-right: 16px;
+        }
+
+        .WallFinishing {
+            flex: calc(100% - 100px);
+            display: -webkit-box;
+            -webkit-line-clamp: 3;
+            -webkit-box-orient: vertical;
+            overflow: hidden;
+            text-overflow: ellipsis;
+        }
+    }
+}
+
+
+
+
+
+.loading-state {
+    width: 90px;
+    height: 90px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    color: #666;
+    text-align: center;
+    background-image: url('../../assets/AIDesign/bg.png');
+    background-size: 100% 100%;
+    border-radius: 5px;
+}
+
+.loading-text {
+    margin-top: 10px;
+    font-size: 14px;
+    color: white;
+    line-height: 15px;
+    font-size: 11px;
+}
+
+.select-indicator {
+    position: absolute;
+    top: 5px;
+    left: 5px;
+}
+
+.select-indicator-circle {
+    width: 24px;
+    height: 24px;
+    border-radius: 50%;
+    background-color: #B2C4DB;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+.icon-select {
+    width: 10px;
+    height: 10px;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+.icon-select.selected {
+    background-color: #FFFFFF;
+}
+
+.delete-button {
+    position: fixed;
+    bottom: 20px;
+    left: 5%;
+    width: 90%;
+    padding: 12px 16px;
+    background-color: #E96337;
+    border: none;
+    border-radius: 12px;
+    color: white;
+    font-weight: 600;
+    cursor: pointer;
+    transition: all 0.2s ease;
+    text-align: center;
+    font-size: 16px;
+    font-weight: normal;
+}
+
+.delete-button:active {
+    transform: scale(0.98);
+}
+
+.header {
+    border-bottom: 1px solid #f8f8f8;
+
+    .van-nav-bar__title {
+        font-size: 20px;
+        color: #333;
+    }
+
+    .van-icon {
+        font-size: 20px;
+        color: #333 !important;
+    }
+}
+</style>

+ 882 - 0
src/views/AIDesign/diagnoseResult.vue

@@ -0,0 +1,882 @@
+<template>
+    <div class="diagnosis-page AI-Design-container">
+        <!-- 顶部导航 -->
+        <header-online pagetitle="诊断结果"></header-online>
+        <section>
+            <!-- 历史诊断 -->
+            <div class="history-section">
+                <div class="history-header" @click="viewHistory">
+                    <van-icon name="clock-o" color="#EC8868" />
+                    <span>历史诊断</span>
+                    <span v-if="!readState" class="badge-dot"></span>
+                </div>
+            </div>
+            <section class="infoWrapper">
+                <div v-if="canvasImg" class="canvasImgWrapper">
+                    <img :src="canvasImg" alt="">
+                </div>
+                <!-- 诊断内容容器(用于生成图片) -->
+                <!-- <div class="diagnosis-container" ref="diagnosisRef" @touchstart="(e) => startLongPress(e, 'box')"
+                @touchend="endLongPress" @touchcancel="endLongPress" @mousedown="(e) => startLongPress(e, 'box')"
+                @mouseup="endLongPress" @mouseleave="endLongPress"> -->
+                <div class="diagnosis-container" ref="diagnosisRef">
+                    <div class="diagnosis-img-box">
+                        <img src="../../assets/AIDesign/diagnoseTit.png" class="diagnoseTitBg">
+                        <!-- <van-image class="diagnosis-image" :src="UserFilePathUrl" fit="contain" v-if="UserFilePathUrl"
+                            placeholder="加载中..." @click="imgClick(UserFilePathUrl)" id="diagnoseResultImg" /> -->
+                            <img class="diagnosis-image"  :src="UserFilePathUrl" v-show="UserFilePathUrl"
+                             @click="imgClick(UserFilePathUrl)"  style="object-fit: contain;"/>
+                              
+                        <p v-show="!apiLoading && StateCode == 2">该建筑的墙面诊断报告如下,长按可保存分享</p>
+                    </div>
+                    <div class="diagnosis-content" v-if="!apiLoading && wallInfo && wallInfo.wallFinishing">
+                        <div class="diagnosis-box">
+                            <h2>
+                                <van-icon name="play" color="#2484F2" size="24" class="triangle" />
+                                墙面装修类型
+                            </h2>
+                            <div class="content-item">
+                                <p class="item-desc">{{ wallInfo.wallFinishing }}</p>
+                            </div>
+                        </div>
+
+                        <div class="diagnosis-box">
+                            <h2>
+                                <van-icon name="play" color="#2484F2" size="24" class="triangle" />
+                                表面状况
+                            </h2>
+                            <div class="content-item" v-for="(item, index) in wallInfo.surfaceConditions"
+                                :key="'surfaceConditions' + index">
+                                <!-- <span v-show="wallType === 'inside'">{{ index + 1 }}.</span> -->
+                                <p class="item-desc"> {{ item }}</p>
+                            </div>
+                        </div>
+                        <div class="diagnosis-box">
+                            <h2>
+                                <van-icon name="play" color="#2484F2" size="24" class="triangle" />
+                                损坏说明
+                            </h2>
+                            <div class="content-item" v-for="(item, index) in wallInfo.damageNotes"
+                                :key="'damageNotes' + index">
+                                <p class="item-desc">{{ item }}</p>
+                            </div>
+                        </div>
+                        <!-- 外墙-解决方案 -->
+                        <section v-if="wallType === 'outside'">
+                            <div class="diagnosis-box">
+                                <h2>
+                                    <van-icon name="play" color="#2484F2" size="24" class="triangle" />
+                                    解决方案
+                                </h2>
+                                <div class="content-item" v-for="(item, index) in wallInfo.solutions"
+                                    :key="'solutions' + index">
+                                    <h3 class="item-title">{{ numberToChinese(index + 1) }}、{{ item.name }}</h3>
+                                    <div class="item-desc" v-for="(items, indexs) in item.solution"
+                                        :key="'solution' + indexs">
+                                        <h4 class="items-title">{{ indexs + 1 }}.{{ items.title }}</h4>
+                                        <p class="items-desc">{{ items.description }}</p>
+                                    </div>
+                                </div>
+                            </div>
+                        </section>
+                        <!-- 内墙-墙病诊断详情 -->
+                        <section v-if="wallType === 'inside'">
+                            <div class="diagnosis-box">
+                                <h2>
+                                    <van-icon name="play" color="#2484F2" size="24" class="triangle" />
+                                    墙病诊断详情
+                                </h2>
+                                <div class="content-item content-item-detectionDetails"
+                                    v-for="(item, index) in wallInfo.detectionDetails"
+                                    :key="'detectionDetails' + index">
+                                    <div class="reason-title">
+                                        <div class="reason-title-l">{{ index + 1 }}.{{ item.name }} </div>
+                                        <!-- <div class="confidence-badge">
+                                        <van-icon name="info-o" />
+                                        <span class="confidence-text">置信度: </span>
+                                        <span class="confidence-value">{{ (item.confidence * 100).toFixed(0) }}%</span>
+                                    </div> -->
+                                    </div>
+                                    <section>
+                                        <!-- 原因分析 -->
+                                        <div class="detail-title">原因分析</div>
+                                        <div v-for="(cause, i) in item.causes" :key="'causes' + i" :value="cause"
+                                            class="detail-item">
+                                            <van-icon name="location-o" />
+                                            {{ cause }}
+                                        </div>
+                                        <!-- 潜在危害 -->
+                                        <div class="detail-title">潜在危害</div>
+                                        <div v-for="(hazard, i) in item.hazards" :key="'hazards' + i" :value="hazard"
+                                            class="detail-item hazard-item">
+                                            <van-icon name="warning-o" />
+                                            {{ hazard }}
+                                        </div>
+                                        <!-- 修复工艺 -->
+                                        <div class="detail-title">推荐修复工艺</div>
+                                        <div class="process-tags">
+                                            <span v-for="(process, i) in item.repairProcesses"
+                                                :key="'repairProcesses' + i" class="process-tag">
+                                                {{ process }}
+                                            </span>
+                                        </div>
+                                    </section>
+                                </div>
+                            </div>
+                        </section>
+                        <!-- 内墙-解决方案 -->
+                        <section v-if="wallType === 'inside'">
+                            <div class="diagnosis-box">
+                                <h2>
+                                    <van-icon name="play" color="#2484F2" size="24" class="triangle" />
+                                    工艺说明
+                                </h2>
+                                <div class="content-item" v-for="(item, index) in wallInfo.solutions"
+                                    :key="'solutions' + index">
+                                    <h3 class="item-title">{{ numberToChinese(index + 1) }}、{{ item.name }}</h3>
+                                    <p class="item-desc">{{ item.description }}</p>
+                                </div>
+                            </div>
+                        </section>
+                    </div>
+                    <!-- 诊断中 -->
+                    <div v-show="!apiLoading && StateCode == 1" class="diagnoseing-wrapper">
+                        <h3>正在为您飞速诊断...</h3>
+                        <ul>
+                            <li>为了提供给您更好的诊断效果,请避免上传模糊、光线不佳、非{{ wallType == "outside" ? "外墙" : "内墙" }}的图片。</li>
+                            <li>立邦AI诊断建议仅作参考,请结合专业人员现场复核。</li>
+                            <li><span class="blod">无需等待</span>,诊断结果会由<span class="blod">企微推送</span>给您。</li>
+                        </ul>
+                    </div>
+                    <!-- 诊断失败 -->
+                    <div v-show="!apiLoading && (StateCode == 3 || StateCode == 4)" class="diagnoseing-wrapper">
+                        <h3>{{ errDescription }}</h3>
+                        <ul>
+                            <li>为了提供给您更好的诊断效果,请避免上传模糊、光线不佳、非{{ wallType == "outside" ? "外墙" : "内墙" }}的图片。</li>
+                            <li>立邦诊断仅作参考,请结合现场实际情况,由施工团队提出具体落地方案。</li>
+                        </ul>
+                        <p></p>
+                    </div>
+                </div>
+            </section>
+
+            <!-- 保存图片状态提示 -->
+            <van-loading v-if="isSavingImage" class="save-loading" type="spinner" :text="savingText" />
+            <!-- AI设计 -->
+            <div class="generate-section" v-show="!apiLoading && StateCode === 2">
+                <van-button type="primary" block @click="handleAIDesignClick" color="#2484F2">AI设计</van-button>
+            </div>
+            <div class="generate-section" v-show="!apiLoading && (StateCode === 3 || StateCode === 4)">
+                <van-button type="primary" block @click="handleAgainClick" color="#2484F2">重新上传</van-button>
+            </div>
+        </section>
+
+        <!-- 全屏加载遮罩 -->
+        <div class="fullscreen-loading" v-if="isLoading">
+            <van-loading type="spinner" color="#ffffff" size="50" />
+            <p class="loading-text">诊断生成中...</p>
+        </div>
+    </div>
+</template>
+
+<script lang="ts">
+import { Component, Vue, Ref, Watch } from 'vue-property-decorator';
+import html2canvas from 'html2canvas';
+import { NavBar, Button, Image, Loading, Empty, Toast, ImagePreview } from 'vant';
+import { diagGetEntity, diagGetReadState, diagUpdateReadState } from "@/api/indexAI";
+import axios from "axios";
+declare let wx: any;
+@Component({
+    components: {
+        VanNavBar: NavBar,
+        VanButton: Button,
+        VanImage: Image,
+        VanLoading: Loading,
+        VanEmpty: Empty,
+        VanToast: Toast
+    }
+})
+export default class DiagnosisPage extends Vue {
+    @Ref('diagnosisRef') private diagnosisRef!: HTMLElement | null;
+    private designPageApi = {
+        outside: '/AIDesign/design',
+        inside: '/AIDesign/insideDesign'
+    };
+
+    private agentFrom = window.localStorage.getItem('agentFromAI');
+    private UserFilePathUrl = '';//用户原图
+    private pollingTimer: number | null = null; // 轮询定时器引用
+    private timer = null;
+    private StateCode = null;
+    private regenerateDisable = true;
+    private readState = true;
+    private wallType = '';
+    private wallInfo = null;
+    private isLoading = true; // 数据加载状态
+    private apiLoading = true;// 接口加载状态
+    private isSavingImage = false; // 图片保存状态
+    private savingText = '正在保存图片...'; // 保存提示文字
+    private errDescription = '图片模糊/光线不佳,请重新上传';
+    private appearPosterFlag = true;
+    private aiImg = "https://p9-flow-imagex-sign.byteimg.com/tos-cn-i-a9rns2rl98/rc_gen_image/7b6fbb743f984de4b6a2ed36e0b69c95preview.jpeg~tplv-a9rns2rl98-downsize_watermark_1_5_b.png?rcl=202511241033234D2C3B74A04216BD29F0&rk3s=8e244e95&rrcfp=ddbb2dc7&x-expires=2079311619&x-signature=LmTn71nSgdI%2F5kcqJ8L561SedVQ%3D"
+    private longPressTimer: NodeJS.Timeout | null = null; // 长按计时器
+    private canvasImg = null;
+    //开始长按(原生方式)
+    // private startLongPress(e: Event, type: string): void {
+    //     let that = this;
+    //     this.appearPosterFlag = false;
+    //     this.longPressTimer = setTimeout(() => {
+    //         that.handleLongPress(e);
+    //     }, 1000);
+    // }
+
+    //结束长按(原生方式)
+    // private endLongPress(): void {
+    //     this.appearPosterFlag = true;
+    //     if (this.longPressTimer) {
+    //         clearTimeout(this.longPressTimer);
+    //         this.longPressTimer = null;
+    //     }
+
+    // }
+    // 页面挂载时请求数据
+    created() {
+        this.getWxconfig();
+    }
+    activated() {
+        // 初始化数据
+        this.initialize();
+        this.GetReadStateFn();
+        this.GetEntityDataFirst()
+    }
+    deactivated() {
+        clearInterval(this.pollingTimer);
+        clearTimeout(this.timer);
+        clearTimeout(this.longPressTimer);
+        this.pollingTimer = null;
+        this.timer = null;
+        this.longPressTimer = null;
+        sessionStorage.removeItem("diagnoseSelectedImage")
+    }
+    // 初始化数据
+    initialize() {
+        clearInterval(this.pollingTimer);
+        clearTimeout(this.timer);
+        clearTimeout(this.longPressTimer);
+        this.UserFilePathUrl = sessionStorage.getItem("diagnoseSelectedImage") || '';
+        this.pollingTimer = null; // 轮询定时器引用
+        this.timer = null;
+        this.StateCode = null;
+        this.regenerateDisable = true;
+        this.readState = true;
+        this.wallInfo = null;
+        this.isLoading = true; // 数据加载状态
+        this.apiLoading = true;
+        this.isSavingImage = false; // 图片保存状态
+        this.savingText = '正在保存图片...'; // 保存提示文字
+        this.appearPosterFlag = true;
+        this.longPressTimer = null; // 长按计时器 
+        this.wallType = this.$route.query.wallType || 'outside';
+    }
+    //进入页面首次调用获取状态
+    GetEntityDataFirst() {
+        let that = this;
+        const F_ID = this.$route.query.F_id || "";
+        const formData = new FormData();
+        formData.append('F_id', F_ID);
+        diagGetEntity(formData).then(response => {
+            if (response.StatusCode == 200) {
+                if (response.Data == null) {
+                    that.isLoading = false;
+                    that.apiLoading= false;
+                    that.regenerateDisable = true;
+                    that.StateCode = 1;
+                    if (that.timer) {
+                        clearTimeout(that.timer);
+                        that.timer = null;
+                    }
+                    that.timer = setTimeout(() => {
+                        that.startPolling();
+                    }, 20000);
+                } else {
+                    this.StateCode = response.Data.StateCode;
+                    that.UserFilePathUrl = response.Data.F_UserFilePath;
+                    const wallInfoObj = response.Data.wallInfo || '';
+                    const WallRepairAnalysisObj = response.Data.WallRepairAnalysis || '';
+
+                    if (this.wallType === 'outside') {
+                        that.wallInfo = wallInfoObj;
+                    } else if (this.wallType === 'inside') {
+                        that.wallInfo = WallRepairAnalysisObj;
+                    }
+                    // that.isLoading = false;
+                    that.apiLoading = false;
+                    sessionStorage.removeItem("diagnoseSelectedImage");
+                    // 生成图片
+                    that.longPressTimer = setTimeout(() => {
+                        that.handleLongPress();
+                    }, 500);
+                    if (response.Data.StateCode == 1) {
+                        let createTime = new Date(response.Data.CreateDate);
+                        let currentTime = new Date().getTime();
+                        if (currentTime - createTime > 20000) {
+                            that.startPolling();
+                        } else {
+                            if (that.timer) {
+                                clearTimeout(that.timer);
+                                that.timer = null;
+                            }
+                            that.timer = setTimeout(() => {
+                                that.startPolling();
+                            }, currentTime - createTime);
+                        }
+                    } else {
+                        if (response.Data.StateCode == 2 || response.Data.StateCode == 3 || response.Data.StateCode == 4) {
+                            that.regenerateDisable = false;
+                            if (response.Data.Description) {
+                                that.errDescription = response.Data.Description;
+                            }
+                        } else {
+                            that.regenerateDisable = true;
+                        }
+                    }
+                }
+            } else {
+                this.$toast.fail(response.Info);
+                that.isLoading = false;
+                that.apiLoading= false;
+            }
+        })
+    }
+
+    private startPolling(): void {
+        // 立即执行一次检查
+        this.GetEntityData();
+        // 设置定时器每秒执行一次检查
+        this.pollingTimer = window.setInterval(() => {
+            if (!this.wallInfo) {
+                if (this.StateCode == 3 || this.StateCode == 4) {
+                    clearInterval(this.pollingTimer);
+                    this.pollingTimer = null;
+                } else {
+                    this.GetEntityData();
+                }
+
+            } else {
+                if (this.pollingTimer) {
+                    clearInterval(this.pollingTimer);
+                    this.pollingTimer = null;
+                }
+            }
+        }, 3000);
+    }
+    GetEntityData() {
+        let that = this;
+        const F_ID = this.$route.query.F_id || "";
+        const formData = new FormData();
+        formData.append('F_id', F_ID);
+        diagGetEntity(formData).then(response => {
+            if (response.StatusCode == 200) {
+                if (response.Data) {
+                    this.StateCode = response.Data.StateCode;
+                    that.UserFilePathUrl = response.Data.F_UserFilePath;
+                    //   const regex = /^\d+\.\s*/; // 匹配数字+.+空格
+                    if (this.wallType === 'outside') {
+                        that.wallInfo = response.Data.wallInfo || '';
+                    } else if (this.wallType === 'inside') {
+                        that.wallInfo = response.Data.WallRepairAnalysis || '';
+                    }
+                    // that.isLoading = false;
+                    that.apiLoading= false;
+                    sessionStorage.removeItem("diagnoseSelectedImage");
+                    // 生成图片
+                    that.longPressTimer = setTimeout(() => {
+                        that.handleLongPress();
+                    }, 500);
+                    if (response.Data.StateCode == 2 || response.Data.StateCode == 3 || response.Data.StateCode == 4) {
+                        that.regenerateDisable = false;
+                        if (response.Data.Description) {
+                            that.errDescription = response.Data.Description;
+                        }
+                    } else {
+                        that.regenerateDisable = true;
+                    }
+                } else {
+                    that.regenerateDisable = true;
+                }
+            } else {
+                that.isLoading = false;
+                that.apiLoading= false;
+                this.$toast.fail(response.Info);
+            }
+        })
+    }
+
+    imgClick(url) {
+        ImagePreview([url]);
+    }
+    // 获取微信API授权信息
+    getWxconfig() {
+        const jsApiList = ['getSetting', 'authorize', 'showModal', 'openSetting', 'downloadFile', 'saveImageToPhotosAlbum'];
+        let url = window.location.href.split("#")[0];
+        axios.get(`${process.env.VUE_APP_BASE_API}wx/ticket`, {
+            params: {
+                url: url,
+                agent: 1
+            }
+        }).then(response => {
+            if (response.status == 200) {
+                let qiyeData = response.data.data;
+                wx.agentConfig({
+                    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
+                    corpid: qiyeData.appId, // 必填,企业微信的corpid,必须与当前登录的企业一致
+                    agentid: qiyeData.agentId, // 必填,企业微信的应用id (e.g. 1000247)
+                    timestamp: qiyeData.timestamp, // 必填,生成签名的时间戳
+                    nonceStr: qiyeData.nonceStr, // 必填,生成签名的随机串
+                    signature: qiyeData.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法
+                    jsApiList: [...jsApiList], //必填,传入需要使用的接口名称
+                    success: function (res) {
+                        console.log('获取签名成功');
+                    },
+                    fail: function (res) {
+                        console.log(res);
+                        if (res.errMsg.indexOf('function not exist') > -1) {
+                            alert('版本过低请升级');
+                        }
+                    },
+                });
+            }
+        });
+    }
+
+    GetReadStateFn() {
+        const formData = new FormData();
+        // const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
+        // formData.append('WXuserid', userInfo.loginName);
+        // 0外墙 1内墙
+        const Entrytype = this.wallType === 'inside' ? 1 : 0;
+        formData.append('Entrytype', Entrytype);
+        diagGetReadState(formData).then(response => {
+            if (response.StatusCode == 200) {
+                this.readState = response.Data.readState;
+            }
+        });
+    }
+
+    // 跳转AI设计页面
+    private handleAIDesignClick() {
+        // this.$router.push({ path: this.designPageApi[this.wallType], query: { from: 'diagnoseResult', diagnoseResultImg: this.UserFilePathUrl } });
+        this.$router.push({ path: this.designPageApi[this.wallType], query: { from: 'diagnoseResult' } });
+    }
+    // 重新上传
+    private handleAgainClick() {
+        this.$router.push({ path: '/AIDesign/diagnose', query: { F_id: this.$route.query.F_id } });
+
+    }
+    // 历史生成
+    private viewHistory() {
+        this.UpdateReadStateFn();
+        // 实现查看历史生成逻辑
+        this.$router.push({ path: '/AIDesign/diagnoseHistory', query: { wallType: this.wallType } });
+    }
+    // 更新未读状态
+    UpdateReadStateFn() {
+        const formData = new FormData();
+        // const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
+        // formData.append('WXuserid', userInfo.loginName);
+        // 0外墙 1内墙
+        const Entrytype = this.wallType === 'inside' ? 1 : 0;
+        formData.append('Entrytype', Entrytype);
+        diagUpdateReadState(formData).then(response => { });
+    }
+    // 转化汉字排序
+    private numberToChinese(num: number): string {
+        const chineseNumbers = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
+        if (num <= 10) {
+            return chineseNumbers[num];
+        }
+        const shi = Math.floor(num / 10);
+        const ge = num % 10;
+        if (ge === 0) {
+            return chineseNumbers[shi] + '十';
+        } else {
+            return chineseNumbers[shi] + '十' + chineseNumbers[ge];
+        }
+    }
+
+    // 长按诊断区域生成图片
+    private async handleLongPress(e: Event): void {
+        let that = this;
+        if (!this.diagnosisRef) {
+            this.$toast('未找到诊断内容');
+            that.isLoading = false;
+            return;
+        }
+        // this.isSavingImage = true;
+        try {
+            // 使用html2canvas将DOM转为canvas
+            const canvas = await html2canvas(this.diagnosisRef, {
+                scale: 3, // 提高清晰度(2倍缩放)
+                useCORS: true, // 允许跨域图片
+                allowTaint: true,
+                logging: true, // 关闭日志false
+                backgroundColor: '#ffffff', // 背景色
+            });
+
+            // 转为图片URL
+            const imageUrl = canvas.toDataURL('image/png');
+            this.canvasImg = imageUrl;
+            that.isLoading = false;
+            clearTimeout(this.longPressTimer);
+            this.longPressTimer = null;
+            // 保存图片到手机
+            // await this.saveImageToGallery(imageUrl);
+            // this.savingText = '保存成功';
+        } catch (error) {
+            that.isLoading = false;
+            // console.error('图片生成/保存失败:', error);
+            // this.savingText = '保存失败';
+            // this.$toast('保存失败,请重试');
+        } finally {
+            that.isLoading = false;
+            // 延迟关闭加载提示,确保用户看到结果
+            // setTimeout(() => {
+            //     this.isSavingImage = false;
+            //     this.savingText = '正在保存图片...';
+            // }, 1500);
+        }
+    }
+
+    // 保存图片到手机相册(适配移动端)
+    private async saveImageToGallery(imageUrl: string) {
+        // 1. 若在H5环境:创建a标签触发下载
+        if (typeof window !== 'undefined') {
+            const link = document.createElement('a');
+            link.href = imageUrl;
+            link.download = '墙面诊断报告.png';
+            link.click();
+            return;
+        }
+    }
+}
+</script>
+
+<style scoped lang="scss">
+.diagnosis-page {
+    background-color: #f8f9fa;
+    min-height: 100vh;
+    flex-direction: column;
+
+    // ul {
+    //     list-style-type: disc;
+    // }
+    .history-section {
+        margin: 10px 0;
+        padding: 0 16px;
+        height: 46px;
+
+        .history-header {
+            display: flex;
+            align-items: center;
+            gap: 12px;
+            padding: 12px 16px;
+            background-color: #ffffff;
+            border-radius: 8px;
+            font-size: 14px;
+        }
+
+        .icon-clock {
+            font-size: 12px;
+            margin-right: 8px;
+        }
+
+        .history-header span {
+            font-weight: 500;
+            color: #EC8868;
+        }
+
+        .history-header .badge-dot {
+            width: 5px;
+            height: 5px;
+            background-color: #ff4d4f;
+            border-radius: 50%;
+        }
+    }
+
+    .infoWrapper {
+        position: relative;
+
+        .canvasImgWrapper {
+            position: absolute;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 100%;
+            z-index: 2;
+            opacity: 0;
+            img {
+                width: 100%;
+                height: 100%;
+            }
+        }
+    }
+
+    // 诊断内容容器(长按区域)
+    .diagnosis-container {
+        margin: 0 15px;
+        padding: 20px 0;
+        background-color: #ffffff;
+        border-radius: 12px;
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+        cursor: pointer;
+        position: relative;
+        user-select: none;
+        /* 可选:禁止选中文字 */
+
+        // 诊断图片
+        .diagnosis-img-box {
+            padding: 0 20px;
+            text-align: center;
+            margin-bottom: 30px;
+            pointer-events: none;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            img{
+                display: block;
+            }
+            .diagnoseTitBg {
+                width: 228px;
+                height: auto;
+                margin:0 auto 15px;
+
+            }
+
+            .diagnosis-image {
+                width: 60%;
+                height: auto;
+            }
+
+            p {
+                color: #86909C;
+                font-size: 14px;
+            }
+
+        }
+
+        // 内容列表
+        .diagnosis-content {
+            .diagnosis-box {
+                // border-bottom: 1px solid #f0f0f0;
+                margin-bottom: 15px;
+                padding-bottom: 15px;
+
+                h2 {
+                    font-size: 20px;
+                }
+
+                .content-item {
+                    margin-top: 10px;
+
+                    &:last-child {
+                        border-bottom: none;
+                        margin-bottom: 0;
+                        padding-bottom: 0;
+                    }
+
+                    .item-title {
+                        font-size: 16px;
+                        color: #333333;
+                        margin: 15px 0 8px;
+                        font-weight: bold;
+                    }
+
+                    .item-desc {
+                        font-size: 14px;
+                        color: #333;
+                        line-height: 1.4;
+                        margin: 10px 0;
+                    }
+
+                    .item-title,
+                    .item-desc {
+                        padding: 0 34px;
+
+                    }
+
+                    .items-title {
+                        font-size: 14px;
+                        margin-bottom: 8px;
+                    }
+
+                    .items-desc {
+                        color: #696868;
+                        padding: 0 10px;
+                    }
+                }
+
+                .content-item-detectionDetails {
+                    padding: 0 34px;
+                    margin-bottom: 30px;
+
+                    .reason-title {
+                        color: #333;
+                        display: flex;
+                        justify-content: space-between;
+                        // align-items: center;
+                        align-items: flex-start;
+
+                        .reason-title-l {
+                            margin: 5px 0 0 0;
+                            font-size: 16px;
+                            font-weight: 600;
+                            color: #262626;
+                            line-height: 30px;
+                        }
+
+                        .confidence-badge {
+                            background: #f0f7ff;
+                            border: 1px solid #91d5ff;
+                            border-radius: 16px;
+                            padding: 2px 6px;
+                            font-size: 10px;
+                            color: #1890ff;
+                            white-space: nowrap;
+                            flex-shrink: 0;
+                            display: flex;
+                            align-items: center;
+                            gap: 4px;
+                            cursor: help;
+                            position: relative;
+                            margin-top: 12px;
+                        }
+
+                    }
+
+                    .detail-title {
+                        font-size: 14px;
+                        font-weight: 600;
+                        color: #434343;
+                        margin: 10px 0 8px 0;
+                        display: flex;
+                        align-items: center;
+
+                    }
+
+                    .detail-title::before {
+                        content: '';
+                        width: 4px;
+                        height: 14px;
+                        background: #1890ff;
+                        border-radius: 2px;
+                        margin-right: 6px;
+                        margin-left: 4px;
+                    }
+
+                    .detail-item {
+                        padding: 4px;
+                        position: relative;
+                        font-size: 14px;
+                        line-height: 1.5;
+                        color: #666;
+                    }
+
+                    .process-tags {
+                        display: flex;
+                        flex-wrap: wrap;
+                        gap: 6px;
+                        padding: 0 4px;
+
+                        .process-tag {
+                            background: #ffffff;
+                            border: 1px solid #EC8868;
+                            color: #EC8868;
+                            padding: 4px 12px;
+                            border-radius: 16px;
+                            font-size: 12px;
+                            font-weight: 500;
+                        }
+                    }
+
+                }
+            }
+        }
+
+        // 加载状态
+        .loading {
+            display: block;
+            margin: 40px auto;
+        }
+    }
+
+    // 保存图片加载提示
+    .save-loading {
+        position: fixed;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%, -50%);
+        background-color: rgba(0, 0, 0, 0.7);
+        padding: 15px 20px;
+        border-radius: 8px;
+    }
+
+    .generate-section {
+        width: 90%;
+        margin: 20px auto 50px;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        gap: 8px;
+        border-radius: 8px;
+        overflow: hidden;
+    }
+
+    .fullscreen-loading {
+        position: fixed;
+        top: 0;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        background-color: rgba(0, 0, 0, 0.7); // 半透明遮罩
+        z-index: 9999; // 确保在最上层
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        backdrop-filter: blur(7px);
+
+        .loading-text {
+            margin-top: 16px;
+            color: #fff;
+            font-size: 15px;
+        }
+    }
+
+    // 诊断中
+    .diagnoseing-wrapper {
+        padding: 0 20px;
+        text-align: left;
+
+        h3 {
+            font-size: 18px;
+            font-weight: bold;
+
+        }
+
+        ul {
+            padding-top: 20px;
+            font-size: 14px;
+            list-style-type: disc;
+            padding-left: 16px;
+
+            li {
+                line-height: 20px;
+
+                .blod {
+                    font-weight: bold;
+                }
+            }
+        }
+    }
+}
+</style>

+ 536 - 0
src/views/AIDesign/history.vue

@@ -0,0 +1,536 @@
+<template>
+  <div class="resout-container AI-Design-container">
+    <div class="header">
+      <van-nav-bar title="历史生图" left-arrow @click-left="returnPage" @click-right="toHome">
+        <template #right>
+          <van-icon name="wap-home-o" color="#333" size="26" />
+        </template>
+      </van-nav-bar>
+    </div>
+    <div class="container">
+      <van-button class="selecBtn" size="small" @click="selectImage">
+        {{ isLongPressing ? "取消" : "选择" }}
+      </van-button>
+
+      <!-- 图片列表 -->
+      <div class="image-groups" v-if="Object.keys(groupedImages).length > 0">
+        <div v-for="(group, date) in groupedImages" :key="date" class="image-group">
+          <div class="group-header">{{ formatDate(date) }}</div>
+          <div class="image-grid">
+            <div v-for="image in group" :key="image.F_ID" class="image-item" @click="() => {
+              if (isLongPressing && image.StateCode == 2) {
+                toggleSelect(getImageIndex(image));
+              } else {
+                $router.push({
+                  path: '/AIDesign/result',
+                  query: {
+                    F_id: image.F_ID,
+                    fromPage: 'history',
+                    wallType,
+                    projectid: image.ProjectID || null
+                  }
+                });
+              }
+            }">
+              <van-image lazy-load v-if="image.StateCode == 2" :src="image.BaseUrl + image.F_ResultSmallFilePath"
+                class="house-image" alt="AI设计图" fit="cover" radius="8px" />
+              <div v-else class="loading-state">
+                <img v-if="image.StateCode != 3 && image.StateCode != 4" src="@/assets/AIDesign/loding.gif"
+                  style="width: 50px;">
+                <p class="loading-text" v-if="image.StateCode == 3 || image.StateCode == 4">生成失败</p>
+                <p class="loading-text" v-else>图片正在生成中</p>
+              </div>
+              <div class="select-indicator" v-if="isLongPressing && image.StateCode == 2">
+                <div class="select-indicator-circle">
+                  <span v-if="selectedImages.includes(getImageIndex(image))" class="icon-select selected"></span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- 加载状态 -->
+      <div v-if="isLoadingMore" class="loading-more">
+        <van-loading size="20px" />
+        <span class="loading-text">加载更多...</span>
+      </div>
+
+      <van-empty v-else-if="!isLoding && Object.keys(groupedImages).length === 0">
+        <p>暂无数据</p>
+      </van-empty>
+
+      <!-- 已加载全部数据提示 -->
+      <div v-if="!hasMore && !isLoding" class="load-all">
+        已加载全部数据
+      </div>
+
+      <!-- 删除按钮 -->
+      <button class="delete-button" @click="deleteImage" v-if="selectedImages.length > 0">
+        删除图片({{ selectedImages.length }})
+      </button>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Vue } from "vue-property-decorator";
+import { GetDesignList, DeleteEntity, insideGetDesignList, insideDeleteEntity } from "@/api/indexAI";
+import { Lazyload, Loading } from 'vant';
+import { toLBHome } from '@/utils/index';
+
+Vue.use(Lazyload);
+Vue.use(Loading);
+
+interface ImageItem {
+  F_ID: string;
+  BaseUrl: string;
+  F_ResultFilePath: string;
+  CreateDate: string;
+  StateCode: number;
+}
+
+@Component
+export default class Resout extends Vue {
+  private images: ImageItem[] = [];
+  private selectedImages: number[] = [];
+  private pressTimer: number | null = null;
+  private isLongPressing = false;
+  private isLoding = true;
+  private wallType = '';
+  // 处理内外墙api
+  private GetDesignListToApi = {
+    outside: GetDesignList,
+    inside: insideGetDesignList
+  };
+  private DeleteEntityToApi = {
+    outside: DeleteEntity,
+    inside: insideDeleteEntity
+  };
+  // 分页参数
+  private pagination = {
+    rows: 10, // 每页加载10条,适合移动端
+    page: 1,  // 当前页码
+    sidx: "CreateDate",
+    sord: "desc",
+    records: 0, // 总记录数
+    total: 0    // 总页数
+  };
+
+  // 滚动加载相关状态
+  private isLoadingMore = false; // 是否正在加载更多
+  private hasMore = true; // 是否还有更多数据
+  private isProcessing = false; // 防止重复加载的锁
+  private designPageApi = {
+    outside: '/AIDesign/design',
+    inside: '/AIDesign/insideDesign'
+  };
+  activated() {
+    this.wallType = this.$route.query.wallType || 'outside';
+    // 重置状态
+    this.images = [];
+    this.pagination.page = 1;
+    this.hasMore = true;
+    this.getDataInfioList();
+    // 监听滚动事件
+    window.addEventListener('scroll', this.handleScroll);
+  }
+
+  deactivated() {
+    clearTimeout(this.pressTimer);
+    this.pressTimer = null;
+    // 移除滚动监听
+    window.removeEventListener('scroll', this.handleScroll);
+  }
+
+  // 处理滚动事件
+  private handleScroll() {
+    // 防止重复触发加载
+    if (this.isProcessing || !this.hasMore || this.isLoadingMore) return;
+
+    // 获取滚动相关参数
+    const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
+    const clientHeight = document.documentElement.clientHeight || window.innerHeight;
+    const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
+
+    // 当滚动到距离底部200px时触发加载
+    if (scrollTop + clientHeight >= scrollHeight - 200) {
+      this.loadMoreData();
+    }
+  }
+
+  // 加载更多数据
+  private loadMoreData() {
+    if (this.pagination.page >= this.pagination.total) {
+      this.hasMore = false;
+      return;
+    }
+
+    this.isProcessing = true;
+    this.isLoadingMore = true;
+    this.pagination.page += 1;
+
+    // 延迟执行,优化用户体验
+    setTimeout(() => {
+      this.getDataInfioList(true);
+    }, 300);
+  }
+
+  // 按日期分组逻辑
+  get groupedImages(): Record<string, ImageItem[]> {
+    if (!this.images || this.images.length === 0) return {};
+
+    const groups: Record<string, ImageItem[]> = {};
+    this.images.forEach(image => {
+      const date = image.CreateDate.split('T')[0];
+      if (!groups[date]) {
+        groups[date] = [];
+      }
+      groups[date].push(image);
+    });
+
+    // 按日期倒序排列
+    const sortedGroups: Record<string, ImageItem[]> = {};
+    Object.keys(groups)
+      .sort((a, b) => new Date(b).getTime() - new Date(a).getTime())
+      .forEach(key => {
+        sortedGroups[key] = groups[key];
+      });
+    return sortedGroups;
+  }
+
+  // 获取数据列表 - 支持加载更多
+  getDataInfioList(isLoadMore = false): void {
+    // const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
+    const queryJson = {
+      // WXuserid: userInfo.loginName
+    };
+
+    const formData = new FormData();
+    formData.append("pagination", JSON.stringify(this.pagination));
+    formData.append("queryJson", JSON.stringify(queryJson));
+
+    this.GetDesignListToApi[this.wallType](formData).then((res) => {
+      if (res.StatusCode == 200) {
+        // 加载更多时合并数据,否则替换数据
+        this.images = isLoadMore ? [...this.images, ...res.Data.rows] : res.Data.rows;
+        // 更新分页信息
+        this.pagination.records = res.Data.records;
+        this.pagination.total = res.Data.total;
+
+        // 判断是否还有更多数据
+        this.hasMore = this.pagination.page < this.pagination.total;
+      } else {
+        this.$toast.fail(res.Info);
+      }
+
+      // 重置加载状态
+      this.isLoding = false;
+      this.isLoadingMore = false;
+      this.isProcessing = false;
+    }).catch(() => {
+      // 错误处理
+      this.isLoding = false;
+      this.isLoadingMore = false;
+      this.isProcessing = false;
+      this.$toast.fail('加载失败,请重试');
+    });
+  }
+
+  getImageIndex(image: ImageItem): number {
+    return this.images.findIndex((item: ImageItem) => item.F_ID === image.F_ID);
+  }
+
+  formatDate(dateString: string): string {
+    const date = new Date(dateString);
+    const today = new Date();
+    const yesterday = new Date(today);
+    yesterday.setDate(yesterday.getDate() - 1);
+
+    if (date.toDateString() === today.toDateString()) {
+      return '今天';
+    }
+
+    if (date.toDateString() === yesterday.toDateString()) {
+      return '昨天';
+    }
+
+    if (date.getFullYear() === today.getFullYear()) {
+      return `${date.getMonth() + 1}月${date.getDate()}日`;
+    }
+
+    return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`;
+  }
+
+  selectImage() {
+    this.selectedImages = [];
+    this.isLongPressing = !this.isLongPressing;
+  }
+
+  handleTouchStart(index: number, event: Event): void {
+    event.preventDefault();
+    this.pressTimer = window.setTimeout(() => {
+      this.isLongPressing = true;
+      this.toggleSelect(index);
+    }, 500);
+  }
+
+  handleTouchEnd(index: number): void {
+    if (this.pressTimer) {
+      clearTimeout(this.pressTimer);
+      this.pressTimer = null;
+    }
+
+    if (!this.isLongPressing) {
+      this.toggleSelect(index);
+    } else {
+      const F_ID = this.images[index].F_ID;
+      this.$router.push({
+        path: '/AIDesign/result',
+        query: {
+          F_id: F_ID,
+          wallType: this.wallType,
+          projectid: this.images[index].ProjectID || null
+        }
+      });
+    }
+    this.isLongPressing = false;
+  }
+
+  toggleSelect(index: number): void {
+    const idx = this.selectedImages.indexOf(index);
+    if (idx === -1) {
+      this.selectedImages.push(index);
+    } else {
+      this.selectedImages.splice(idx, 1);
+    }
+  }
+
+  saveImage(): void {
+    this.selectedImages.forEach((index) => {
+      if (index < 0 || index >= this.images.length) return;
+      const image = this.images[index];
+      if (!image) return;
+      const imageUrl = image.BaseUrl + image.F_ResultFilePath;
+      this.downloadImage(imageUrl, `ai-design-${image.F_ID}.png`);
+    });
+  }
+
+  returnPage() {
+    this.$router.push({ path: this.designPageApi[this.wallType] });
+  }
+  toHome() {
+    toLBHome()
+  }
+  downloadImage(imageUrl: string, filename: string): void {
+    fetch(imageUrl).then(response => response.blob()).then(blob => {
+      const blobUrl = URL.createObjectURL(blob);
+      const link = document.createElement('a');
+      link.href = blobUrl;
+      link.download = `ai-design-${new Date().getTime()}.png`;
+      link.style.display = 'none';
+      document.body.appendChild(link);
+      link.click();
+      document.body.removeChild(link);
+      URL.revokeObjectURL(blobUrl);
+    }).catch(error => {
+      console.error('图片下载失败:', error);
+      this.$toast.fail('图片下载失败');
+    });
+  }
+
+  deleteImage(): void {
+    const F_ids = this.selectedImages.map(index => this.images[index].F_ID);
+    const formData = new FormData();
+    formData.append("F_ids", JSON.stringify(F_ids));
+
+    this.DeleteEntityToApi[this.wallType](formData).then((res) => {
+      if (res.StatusCode == 200) {
+        this.$toast.success("删除成功");
+        // 重新加载第一页数据
+        this.pagination.page = 1;
+        this.getDataInfioList();
+        this.selectedImages = [];
+      } else {
+        this.$toast.fail(res.Info);
+      }
+    });
+  }
+
+  beforeDestroy() {
+    if (this.pressTimer) {
+      clearTimeout(this.pressTimer);
+    }
+    window.removeEventListener('scroll', this.handleScroll);
+  }
+}
+</script>
+
+<style scoped lang="scss">
+/* 原有样式保持不变,增加以下样式 */
+// 加载更多样式
+.loading-more {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 20px 0;
+  color: #666;
+
+  .loading-text {
+    margin-left: 8px;
+    font-size: 14px;
+  }
+}
+
+// 加载完成提示
+.load-all {
+  text-align: center;
+  padding: 15px 0;
+  color: #999;
+  font-size: 14px;
+}
+
+/* 其他原有样式... */
+.resout-container {
+  width: 100%;
+  background-color: #f8f9fa;
+  min-height: 100vh;
+  flex-direction: column;
+}
+
+.container {
+  position: relative;
+  padding: 20px;
+
+  .selecBtn {
+    font-size: 14px;
+    width: 50px;
+    position: absolute;
+    right: 20px;
+    top: 14px;
+    border-radius: 8px;
+    background-color: #2484F2;
+    color: #fff;
+  }
+}
+
+.image-groups {
+  flex: 1;
+}
+
+.image-group {
+  margin-bottom: 24px;
+}
+
+.group-header {
+  font-size: 16px;
+  font-weight: 500;
+  color: #333;
+  margin-bottom: 12px;
+  padding-left: 8px;
+}
+
+.image-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 16px;
+}
+
+.image-item {
+  position: relative;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: #f0eded;
+}
+
+.house-image {
+  height: 150px;
+  width: 100%;
+}
+
+.loading-state {
+  width: 100%;
+  height: 150px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  color: #666;
+  text-align: center;
+  background-image: url('../../assets/AIDesign/bg.png');
+  background-size: 100% 100%;
+}
+
+.loading-text {
+  margin-top: 10px;
+  font-size: 14px;
+  color: white;
+}
+
+.select-indicator {
+  position: absolute;
+  top: 10px;
+  right: 10px;
+}
+
+.select-indicator-circle {
+  width: 24px;
+  height: 24px;
+  border-radius: 50%;
+  background-color: #B2C4DB;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.icon-select {
+  width: 10px;
+  height: 10px;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.icon-select.selected {
+  background-color: #FFFFFF;
+}
+
+.delete-button {
+  position: fixed;
+  bottom: 20px;
+  left: 5%;
+  width: 90%;
+  padding: 12px 16px;
+  background-color: #E96337;
+  border: none;
+  border-radius: 12px;
+  color: white;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.2s ease;
+  text-align: center;
+  font-size: 16px;
+  font-weight: normal;
+}
+
+.delete-button:active {
+  transform: scale(0.98);
+}
+
+.header {
+  border-bottom: 1px solid #f8f8f8;
+
+  .van-nav-bar__title {
+    font-size: 20px;
+    color: #333;
+  }
+
+  .van-icon {
+    font-size: 20px;
+    color: #333 !important;
+  }
+}
+</style>

+ 342 - 0
src/views/AIDesign/index.vue

@@ -0,0 +1,342 @@
+<template>
+  <div class="home-container AI-Design-container">
+    <header-online pagetitle="首页" :showRightIcon="false"></header-online>
+    <!--<div class="header">-->
+    <!--<van-nav-bar title="首页" left-arrow @click-left="returnPage" @click-right="toHome">-->
+    <!--<template #right>-->
+    <!--<van-icon name="wap-home-o" color="#333" size="26" />-->
+    <!--</template>-->
+    <!--</van-nav-bar>-->
+    <!--</div>-->
+    <!-- 顶部装饰背景图 -->
+    <div class="top-bg">
+      <img src="@/assets/AIDesign/top-bg.png" alt="背景图" class="bg-image" />
+    </div>
+
+    <!-- 空间标题 -->
+    <div class="smart-space-title-new">
+      <div class="tab-title" :class="{ active_l: currentTab === 'outside' }" @click="handleTabChange('outside')">
+        <div>外墙空间</div>
+      </div>
+      <div class="tab-title" :class="{ active_r: currentTab === 'inside' }" @click="handleTabChange('inside')">
+        <div>内墙空间</div>
+      </div>
+    </div>
+    <div>
+
+    </div>
+
+    <!-- 外墙-功能卡片区域 -->
+    <div class="feature-cards" v-show="currentTab === 'outside'">
+      <!-- 我要设计 -->
+      <div class="card card-design" @click="handleDesignClick('outside')">
+        <div class="card-content">
+          <div class="card-title" style="color: #512E79;">我要设计</div>
+          <div class="card-desc" style="color: #7F639E;">AI在线生图,快速预览效果</div>
+        </div>
+        <div class="card-icon">
+          <img src="@/assets/AIDesign/design-robot.png" alt="设计图标" />
+        </div>
+      </div>
+
+      <!-- 一键诊断 -->
+      <div class="card card-diagnosis" @click="handleDiagnosisClick('outside')">
+        <div class="card-content">
+          <div class="card-title" style="color: #2F655B;">一键诊断(规划中)</div>
+          <div class="card-desc" style="color: #6D9587;">AI诊断墙面问题,提供解决方案</div>
+        </div>
+        <div class="card-icon">
+          <img src="@/assets/AIDesign/diagnosis-printer.png" alt="诊断图标" />
+        </div>
+      </div>
+
+      <!-- 五行推荐 -->
+      <div class="card card-five-element" @click="handleFiveElementClick">
+        <div class="card-content">
+          <div class="card-title" style="color: #635A30;">五行推荐(规划中)</div>
+          <div class="card-desc" style="color: #8F865B;">根据五行推荐最适合的颜色</div>
+        </div>
+        <div class="card-icon">
+          <img src="@/assets/AIDesign/five-element-planet.png" alt="五行图标" />
+        </div>
+      </div>
+    </div>
+
+    <!-- 内墙-功能卡片区域 -->
+    <div class="feature-cards" v-show="currentTab === 'inside'">
+      <!-- 我要设计 -->
+      <div class="card card-design" @click="handleDesignClick('inside')">
+        <div class="card-content">
+          <div class="card-title" style="color: #512E79;">我要设计 震撼上线!</div>
+          <div class="card-desc" style="color: #7F639E;">AI在线生图,快速预览效果</div>
+        </div>
+        <div class="card-icon">
+          <img src="@/assets/AIDesign/design-robot.png" alt="设计图标" />
+        </div>
+      </div>
+
+      <!-- 一键诊断 -->
+      <div class="card card-diagnosis" @click="handleDiagnosisClick('inside')">
+        <div class="card-content">
+          <div class="card-title" style="color: #2F655B;">一键诊断 震撼上线!</div>
+          <div class="card-desc" style="color: #6D9587;">AI诊断墙面问题,提供解决方案</div>
+        </div>
+        <div class="card-icon">
+          <img src="@/assets/AIDesign/diagnosis-printer.png" alt="诊断图标" />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Vue } from "vue-property-decorator";
+import { toLBHome, getGuid, getQyCode } from '@/utils/index';
+import axios from "axios";
+declare let wx: any;
+@Component
+export default class extends Vue {
+  private currentTab = 'outside';
+  private toastLoading = null;
+  created() {
+    // 经销商随身邦,好邦手进去,默认在内墙空间;服务商进去,默认外墙空间
+    const agentFrom = window.localStorage.getItem('agentFrom');
+    window.localStorage.setItem('agentFromAI', agentFrom);
+    // 导购直接从AI设计首页进来的修改agentFrom=dg
+    const agent = this.$route.query.agent || null;
+    if (agent && agent === 'dg') {
+      window.localStorage.setItem('agentFromAI', agent);
+    }
+    if (agentFrom === 'ssb' || agentFrom === 'hbs') {
+      this.currentTab = 'inside';
+    } else {
+      this.currentTab = 'outside';
+    }
+  }
+  handleTabChange(tabType: 'outside' | 'inside'): void {
+    this.currentTab = tabType;
+  }
+  returnPage() {
+    this.$router.go(-1);
+  }
+  toHome() {
+    toLBHome()
+  }
+  // 点击事件处理
+  handleDesignClick(type) {
+    if (type === 'outside') {
+      // 外墙设计页
+      this.$router.push("/AIDesign/design");
+    } else if (type === 'inside') {
+      // 内墙设计页
+      this.$router.push("/AIDesign/insideDesign");
+    }
+  }
+
+  handleDiagnosisClick(wallType) {
+    if (wallType === "outside") {
+      this.$toast('规划中,敬请期待');
+      return;
+    }
+    this.$router.push({ path: '/AIDesign/diagnose', query: { wallType } });
+  }
+
+  handleFiveElementClick() {
+    this.$toast('规划中,敬请期待');
+    // this.$router.push("/AIDesign/five-element");
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.home-container {
+  /* padding: 20px; */
+  background-color: #f7f7f7;
+  min-height: 100vh;
+  flex-direction: column;
+}
+
+/* 顶部背景图 */
+.top-bg {
+  font-size: 0;
+  line-height: 0;
+  position: relative;
+
+  .bg-image {
+    width: 100%;
+    height: auto;
+    /* object-fit: cover; */
+  }
+}
+
+
+
+/* 标题样式 */
+.smart-space-title {
+  padding: 0 20px;
+  position: relative;
+  font-size: 20px;
+  font-weight: bold;
+  color: #333;
+  margin-bottom: 20px;
+  display: flex;
+  align-items: center;
+  gap: 5px;
+}
+
+.smart-space-title-new {
+  display: flex;
+  justify-content: space-between;
+  // background-color: #dce0ea;
+  background-color: #d9e0ef;
+  height: 5.5rem;
+  line-height: 5.5rem;
+  margin-bottom: 3rem;
+  padding-top: 1.8rem;
+  position: relative;
+  top: -2px;
+
+  .tab-title {
+    flex: 1;
+    text-align: center;
+    font-size: 20px;
+    font-weight: bold;
+    color: #333;
+    position: relative;
+    z-index: 0;
+  }
+
+  .active_l,
+  .active_r {
+    >div {
+      position: relative;
+      z-index: 0;
+    }
+
+    ::after {
+      content: '';
+      position: absolute;
+      width: 3rem;
+      height: 2.4rem;
+      right: calc(50% - 75px);
+      transform: translate(-50%, 0);
+      top: 10px;
+      background: url('../../assets/AIDesign/AIIcon.png') 100% 100%;
+      background-size: 100% 100%;
+      z-index: -1;
+    }
+  }
+
+  .active_l::after,
+  .active_r::after {
+    content: '';
+    width: calc(100% + 10rem);
+    height: 5.5rem;
+    position: absolute;
+    top: 0;
+    z-index: -1;
+
+  }
+
+  .active_l::after {
+    left: -6rem;
+    background: url('../../assets/AIDesign/tabL.png') 100% 100%;
+    background-size: 100% 100%;
+  }
+
+  .active_r::after {
+    left: -4rem;
+    background: url('../../assets/AIDesign/tabR.png') 100% 100%;
+    background-size: 100% 100%;
+  }
+}
+
+
+/* 功能卡片容器 */
+.feature-cards {
+  padding: 0 20px;
+  display: flex;
+  flex-direction: column;
+  gap: 16px;
+}
+
+/* 卡片通用样式 */
+.card {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 16px;
+  border-radius: 16px;
+  cursor: pointer;
+  transition: transform 0.2s ease;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+}
+
+.card:hover {
+  transform: translateY(-2px);
+}
+
+.card-content {
+  flex: 1;
+}
+
+.card-title {
+  font-size: 15px;
+  font-weight: 600;
+  color: #333;
+}
+
+.card-desc {
+  font-size: 12px;
+  color: #666;
+  margin-top: 4px;
+}
+
+.card-icon {
+  width: 80px;
+  height: 80px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.card-icon img {
+  width: 80px;
+  height: 80px;
+}
+
+/* 各卡片背景色 */
+.card-design {
+  background: linear-gradient(135deg, #e6e6ff, #f0f0ff);
+  /* border: 1px solid #d0d0ff; */
+}
+
+.card-diagnosis {
+  background: linear-gradient(135deg, #e6ffe6, #f0fff0);
+  /* border: 1px solid #c0ffc0; */
+}
+
+.card-five-element {
+  margin-bottom: 1rem;
+  background: linear-gradient(135deg, #fff8e6, #fff0e6);
+  /* border: 1px solid #ffd0c0; */
+}
+
+.header {
+  /*height: 50px;*/
+  /*line-height: 50px;*/
+  /*text-align: center;*/
+  /*background: #fff;*/
+  border-bottom: 1px solid #f8f8f8;
+
+  .van-nav-bar__title {
+    font-size: 20px;
+    color: #333;
+  }
+
+  .van-icon {
+    font-size: 20px;
+    color: #333 !important;
+  }
+}
+</style>

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1377 - 0
src/views/AIDesign/insideDesign.vue


+ 865 - 0
src/views/AIDesign/result.vue

@@ -0,0 +1,865 @@
+<template>
+  <div class="resout-container AI-Design-container">
+    <header-online pagetitle="生成结果"></header-online>
+    <!-- <div class="header">
+      <van-nav-bar title="生成结果" left-arrow @click-left="returnPage" @click-right="toHome">
+        <template #right>
+          <van-icon name="wap-home-o" color="#333" size="26" />
+        </template>
+</van-nav-bar>
+</div> -->
+
+    <div class="container">
+      <!-- 房屋效果图 -->
+      <div class="image-container">
+        <div v-if="imageUrl" class="comparisonWrapper">
+          <div class="imgbox-t">
+            <div>
+              <p class="tit">原图</p>
+            </div>
+            <div>
+              <p class="tit">AI效果图</p>
+            </div>
+          </div>
+          <div class="imgbox-b">
+            <div class="image-wrapper" @click="imgClick(UserFilePathUrl)">
+              <img :src="UserFilePathUrl" alt="房屋效果图" class="house-image" />
+              <div></div>
+            </div>
+            <div class="image-wrapper" @click="imgClick(imageUrl)">
+              <img :src="imageUrlSmall" alt="房屋效果图" class="house-image" />
+              <div></div>
+            </div>
+          </div>
+        </div>
+        <div v-else class="loading-state">
+          <img v-if="StateCode != 3 && StateCode != 4" src="@/assets/AIDesign/loding.gif" style="width: 100px;">
+          <p class="loading-text">{{ type || StateCode ? (StateCode == 3 ? '生成失败' : (StateCode == 4 ?
+            '生成失败,\n' + StateInfo :
+            '正在为您加速生成中,先喝杯茶吧~\n退出本页不影响生成')) : '加载中...' }}</p>
+        </div>
+      </div>
+
+      <!-- 保存按钮 -->
+      <!-- <button class="save-button" :disabled="!imageUrl" :class="{ 'save-button-disabled': !imageUrl }"
+        @click="saveImageToAlbum">保存图片</button> -->
+
+      <!-- 功能按钮组 -->
+      <div class="button-group">
+        <!--<button class="action-button" :disabled="!imageUrl" :class="{ 'save-button-disabled': !imageUrl }"-->
+        <button class="action-button" :disabled="regenerateDisable"
+          :class="regenerateDisable == true ? 'save-button-disabled' : ''" @click="regenerate">
+          <van-icon class="icon" name="replay" />
+          <span class="text">重新生成</span>
+        </button>
+        <button class="action-button" @click="viewHistory">
+          <van-icon class="icon" name="clock-o" />
+          <span class="text">历史生图</span>
+          <span v-if="!readState" class="badge-dot"></span>
+        </button>
+        <!-- 服务商随身邦和部分经销商展示转人工 -->
+        <button class="action-button" @click="manualDesign" v-if="showArtificial" :disabled="projectDisableFlag"
+          :class="projectDisableFlag == true ? 'save-button-disabled' : ''">
+          <van-icon class="icon" name="user-o" />
+          <span class="text">转人工设计(原别墅之星小程序)</span>
+        </button>
+      </div>
+    </div>
+
+  </div>
+</template>
+<script lang="ts">
+import { ImagePreview, Dialog } from 'vant';
+import { Component, Vue } from "vue-property-decorator";
+import { GetEntity, GetReadState, UpdateReadState, insideGetEntity, insideGetReadState, insideUpdateReadState, GetProjectlist, GetDictList } from "@/api/indexAI";
+import { getWecomType ,toLBHome } from '@/utils/index';
+import axios from "axios";
+declare let wx: any;
+@Component
+export default class extends Vue {
+  private readState = true;
+  // 数据属性
+  // private imageUrl = require('@/assets/AIDesign/house-image.jpg'); // 替换为实际图片路径
+  private imageUrl = ''; // 替换为实际图片路径
+  private imageUrlSmall = '';
+  private UserFilePathUrl = '';//用户原图
+  private pollingTimer: number | null = null; // 轮询定时器引用
+  private timer = null;
+  private StateCode = null;
+  private projectId = null;
+  private regenerateDisable = true;
+  private StateInfo = '';
+  private type = '';
+  private wallType = '';
+  // 处理内外墙api
+  private GetEntityToApi = {
+    outside: GetEntity,
+    inside: insideGetEntity
+  };
+  private GetReadStateToApi = {
+    outside: GetReadState,
+    inside: insideGetReadState
+  };
+  private UpdateReadStateToApi = {
+    outside: UpdateReadState,
+    inside: insideUpdateReadState
+  };
+
+  private designPageApi = {
+    outside: '/AIDesign/design',
+    inside: '/AIDesign/insideDesign'
+  };
+
+  private designTimer = {
+    outside: 50000,
+    inside: 20000
+  };
+  private showArtificial = false;
+  private agentFrom = window.localStorage.getItem('agentFromAI');
+  private outsideDesignCount = 0;//项目下设计已用数量-接口获取
+  private isNeedProjectFlag = true;//是否需要项目-接口获取
+  private projectDisableFlag = true;//转人工不可点击
+  private serviceCodeArray = [];
+  created() {
+    this.getWxconfig();
+    // this.getServiceCode();
+  }
+
+  activated() {
+    this.initialize();
+    this.wallType = this.$route.query.wallType || 'outside';
+    const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
+    const customerCode = userInfo && userInfo.sysUserExt ? userInfo.sysUserExt.customerCode : '';
+    const salesLevel = userInfo && userInfo.sysUserExt ? userInfo.sysUserExt.salesLevel : '';
+    // 外墙-服务商随身邦
+    if (this.agentFrom === 'stoneLikePaint' && this.wallType === 'outside') {
+      this.showArtificial = true;
+      this.getIsNeedProjectFlag();//获取是否关联了项目
+    }
+    // 和部分经销商展示转人工
+    // else if(customerCode && (salesLevel === 'customer_level' || salesLevel === 'reseller_level')){
+    //   this.showArtificial = true;
+    // }
+    // 从经销商随身邦进入的,显示转人工按钮,没有次数限制
+    if (this.agentFrom === 'ssb' && this.wallType === 'outside') {
+      this.showArtificial = true;
+      this.projectDisableFlag = false;
+    }
+    this.type = window.localStorage.getItem('type');
+    this.GetReadStateFn();
+    this.GetEntityDataFirst()
+  }
+  // 离开页面时清除定时器
+  deactivated() {
+    // console.log('resule页面销毁1')
+    window.localStorage.removeItem('type');
+    clearInterval(this.pollingTimer);
+    clearTimeout(this.timer);
+    this.pollingTimer = null;
+    this.timer = null;
+  }
+  initialize() {
+    clearInterval(this.pollingTimer);
+    clearTimeout(this.timer);
+    this.readState = true;
+    this.imageUrl = ''; // 替换为实际图片路径
+    this.imageUrlSmall = '';
+    this.UserFilePathUrl = '';//用户原图
+    this.pollingTimer = null; // 轮询定时器引用
+    this.timer = null;
+    this.StateCode = null;
+    this.projectId = null;
+    this.regenerateDisable = true;
+    this.StateInfo = '';
+    this.type = '';
+    this.wallType = '';
+    this.outsideDesignCount = 0;
+    this.isNeedProjectFlag = true;
+    this.projectDisableFlag = true;
+    this.showArtificial = false;
+  }
+  // 是否关联了项目
+  getIsNeedProjectFlag() {
+    let that = this;
+    const formData = new FormData();
+    // const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
+    // let roleIdArray = [];
+    // if (userInfo.roles.length > 0) {
+    //   userInfo.roles.forEach(item => {
+    //     roleIdArray.push(item.roleId);
+    //   })
+    // }
+    // formData.append('roleIds', roleIdArray.join(','));
+    // formData.append('WXuserid', userInfo.loginName);
+    formData.append('baseType', 0);//0外墙--这里只用查询外墙
+    const agentFrom = window.localStorage.getItem('agentFromAI');
+    const wecomType = getWecomType(agentFrom);
+    formData.append('wecomType', 5);
+    GetDictList(formData).then(response => {
+      if (response.StatusCode == 200) {
+        if (that.serviceCodeArray.length == 0) {
+          that.isNeedProjectFlag = false; //是否需要项目
+        } else {
+          that.isNeedProjectFlag = response.Data.isNeedProject;
+        }
+        if (that.isNeedProjectFlag) {
+          that.updateCheckedProjectLastNum();
+        } else {
+          that.projectDisableFlag = false;//没有项目就可点击
+        }
+      }
+    })
+  }
+  //获取选中关联项目已用数量
+  private updateCheckedProjectLastNum() {
+    let that = this;
+    const formData = new FormData();
+    // formData.append('ServiceCode', that.serviceCodeArray.join(','));
+    formData.append('projectid', this.$route.query.projectid);
+    GetProjectlist(formData).then(response => {
+      if (response.StatusCode == 200 && response.Data && response.Data[0]) {
+        that.outsideDesignCount = response.Data[0].DesignCount || 0;
+        // 单一关联项目下设计了1~3套,转人工设计均置灰不可点。从第4套起等转人工设计均可点
+        if (that.outsideDesignCount > 3) {
+          that.projectDisableFlag = false;//有项目判断>3可点击
+        }
+      }
+    });
+  }
+  private getServiceCode() {
+    let that = this;
+    const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
+    let serviceCodeArray = [];
+    if (userInfo.loginTypeList.length > 0) {
+      userInfo.loginTypeList.forEach(item => {
+        if (item.shopType == 'stoneLikePaint') {
+          item.shopList.forEach(childItem => {
+            serviceCodeArray.push(childItem.shop_code);
+          })
+        }
+      })
+    }
+    that.serviceCodeArray = serviceCodeArray;
+  }
+  GetReadStateFn() {
+    const formData = new FormData();
+    // const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
+    // formData.append('WXuserid', userInfo.loginName);
+    this.GetReadStateToApi[this.wallType](formData).then(response => {
+      if (response.StatusCode == 200) {
+        this.readState = response.Data.readState;
+      }
+    });
+  }
+  UpdateReadStateFn() {
+    const formData = new FormData();
+    // const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
+    // formData.append('WXuserid', userInfo.loginName);
+    this.UpdateReadStateToApi[this.wallType](formData).then(response => { });
+  }
+  returnPage() {
+    this.$router.push({ path: '/AIDesign' });
+  }
+  toHome() {
+    toLBHome()
+  }
+  imgClick(url) {
+    ImagePreview([url]);
+  }
+  private startPolling(): void {
+    // 立即执行一次检查
+    this.GetEntityData();
+
+    // 设置定时器每秒执行一次检查
+    this.pollingTimer = window.setInterval(() => {
+      if (!this.imageUrl) {
+        if (this.StateCode == 3 || this.StateCode == 4) {
+          clearInterval(this.pollingTimer);
+          this.pollingTimer = null;
+        } else {
+          this.GetEntityData();
+        }
+
+      } else {
+        // 当 imageUrl 有值时,清除定时器
+        if (this.pollingTimer) {
+          clearInterval(this.pollingTimer);
+          this.pollingTimer = null;
+        }
+      }
+    }, 3000);
+  }
+  //进入页面首次调用获取状态
+  GetEntityDataFirst() {
+    let that = this;
+    const F_ID = this.$route.query.F_id || "";
+    const formData = new FormData();
+    formData.append('F_id', F_ID);
+    this.GetEntityToApi[this.wallType](formData).then(response => {
+      // console.log(response);
+      if (response.StatusCode == 200) {
+        if (response.Data == null) {
+          that.regenerateDisable = true;
+          if (that.timer) {
+            clearTimeout(that.timer);
+            that.timer = null;
+          }
+          that.timer = setTimeout(() => {
+            that.startPolling();
+          }, that.designTimer[that.wallType]);
+        } else {
+          this.StateCode = response.Data.StateCode;
+          this.StateInfo = response.Data.Description;
+          this.projectId = response.Data.ProjectID;
+          if (response.Data.F_ResultFilePath || response.Data.F_ResultlargeFilePath) {
+            const high_Definition_img = response.Data.F_ResultFilePath || response.Data.F_ResultlargeFilePath || response.Data.F_ResultSmallFilePath;
+            that.imageUrl = response.Data.BaseUrl + high_Definition_img;
+            that.imageUrlSmall = response.Data.BaseUrl + response.Data.F_ResultSmallFilePath;
+            that.UserFilePathUrl = response.Data.BaseUrl + response.Data.F_UserFilePath;
+          }
+          if (response.Data.StateCode == 1) {
+            let createTime = new Date(response.Data.CreateDate);
+            let currentTime = new Date().getTime();
+            if (currentTime - createTime > that.designTimer[that.wallType]) {
+              that.startPolling();
+            } else {
+              if (that.timer) {
+                clearTimeout(that.timer);
+                that.timer = null;
+              }
+              that.timer = setTimeout(() => {
+                that.startPolling();
+              }, currentTime - createTime);
+            }
+          } else {
+            if (response.Data.StateCode == 2 || response.Data.StateCode == 3 || response.Data.StateCode == 4) {
+              that.regenerateDisable = false;
+            } else {
+              that.regenerateDisable = true;
+            }
+          }
+        }
+      } else {
+        this.$toast.fail(response.Info);
+      }
+    })
+  }
+
+  GetEntityData() {
+    let that = this;
+    const F_ID = this.$route.query.F_id || "";
+    const formData = new FormData();
+    formData.append('F_id', F_ID);
+    this.GetEntityToApi[this.wallType](formData).then(response => {
+      // console.log(response);
+      if (response.StatusCode == 200) {
+        if (response.Data) {
+          this.StateCode = response.Data.StateCode;
+          this.StateInfo = response.Data.Description;
+          if (response.Data.F_ResultFilePath || response.Data.F_ResultlargeFilePath) {
+            const high_Definition_img = response.Data.F_ResultFilePath || response.Data.F_ResultlargeFilePath || response.Data.F_ResultlargeFilePath;
+            that.imageUrl = response.Data.BaseUrl + high_Definition_img;
+            that.imageUrlSmall = response.Data.BaseUrl + response.Data.F_ResultSmallFilePath;
+            that.UserFilePathUrl = response.Data.BaseUrl + response.Data.F_UserFilePath;
+          }
+          if (response.Data.StateCode == 2 || response.Data.StateCode == 3 || response.Data.StateCode == 4) {
+            that.regenerateDisable = false;
+          } else {
+            that.regenerateDisable = true;
+          }
+        } else {
+          that.regenerateDisable = true;
+        }
+      } else {
+        this.$toast.fail(response.Info);
+      }
+    })
+  }
+  // 获取微信API授权信息
+  getWxconfig() {
+    const jsApiList = ['getSetting', 'authorize', 'showModal', 'openSetting', 'downloadFile', 'saveImageToPhotosAlbum'];
+    let url = window.location.href.split("#")[0];
+    axios.get(`${process.env.VUE_APP_BASE_API}wx/ticket`, {
+      params: {
+        url: url,
+        agent: 1
+      }
+    }).then(response => {
+      if (response.status == 200) {
+        let qiyeData = response.data.data;
+        wx.agentConfig({
+          debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
+          corpid: qiyeData.appId, // 必填,企业微信的corpid,必须与当前登录的企业一致
+          agentid: qiyeData.agentId, // 必填,企业微信的应用id (e.g. 1000247)
+          timestamp: qiyeData.timestamp, // 必填,生成签名的时间戳
+          nonceStr: qiyeData.nonceStr, // 必填,生成签名的随机串
+          signature: qiyeData.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法
+          jsApiList: [...jsApiList], //必填,传入需要使用的接口名称
+          success: function (res) {
+            console.log('获取签名成功');
+          },
+          fail: function (res) {
+            console.log(res);
+            if (res.errMsg.indexOf('function not exist') > -1) {
+              alert('版本过低请升级');
+            }
+          },
+        });
+      }
+    });
+  }
+  // 点击保存图片按钮
+  saveImageToAlbum() {
+    const that = this;
+    wx.ready(function () {
+      // 1. 检查用户是否授权保存图片到相册
+      wx.getSetting({
+        success: (res) => {
+          // 2. 如果未授权,请求授权
+          if (!res.authSetting['scope.writePhotosAlbum']) {
+            wx.authorize({
+              scope: 'scope.writePhotosAlbum',
+              success: () => {
+                // 授权成功,执行保存逻辑
+                that.downloadAndSaveImage();
+              },
+              fail: () => {
+                // 用户拒绝授权,引导手动开启
+                wx.showModal({
+                  title: '授权提示',
+                  content: '需要你的授权才能保存图片到相册,请在设置中开启授权',
+                  confirmText: '去设置',
+                  success: (modalRes) => {
+                    if (modalRes.confirm) {
+                      // 打开设置页面
+                      wx.openSetting({
+                        success: (settingRes) => {
+                          if (settingRes.authSetting['scope.writePhotosAlbum']) {
+                            that.downloadAndSaveImage();
+                          } else {
+                            that.$toast.fail('未授权,无法保存图片');
+                          }
+                        }
+                      });
+                    }
+                  }
+                });
+              }
+            });
+          } else {
+            // 已授权,直接执行保存逻辑
+            that.downloadAndSaveImage();
+          }
+        },
+        fail: (err) => {
+          console.error('获取设置失败', err);
+          that.$toast.fail('获取授权状态失败,请重试');
+        }
+      });
+    });
+
+  }
+
+  // 下载图片并保存到相册
+  downloadAndSaveImage() {
+    const that = this;
+    const imageUrl = this.imageUrl;
+    wx.ready(function () {
+      // 1. 下载OSS图片到本地临时路径
+      wx.downloadFile({
+        url: imageUrl,
+        success: (downloadRes) => {
+          // 检查下载是否成功(临时文件路径存在)
+          if (downloadRes.statusCode === 200 && downloadRes.tempFilePath) {
+            // 2. 保存图片到相册
+            wx.saveImageToPhotosAlbum({
+              filePath: downloadRes.tempFilePath,
+              success: () => {
+                // 提示用户
+                that.$toast.success('图片已成功保存到相册');
+              },
+              fail: (saveErr) => {
+                console.error('保存图片失败', saveErr);
+                that.$toast.fail('保存失败,请重试');
+              }
+            });
+          } else {
+            console.error('图片下载失败', downloadRes);
+            that.$toast.fail('图片下载失败,请检查URL');
+          }
+        },
+        fail: (downloadErr) => {
+          console.error('下载请求失败', downloadErr);
+          that.$toast.fail('下载图片失败,请重试');
+        }
+      });
+    });
+  }
+  // 方法
+  private saveImage(): void {
+    if (!this.imageUrl) {
+      this.$toast.fail('图片尚未生成完成');
+      return;
+    }
+
+    // // 创建一个临时的下载链接
+    // const link = document.createElement('a');
+    // link.href = this.imageUrl;
+    // link.download = `ai-design-${new Date().getTime()}.png`;
+    // link.style.display = 'none';
+
+    // // 将链接添加到页面并触发点击事件
+    // document.body.appendChild(link);
+    // link.click();
+
+    // // 清理DOM元素
+    // document.body.removeChild(link);
+
+    fetch(this.imageUrl).then(response => response.blob()).then(blob => {
+      const blobUrl = URL.createObjectURL(blob);
+      // 创建一个临时的下载链接
+      const link = document.createElement('a');
+      link.href = blobUrl;
+      link.download = `ai-design-${new Date().getTime()}.png`;
+      link.style.display = 'none';
+
+      // 将链接添加到页面并触发点击事件
+      document.body.appendChild(link);
+      link.click();
+
+      // 清理DOM元素
+      document.body.removeChild(link);
+
+      // 释放Blob URL
+      URL.revokeObjectURL(blobUrl);
+
+      // this.$toast.success('图片保存成功');
+    }).catch(error => {
+      console.error('图片下载失败:', error);
+      this.$toast.fail('图片下载失败');
+    });
+  }
+
+  private regenerate(): void {
+    // console.log('重新生成');
+    let that = this;
+    // 实现重新生成逻辑
+    const F_ID = this.$route.query.F_id || "";
+    this.$router.push({
+      path: this.designPageApi[this.wallType],
+      query: {
+        F_id: F_ID,
+        projectId: that.projectId
+      }
+    });
+  }
+
+  private viewHistory(): void {
+    this.UpdateReadStateFn();
+    // console.log('查看历史生成');
+    // 实现查看历史生成逻辑
+    this.$router.push({ path: '/AIDesign/history', query: { wallType: this.wallType } });
+  }
+
+  private manualDesign(): void {
+    let that = this;
+    debugger
+    // console.log('转人工设计');
+    // 实现转人工设计逻辑
+    that.$magnetlogadd.setLog('AI外墙设计-转人工设计', function () {
+      that.toXiaoChengxu(`${process.env.VUE_APP_BASE_DISID6}`);
+    })
+  }
+  //跳转微信小程序
+  toXiaoChengxu(appid) {
+    let url = window.location.href.split("#")[0];
+    wx.ready(function () {
+      wx.checkJsApi({
+        jsApiList: ["agentConfig", "launchMiniprogram"], // 需要检测的JS接口列表
+        success: function (res) {
+          axios.get(`${process.env.VUE_APP_BASE_API}wx/ticket`, {
+            params: {
+              url: url,
+              agent: 1
+            }
+          }).then(response => {
+            if (response.status == 200) {
+              let yingyongData = response.data.data;
+              wx.agentConfig({
+                corpid: yingyongData.appId, // 必填,企业微信的corpid,必须与当前登录的企业一致
+                agentid: yingyongData.agentId, // 必填,企业微信的应用id (e.g. 1000247)
+                timestamp: yingyongData.timestamp, // 必填,生成签名的时间戳
+                nonceStr: yingyongData.nonceStr, // 必填,生成签名的随机串
+                signature: yingyongData.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法
+                jsApiList: ["launchMiniprogram"], //必填,传入需要使用的接口名称
+                success: function (res) {
+                  wx.invoke(
+                    "launchMiniprogram",
+                    {
+                      appid: appid, // 需跳转的小程序appid
+                      path: "" // 所需跳转的小程序内页面路径及参数。非必填
+                    },
+                    function (res) {
+                      if (res.err_msg == "launchMiniprogram:ok") {
+                        // 正常
+                        console.log("正常");
+                      } else {
+                        // 错误处理
+                      }
+                    }
+                  );
+                },
+                fail: function (res) {
+                  if (res.errMsg.indexOf("function not exist") > -1) {
+                    alert("版本过低请升级");
+                  }
+                }
+              });
+            }
+          });
+        }
+      });
+    });
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.resout-container {
+  background-color: #f8f9fa;
+  min-height: 100vh;
+  flex-direction: column;
+}
+
+.header {
+  /*height: 50px;*/
+  /*line-height: 50px;*/
+  /*text-align: center;*/
+  /*background: #fff;*/
+  border-bottom: 1px solid #f8f8f8;
+
+  .van-nav-bar__title {
+    font-size: 20px;
+    color: #333;
+  }
+
+  .van-icon {
+    font-size: 20px;
+    color: #333 !important;
+  }
+}
+
+.container {
+  padding: 0 20px;
+}
+
+.image-container {
+  position: relative;
+  width: 100%;
+  border-radius: 10px;
+  overflow: hidden;
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+  margin-top: 20px;
+
+  .comparisonWrapper {
+    display: flex;
+    flex-direction: column;
+    padding: 35px 6px;
+
+    .imgbox-t {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+
+      >div {
+        .tit {
+          width: fit-content;
+          padding: 0 5px;
+          height: 17px;
+          line-height: 17px;
+          border-radius: 32px;
+          font-size: 10px;
+        }
+      }
+
+      >div:first-child {
+        width: 36%;
+
+        .tit {
+          background: rgba(204, 204, 204, 1);
+        }
+      }
+
+      >div:last-child {
+        width: 58%;
+
+        .tit {
+          color: #fff;
+          background: rgba(244, 155, 125, 1);
+        }
+      }
+    }
+
+    .imgbox-b {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+
+      >div:first-child {
+        width: 36%;
+      }
+
+      >div:last-child {
+        width: 58%;
+      }
+
+      .image-wrapper {
+        position: relative;
+        width: 100%;
+        margin: 5px 0;
+        display: flex;
+        align-items: center;
+        justify-content: flex-start;
+
+        .house-image {
+          border-radius: 10px;
+          display: block;
+          width: 100%;
+          height: auto;
+        }
+
+        .house-image+div {
+          position: absolute;
+          top: 0;
+          left: 0;
+          width: 100%;
+          height: 100%;
+          background: transparent;
+          z-index: 2;
+        }
+      }
+    }
+  }
+}
+
+.loading-state {
+  position: relative;
+  width: 100%;
+  height: 300px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  color: #666;
+  text-align: center;
+  // background-color: rgba(0, 0, 0, 0.7);
+  background-image: url('../../assets/AIDesign/bg.png');
+  background-size: 100% 100%;
+  /* 添加半透明黑色背景 */
+  // border-radius: 16px;
+  /* 圆角边框 */
+}
+
+.loading-text {
+  margin-top: 10px;
+  font-size: 14px;
+  color: white;
+  white-space: pre-line
+    /* 文字颜色改为白色以提高对比度 */
+}
+
+
+
+.address-info {
+  position: absolute;
+  bottom: 10px;
+  left: 10px;
+  right: 10px;
+  background-color: rgba(0, 0, 0, 0.5);
+  color: white;
+  padding: 8px;
+  border-radius: 8px;
+  font-size: 14px;
+  text-align: center;
+}
+
+.project-name {
+  margin: 0;
+  font-weight: bold;
+}
+
+.address {
+  margin: 4px 0 0;
+  font-size: 12px;
+}
+
+.save-button {
+  width: 100%;
+  padding: 16px;
+  margin-top: 20px;
+  background-color: #E96337;
+  color: white;
+  border: none;
+  border-radius: 12px;
+  font-size: 16px;
+  font-weight: bold;
+  cursor: pointer;
+  transition: background-color 0.3s ease;
+}
+
+.save-button-disabled {
+  background-color: #cccccc !important;
+  cursor: not-allowed !important;
+  color: white !important;
+}
+
+/* .save-button:hover {
+  background-color: #e04a1d;
+} */
+
+.button-group {
+  margin-top: 20px;
+}
+
+.action-button {
+  width: 100%;
+  padding: 14px;
+  margin-bottom: 12px;
+  background-color: white;
+  border: 1px solid #e0e0e0;
+  border-radius: 12px;
+  font-size: 15px;
+  color: #333;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  transition: background-color 0.3s ease;
+}
+
+.action-button:hover {
+  background-color: #f5f5f5;
+}
+
+.badge-dot {
+  margin-left: 10px;
+  width: 5px;
+  height: 5px;
+  background-color: #ff4d4f;
+  border-radius: 50%;
+}
+
+.icon {
+  margin-right: 10px;
+  font-size: 18px;
+}
+
+.text {
+  font-weight: 500;
+}
+
+.van-nav-bar__title {
+  font-size: 20px;
+  color: #333;
+}
+</style>

+ 0 - 0
src/views/errorPage/index.vue


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels