浏览代码

嵌入小程序

shaogen1995 7 月之前
父节点
当前提交
648a83c3df
共有 100 个文件被更改,包括 37608 次插入0 次删除
  1. 5 0
      小程序/guildsvg/.vscode/settings.json
  2. 3 0
      小程序/guildsvg/axios.min.js
  3. 259 0
      小程序/guildsvg/collection.html
  4. 43 0
      小程序/guildsvg/flexible.js
  5. 1372 0
      小程序/guildsvg/map.svg
  6. 1775 0
      小程序/guildsvg/svg.html
  7. 327 0
      小程序/history.json
  8. 2 0
      小程序/jingtailan/.env.dev
  9. 2 0
      小程序/jingtailan/.env.pro
  10. 21 0
      小程序/jingtailan/.gitignore
  11. 35 0
      小程序/jingtailan/.vscode/vue-setup.code-snippets
  12. 51 0
      小程序/jingtailan/history.json
  13. 20 0
      小程序/jingtailan/index.html
  14. 21146 0
      小程序/jingtailan/package-lock.json
  15. 76 0
      小程序/jingtailan/package.json
  16. 29 0
      小程序/jingtailan/project.config.json
  17. 7 0
      小程序/jingtailan/project.private.config.json
  18. 124 0
      小程序/jingtailan/src/App.vue
  19. 17 0
      小程序/jingtailan/src/api/api/analyse/index.ts
  20. 11 0
      小程序/jingtailan/src/api/api/explore/craft/index.ts
  21. 7 0
      小程序/jingtailan/src/api/api/explore/gift/index.ts
  22. 11 0
      小程序/jingtailan/src/api/api/explore/great/index.ts
  23. 12 0
      小程序/jingtailan/src/api/api/explore/index.ts
  24. 12 0
      小程序/jingtailan/src/api/api/home/index.ts
  25. 11 0
      小程序/jingtailan/src/api/api/login/index.ts
  26. 35 0
      小程序/jingtailan/src/api/api/mine/index.ts
  27. 18 0
      小程序/jingtailan/src/api/api/visit/index.ts
  28. 1 0
      小程序/jingtailan/src/api/record.ts
  29. 106 0
      小程序/jingtailan/src/api/request.ts
  30. 191 0
      小程序/jingtailan/src/components/ModelDeatil copy.vue
  31. 282 0
      小程序/jingtailan/src/components/ModelDeatil.vue
  32. 106 0
      小程序/jingtailan/src/components/PageList.vue
  33. 208 0
      小程序/jingtailan/src/components/PageListNoRow.vue
  34. 349 0
      小程序/jingtailan/src/components/TabBar.vue
  35. 73 0
      小程序/jingtailan/src/components/TabBarTop.vue
  36. 77 0
      小程序/jingtailan/src/components/TabBarTopHome.vue
  37. 502 0
      小程序/jingtailan/src/components/mp-html/mp-html.vue
  38. 604 0
      小程序/jingtailan/src/components/mp-html/node/node.vue
  39. 1335 0
      小程序/jingtailan/src/components/mp-html/parser.js
  40. 8 0
      小程序/jingtailan/src/env.d.ts
  41. 11 0
      小程序/jingtailan/src/main.ts
  42. 73 0
      小程序/jingtailan/src/manifest.json
  43. 232 0
      小程序/jingtailan/src/pages.json
  44. 288 0
      小程序/jingtailan/src/pages/analyse/detail/culturalRelicDetail/index copy.vue
  45. 414 0
      小程序/jingtailan/src/pages/analyse/detail/culturalRelicDetail/index.vue
  46. 131 0
      小程序/jingtailan/src/pages/analyse/detail/culturalRelicDetail/index3D.vue
  47. 249 0
      小程序/jingtailan/src/pages/analyse/detail/index.vue
  48. 270 0
      小程序/jingtailan/src/pages/analyse/index.vue
  49. 68 0
      小程序/jingtailan/src/pages/explore/craft/detail/index.vue
  50. 258 0
      小程序/jingtailan/src/pages/explore/craft/index.vue
  51. 65 0
      小程序/jingtailan/src/pages/explore/gift/detail/index.vue
  52. 65 0
      小程序/jingtailan/src/pages/explore/gift/index.vue
  53. 202 0
      小程序/jingtailan/src/pages/explore/great/detail/index.vue
  54. 77 0
      小程序/jingtailan/src/pages/explore/great/index.vue
  55. 34 0
      小程序/jingtailan/src/pages/explore/history/detail/index.vue
  56. 67 0
      小程序/jingtailan/src/pages/explore/history/index.vue
  57. 122 0
      小程序/jingtailan/src/pages/explore/index.vue
  58. 33 0
      小程序/jingtailan/src/pages/explore/order/detail/index.vue
  59. 61 0
      小程序/jingtailan/src/pages/explore/order/index.vue
  60. 35 0
      小程序/jingtailan/src/pages/explore/project/detail/index.vue
  61. 97 0
      小程序/jingtailan/src/pages/explore/project/detail/index2.vue
  62. 160 0
      小程序/jingtailan/src/pages/explore/project/index.vue
  63. 635 0
      小程序/jingtailan/src/pages/home/index.vue
  64. 106 0
      小程序/jingtailan/src/pages/mine/content/index copy.vue
  65. 123 0
      小程序/jingtailan/src/pages/mine/content/index.vue
  66. 140 0
      小程序/jingtailan/src/pages/mine/culturalRelic/index.vue
  67. 822 0
      小程序/jingtailan/src/pages/mine/index.vue
  68. 596 0
      小程序/jingtailan/src/pages/mine/index2.vue
  69. 182 0
      小程序/jingtailan/src/pages/mine/perfectInfo/index.vue
  70. 47 0
      小程序/jingtailan/src/pages/visit/exhibition/index.vue
  71. 1751 0
      小程序/jingtailan/src/pages/visit/guide/index copy 2.vue
  72. 47 0
      小程序/jingtailan/src/pages/visit/guide/index copy.vue
  73. 47 0
      小程序/jingtailan/src/pages/visit/guide/index.vue
  74. 394 0
      小程序/jingtailan/src/pages/visit/history/index.vue
  75. 243 0
      小程序/jingtailan/src/pages/visit/index.vue
  76. 6 0
      小程序/jingtailan/src/shime-uni.d.ts
  77. 10 0
      小程序/jingtailan/src/static/data/common.ts
  78. 二进制
      小程序/jingtailan/src/static/img/bottomInco/back1.png
  79. 二进制
      小程序/jingtailan/src/static/img/bottomInco/back2.png
  80. 1 0
      小程序/jingtailan/src/static/img/bottomInco/gride.svg
  81. 二进制
      小程序/jingtailan/src/static/img/bottomInco/inco1.png
  82. 二进制
      小程序/jingtailan/src/static/img/bottomInco/inco1Ac.png
  83. 二进制
      小程序/jingtailan/src/static/img/bottomInco/inco2.png
  84. 二进制
      小程序/jingtailan/src/static/img/bottomInco/inco2Ac.png
  85. 二进制
      小程序/jingtailan/src/static/img/bottomInco/inco3.png
  86. 二进制
      小程序/jingtailan/src/static/img/bottomInco/inco3Ac.png
  87. 二进制
      小程序/jingtailan/src/static/img/bottomInco/inco4.png
  88. 二进制
      小程序/jingtailan/src/static/img/bottomInco/inco4Ac.png
  89. 二进制
      小程序/jingtailan/src/static/img/bottomInco/inco5.png
  90. 二进制
      小程序/jingtailan/src/static/img/bottomInco/inco5Ac.png
  91. 二进制
      小程序/jingtailan/src/static/img/bottomInco/music.png
  92. 二进制
      小程序/jingtailan/src/static/img/bottomInco/musicAc.png
  93. 二进制
      小程序/jingtailan/src/static/img/bottomInco/right.png
  94. 二进制
      小程序/jingtailan/src/static/img/bottomInco/title-logo.png
  95. 4 0
      小程序/jingtailan/src/types/declaration.d.ts
  96. 2 0
      小程序/jingtailan/src/types/index.d.ts
  97. 1 0
      小程序/jingtailan/src/types/store/Mine.d.ts
  98. 76 0
      小程序/jingtailan/src/uni.scss
  99. 90 0
      小程序/jingtailan/src/util/index.ts
  100. 0 0
      小程序/jingtailan/tsconfig.json

+ 5 - 0
小程序/guildsvg/.vscode/settings.json

@@ -0,0 +1,5 @@
+{
+    "files.associations": {
+        "*.vue": "html"
+    },
+}

文件差异内容过多而无法显示
+ 3 - 0
小程序/guildsvg/axios.min.js


+ 259 - 0
小程序/guildsvg/collection.html

@@ -0,0 +1,259 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <meta
+      name="viewport"
+      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
+    />
+    <title></title>
+    <script src="./vue.min.js"></script>
+    <style>
+      body {
+        margin: 0;
+      }
+      #app {
+        min-width: 100vw;
+        height: 100vh;
+        background: #f7f1e6;
+        box-sizing: border-box;
+        overflow: hidden;
+      }
+      .top {
+        width: 100%;
+        height: 65%;
+      }
+      .top > iframe {
+        width: 100%;
+        height: 100%;
+      }
+
+      .bottom {
+        position: absolute;
+        top: calc(65% - 30px);
+        width: 100%;
+        min-height: 40vh;
+        background: #f7f1e6;
+        border-radius: 30px 30px 0px 0px;
+        box-shadow: 0px -4px 4px 0px rgba(0, 0, 0, 0.2);
+        padding: 20px;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        box-sizing: border-box;
+      }
+      .title {
+        font-weight: bold;
+      }
+
+      .content {
+        white-space: pre-wrap;
+        font-size: 14px !important;
+        line-height: 25px !important;
+      }
+
+      .bottom > p {
+        text-indent: 2em;
+        font-size: 12px;
+        overflow: auto;
+      }
+      .previewImg {
+        width: 100vw;
+        height: 100vh;
+        z-index: 9999;
+        background: #000000be;
+        position: fixed;
+        top: 0;
+        left: 0;
+        display: flex;
+        align-items: center;
+      }
+      .previewImg > img {
+        width: 100vw;
+      }
+
+      .levitated-box {
+        background-color: #00000080;
+        border-radius: 50px;
+        width: 50px;
+        height: 50px;
+        box-sizing: border-box;
+        position: fixed;
+        right: 10px;
+        top: 50vh;
+        z-index: 999;
+        padding: 10px;
+      }
+
+      .levitated-box > img {
+        width: 100%;
+        height: 100%;
+      }
+    </style>
+    <style></style>
+  </head>
+  <body>
+    <div id="app" v-if="JSON.stringify(info) != '{}'">
+      <div class="top">
+        <!-- <iframe
+          src="https://4dscene.4dage.com/culturalrelics/YFYCM2/Model2.html?m=yfyc204"
+        ></iframe> -->
+        <iframe :src="info.modelUrl"></iframe>
+      </div>
+      <div class="bottom">
+        <span class="title">{{info.name}}</span>
+        <!-- <rich-text :nodes="info.content"></rich-text> -->
+        <div class="content" v-html="info.content" @click="showImg"></div>
+      </div>
+      <!-- 富文本中图片放大预览部分 -->
+      <div class="previewImg" @click="imgShowHandler" v-show="imgShow">
+        <img :src="previewImg" alt="" />
+      </div>
+      <div class="levitated-box">
+        <img
+          width="40px"
+          height="40px"
+          :src="`https://houseoss.4dkankan.com/project/bjfljtl/img/bottomInco/collectIcon${isCollectedInfo ? 'Ac' : ''}.png`"
+          @click="collecttion"
+        />
+      </div>
+    </div>
+
+    <!-- 微信的SDK -->
+    <script
+      type="text/javascript"
+      src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"
+    ></script>
+    <!-- uni 的 SDK -->
+    <script
+      type="text/javascript"
+      src="https://unpkg.com/@dcloudio/uni-webview-js@0.0.3/index.js"
+    ></script>
+
+    <script src="./axios.min.js"></script>
+    <script>
+      var app = new Vue({
+        el: "#app",
+        data() {
+          return {
+            info: {},
+            isCollectedInfo: false,
+            previewImg: "",
+            imgShow: false,
+          };
+        },
+        mounted() {},
+        beforCreat() {},
+        created() {
+          let _this = this;
+          const params = this.urlParameter(window.location.href);
+          console.log(params, parseInt(params.isCollected) == "1");
+          this.isCollectedInfo =
+            parseInt(params.isCollected) == "1" ? true : false;
+          console.log(this.isCollectedInfo);
+          axios({
+            method: "get",
+            url: `https://wxfalangchang.4dage.com/api/wxShow/goods/detail/${params.id}`,
+          }).then(function (resp) {
+            _this.info = resp.data.data;
+            _this.info.content = _this.formatRichText(_this.info.content);
+          });
+        },
+        watch: {
+          info: {
+            handler(newValue, oldValue) {
+              console.log("刷新", newValue, oldValue);
+            },
+            immediate: true,
+            deep: true,
+          },
+        },
+        methods: {
+          // v-html模块点击
+          showImg(e) {
+            if (e.target.tagName == "IMG") {
+              this.previewImg = e.target.src;
+              this.imgShow = true;
+            }
+          },
+          imgShowHandler() {
+            this.imgShow = false;
+          },
+          urlParameter(data) {
+            if (data) {
+              const query = data.substring(data.indexOf("?") + 1);
+              const arr = query.split("&");
+              const params = {};
+              arr.forEach((v) => {
+                const key = v.substring(0, v.indexOf("="));
+                const val = v.substring(v.indexOf("=") + 1);
+                params[key] = val;
+              });
+              return params;
+            } else return {};
+          },
+          // 富文本解析
+          formatRichText(html) {
+            let newContent = html.replace(
+              /<img[^>]*>/gi,
+              function (match, capture) {
+                match = match
+                  .replace(/style="[^"]+"/gi, "")
+                  .replace(/style='[^']+'/gi, "");
+                match = match
+                  .replace(/width="[^"]+"/gi, "")
+                  .replace(/width='[^']+'/gi, "");
+                match = match
+                  .replace(/height="[^"]+"/gi, "")
+                  .replace(/height='[^']+'/gi, "");
+                let isExist = match.includes("https://");
+                if (!isExist) {
+                  match = match.replace(
+                    /(src=")/gi,
+                    'src="https://wxfalangchang.4dage.com'
+                  );
+                }
+                return match;
+              }
+            );
+            newContent = newContent.replace(
+              /style="[^"]+"/gi,
+              function (match, capture) {
+                match = match
+                  .replace(/width:[^;]+;/gi, "max-width:100%;")
+                  .replace(/width:[^;]+;/gi, "max-width:100%;");
+                return match;
+              }
+            );
+            newContent = newContent.replace(/<br[^>]*\/>/gi, "");
+            newContent = newContent.replace(
+              /\<img/gi,
+              '<img style="max-width:100%;height:auto;display:inline-block;margin:10rpx auto;"'
+            );
+            return newContent;
+          },
+          // 收藏
+          collecttion() {
+            const params = this.urlParameter(window.location.href);
+            console.log(params);
+
+            console.log(params.isLogin);
+            if (params.isLogin == "1") {
+              this.isCollectedInfo = !this.isCollectedInfo;
+              uni.postMessage({
+                data: {
+                  action: this.isCollectedInfo ? 1 : 0,
+                },
+              });
+            } else {
+              alert("身份过期,请重新登录");
+              uni.reLaunch({
+                url: "../../../mine/index",
+              });
+            }
+          },
+        },
+      });
+    </script>
+  </body>
+</html>

+ 43 - 0
小程序/guildsvg/flexible.js

@@ -0,0 +1,43 @@
+(function flexible(window, document) {
+  var docEl = document.documentElement;
+  var dpr = window.devicePixelRatio || 1;
+
+  // adjust body font size
+  function setBodyFontSize() {
+    if (document.body) {
+      document.body.style.fontSize = 12 * dpr + "px";
+    } else {
+      document.addEventListener("DOMContentLoaded", setBodyFontSize);
+    }
+  }
+  setBodyFontSize();
+
+  // set 1rem = viewWidth / 10
+  function setRemUnit() {
+    var rem = docEl.clientWidth / 24;
+    docEl.style.fontSize = rem + "px";
+  }
+
+  setRemUnit();
+
+  // reset rem unit on page resize
+  window.addEventListener("resize", setRemUnit);
+  window.addEventListener("pageshow", function (e) {
+    if (e.persisted) {
+      setRemUnit();
+    }
+  });
+
+  // detect 0.5px supports
+  if (dpr >= 2) {
+    var fakeBody = document.createElement("body");
+    var testElement = document.createElement("div");
+    testElement.style.border = ".5px solid transparent";
+    fakeBody.appendChild(testElement);
+    docEl.appendChild(fakeBody);
+    if (testElement.offsetHeight === 1) {
+      docEl.classList.add("hairlines");
+    }
+    docEl.removeChild(fakeBody);
+  }
+})(window, document);

文件差异内容过多而无法显示
+ 1372 - 0
小程序/guildsvg/map.svg


文件差异内容过多而无法显示
+ 1775 - 0
小程序/guildsvg/svg.html


文件差异内容过多而无法显示
+ 327 - 0
小程序/history.json


+ 2 - 0
小程序/jingtailan/.env.dev

@@ -0,0 +1,2 @@
+NODE_ENV = 'development'
+VITE_BASE_API = "http://192.168.20.48:3000/data/"

+ 2 - 0
小程序/jingtailan/.env.pro

@@ -0,0 +1,2 @@
+NODE_ENV = production
+VITE_BASE_API = "http://192.168.20.48:3000/data"

+ 21 - 0
小程序/jingtailan/.gitignore

@@ -0,0 +1,21 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+.DS_Store
+dist
+*.local
+
+# Editor directories and files
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

+ 35 - 0
小程序/jingtailan/.vscode/vue-setup.code-snippets

@@ -0,0 +1,35 @@
+{
+	// Place your 全局 snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and 
+	// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope 
+	// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is 
+	// used to trigger the snippet and the body will be expanded and inserted. Possible variables are: 
+	// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. 
+	// Placeholders with the same ids are connected.
+	// Example:
+	// "Print to console": {
+	// 	"scope": "javascript,typescript",
+	// 	"prefix": "log",
+	// 	"body": [
+	// 		"console.log('$1');",
+	// 		"$2"
+	// 	],
+	// 	"description": "Log output to console"
+	// }
+	"setup": {
+		"prefix": "setup",
+		"body": [
+			"<script setup lang='ts'>",
+			"\t",
+			"</script>",
+			"\t",
+			"<template>",
+			"\t",
+			"</template>",
+			"\t",
+			"<style lang='scss' scoped>",
+			"\t",
+			"</style>"
+		],
+		"description": "vue3语法糖"
+	}
+}

+ 51 - 0
小程序/jingtailan/history.json

@@ -0,0 +1,51 @@
+{
+  "corporationInfo": [
+    {
+      "text": "第一段文字",
+      "image": ""
+    },
+    {
+      "text": "第二段文字",
+      "image": "https://4d-tjw.oss-cn-shenzhen.aliyuncs.com/project/bjfljtl/img/data/C1Visit/home/3.png"
+    },
+    {
+      "text": "第一段文字",
+      "image": ""
+    },
+    {
+      "text": "第四段文字",
+      "image": "https://4d-tjw.oss-cn-shenzhen.aliyuncs.com/project/bjfljtl/img/data/C1Visit/home/3.png"
+    },
+    {
+      "text": "第一段文字",
+      "image": ""
+    }
+  ],
+  "year": [
+    {
+      "totle": "1890-1900",
+      "detail": [
+        {
+          "time": "一九五六年一月",
+          "content": "实行了全行业的公私合营 \n 42家人作坊公私合营成立北京法琅厂,钱美华设计的我国第一张景秦蓝图纸完成手稿",
+          "image": ""
+        },
+        {
+          "time": "一九五六年一月",
+          "content": "实行了全行业的公私合营 \n 42家人作坊公私合营成立北京法琅厂,钱美华设计的我国第一张景秦蓝图纸完成手稿",
+          "image": "https://4d-tjw.oss-cn-shenzhen.aliyuncs.com/project/bjfljtl/img/data/C1Visit/home/1.png"
+        },
+        {
+          "time": "一九五六年一月",
+          "content": "实行了全行业的公私合营 \n 42家人作坊公私合营成立北京法琅厂,钱美华设计的我国第一张景秦蓝图纸完成手稿",
+          "image": "https://4d-tjw.oss-cn-shenzhen.aliyuncs.com/project/bjfljtl/img/data/C1Visit/home/1.png"
+        },
+        {
+          "time": "一九五六年一月",
+          "content": "实行了全行业的公私合营 \n 42家人作坊公私合营成立北京法琅厂,钱美华设计的我国第一张景秦蓝图纸完成手稿",
+          "image": "https://4d-tjw.oss-cn-shenzhen.aliyuncs.com/project/bjfljtl/img/data/C1Visit/home/1.png"
+        }
+      ]
+    }
+  ]
+}

+ 20 - 0
小程序/jingtailan/index.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8" />
+    <script>
+      var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
+        CSS.supports('top: constant(a)'))
+      document.write(
+        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
+        (coverSupport ? ', viewport-fit=cover' : '') + '" />')
+    </script>
+    <title></title>
+    <!--preload-links-->
+    <!--app-context-->
+  </head>
+  <body>
+    <div id="app"><!--app-html--></div>
+    <script type="module" src="/src/main.ts"></script>
+  </body>
+</html>

文件差异内容过多而无法显示
+ 21146 - 0
小程序/jingtailan/package-lock.json


+ 76 - 0
小程序/jingtailan/package.json

@@ -0,0 +1,76 @@
+{
+  "name": "uni-preset-vue",
+  "version": "0.0.0",
+  "scripts": {
+    "dev:app": "uni -p app",
+    "dev:app-android": "uni -p app-android",
+    "dev:app-ios": "uni -p app-ios",
+    "dev:custom": "uni -p",
+    "dev:h5": "uni",
+    "dev:h5:ssr": "uni --ssr",
+    "dev:mp-alipay": "uni -p mp-alipay",
+    "dev:mp-baidu": "uni -p mp-baidu",
+    "dev:mp-jd": "uni -p mp-jd",
+    "dev:mp-kuaishou": "uni -p mp-kuaishou",
+    "dev:mp-lark": "uni -p mp-lark",
+    "dev:mp-qq": "uni -p mp-qq",
+    "dev:mp-toutiao": "uni -p mp-toutiao",
+    "dev:mp-weixin": "uni -p mp-weixin",
+    "dev:quickapp-webview": "uni -p quickapp-webview",
+    "dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
+    "dev:quickapp-webview-union": "uni -p quickapp-webview-union",
+    "build:app": "uni build -p app",
+    "build:app-android": "uni build -p app-android",
+    "build:app-ios": "uni build -p app-ios",
+    "build:custom": "uni build -p",
+    "build:h5": "uni build",
+    "build:h5:ssr": "uni build --ssr",
+    "build:mp-alipay": "uni build -p mp-alipay",
+    "build:mp-baidu": "uni build -p mp-baidu",
+    "build:mp-jd": "uni build -p mp-jd",
+    "build:mp-kuaishou": "uni build -p mp-kuaishou",
+    "build:mp-lark": "uni build -p mp-lark",
+    "build:mp-qq": "uni build -p mp-qq",
+    "build:mp-toutiao": "uni build -p mp-toutiao",
+    "build:mp-weixin": "uni build -p mp-weixin",
+    "build:quickapp-webview": "uni build -p quickapp-webview",
+    "build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
+    "build:quickapp-webview-union": "uni build -p quickapp-webview-union",
+    "type-check": "vue-tsc --noEmit"
+  },
+  "dependencies": {
+    "@dcloudio/uni-app": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-app-plus": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-components": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-h5": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-mp-alipay": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-mp-baidu": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-mp-jd": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-mp-kuaishou": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-mp-lark": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-mp-qq": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-mp-toutiao": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-mp-weixin": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-quickapp-webview": "3.0.0-alpha-3070720230316001",
+    "animate.css": "^4.1.1",
+    "axios": "^1.4.0",
+    "eslint": "^8.42.0",
+    "mp-html": "^2.4.2",
+    "uview-ui": "^2.0.31",
+    "vue": "^3.2.45",
+    "vue-i18n": "^9.1.9"
+  },
+  "devDependencies": {
+    "@dcloudio/types": "^3.3.2",
+    "@dcloudio/uni-automator": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-cli-shared": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/uni-stacktracey": "3.0.0-alpha-3070720230316001",
+    "@dcloudio/vite-plugin-uni": "3.0.0-alpha-3070720230316001",
+    "@vue/tsconfig": "^0.1.3",
+    "sass": "^1.63.4",
+    "sass-loader": "^10.4.1",
+    "typescript": "^4.9.4",
+    "vite": "4.0.4",
+    "vue-tsc": "^1.0.24"
+  }
+}

+ 29 - 0
小程序/jingtailan/project.config.json

@@ -0,0 +1,29 @@
+{
+    "appid": "wxbf5bad7c11ef4b33",
+    "compileType": "miniprogram",
+    "libVersion": "2.32.2",
+    "packOptions": {
+        "ignore": [],
+        "include": []
+    },
+    "setting": {
+        "coverView": true,
+        "es6": true,
+        "postcss": true,
+        "minified": true,
+        "enhance": true,
+        "showShadowRootInWxmlPanel": true,
+        "packNpmRelationList": [],
+        "babelSetting": {
+            "ignore": [],
+            "disablePlugins": [],
+            "outputPath": ""
+        },
+        "condition": false
+    },
+    "condition": {},
+    "editorSetting": {
+        "tabIndent": "insertSpaces",
+        "tabSize": 4
+    }
+}

+ 7 - 0
小程序/jingtailan/project.private.config.json

@@ -0,0 +1,7 @@
+{
+    "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
+    "projectname": "jingtailan",
+    "setting": {
+        "compileHotReLoad": true
+    }
+}

+ 124 - 0
小程序/jingtailan/src/App.vue

@@ -0,0 +1,124 @@
+<script setup lang="ts">
+import { onLaunch, onShow, onHide } from "@dcloudio/uni-app";
+import commonn from "./static/data/common";
+
+// 背景音乐播放 ios  解决静音模式下音乐无法播放的兼容问题
+/**
+* 比较wx SDKVersion
+* @param {String} v1 版本字符串
+* @param {String} v2 版本字符串
+* @returns {Number} v1>v2,返回1;v1<v2,返回-1;v1==v2,返回0
+*/
+const compareVersion = (v1: any, v2: any) => {
+  v1 = v1.split('.');
+  v2 = v2.split('.');
+  const len = Math.max(v1.length, v2.length);
+  while (v1.length < len) {
+    v1.push('0');
+  }
+  while (v2.length < len) {
+    v2.push('0');
+  }
+  for (let i = 0; i < len; i++) {
+    const num1 = parseInt(v1[i]);
+    const num2 = parseInt(v2[i]);
+    if (num1 > num2) {
+      return 1;
+    }
+    if (num1 < num2) {
+      return -1;
+    }
+  }
+  return 0;
+}
+
+const canIUseWxAudio = () => {
+  const version = wx.getSystemInfoSync().SDKVersion;
+  if (compareVersion(version, '2.3.0') >= 0) {
+    wx.setInnerAudioOption({
+      obeyMuteSwitch: false
+    })
+  } else {
+    wx.showModal({
+      title: '提示',
+      content: '当前微信版本过低,手机开启静音模式下可能会导致播放音频失败。'
+    })
+  }
+}
+
+// 项目禁止在PC使用,只能使用手机使用
+const onlyPhone = () => {
+  try {
+    const res = wx.getSystemInfoSync()
+    if (res.platform == 'windows' || res.platform == 'mac' ) {
+      wx.showModal({
+        title: '温馨提示!',
+        content: '请使用手机端打开',
+        showCancel: false,
+        success(res) {
+          wx.exitMiniProgram()//关闭当前小程序
+        }
+      });
+      return;
+    }
+  } catch (e) {
+  }
+}
+onLaunch(() => {
+  console.log("App Launch");
+  // 存放首次进入
+  uni.setStorageSync('FIRST_KEY', 1);
+});
+onShow(() => {
+  onlyPhone()
+  canIUseWxAudio()
+  commonn.innerAudioContext.src = 'https://houseoss.4dkankan.com/project/bjfljtl/audio/bgMusic.mp3'
+  commonn.innerAudioContext.autoplay = true
+  commonn.innerAudioContext.loop = true
+  commonn.innerAudioContext.play()
+  // commonn.innerAudioContext.onPlay(() => {
+  //   // alert('音乐开始播放')
+  //   uni.showToast({
+  //     title: "音乐开始播放",
+  //     icon: "none",
+  //     duration: 1000,
+  //   });
+  // })
+  // commonn.innerAudioContext.onError((err: any) => {
+  //   uni.showToast({
+  //     title: err,
+  //     icon: "none",
+  //     duration: 1000,
+  //   });
+  // })
+  commonn.musicSta = true
+});
+onHide(() => {
+  console.log("App Hide");
+});
+</script>
+<style>
+@font-face {
+  font-family: "SOURCEHANSERIFCN-BOLD";
+  /* 字体名称 */
+  src: url("https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/SOURCEHANSERIFCN-BOLD.oft");
+  /* 字体文件相对路径 */
+}
+
+body {
+  background: #F7F1E6;
+  width: 100vw;
+  /* height: 100vh; */
+}
+
+
+wx-swiper .wx-swiper-dot {
+  position: relative;
+  bottom: 24rpx;
+}
+
+uni-tabbar,
+uni-tabbar .uni-tabbar {
+  box-shadow: 0px -2px 10px 0px rgba(132, 85, 250, 0.82);
+}
+</style>

+ 17 - 0
小程序/jingtailan/src/api/api/analyse/index.ts

@@ -0,0 +1,17 @@
+import { request } from "@/api/request";
+
+export const AnalyseApi = {
+  // 赏析列表
+  getAnalyseList: () => request("/wxShow/config/getAppreciate", "GET", {}),
+
+  // 赏析详情
+  getAnalyseDetail: (id: Number) =>
+    request(`/wxShow/config/detail/${id}`, "GET", {}),
+
+  // 藏品列表
+  getGoodsList: (data: any) => request(`/wxShow/goods/pageList/`, "POST", data),
+
+  // 藏品详情
+  getGoodDetail: (id: Number) =>
+    request(`/wxShow/goods/detail/${id}`, "GET", {}),
+};

+ 11 - 0
小程序/jingtailan/src/api/api/explore/craft/index.ts

@@ -0,0 +1,11 @@
+import { request } from "@/api/request";
+
+export const CraftApi = {
+  // 获得工艺列表
+  getCraftList: (data: any) =>
+    request("/wxShow/craft/pageList", "POST", data),
+
+  // 获得工艺细节
+  getCraftDetail: (id: Number) =>
+    request(`/wxShow/craft/detail/${id}`, "GET", { }),
+};

+ 7 - 0
小程序/jingtailan/src/api/api/explore/gift/index.ts

@@ -0,0 +1,7 @@
+import { request } from "@/api/request";
+
+export const GiftApi = {
+  // 获得国礼详情
+  getGoodDetail: (id: Number) =>
+    request(`/wxShow/config/detail/${id}`, "GET", {}),
+};

+ 11 - 0
小程序/jingtailan/src/api/api/explore/great/index.ts

@@ -0,0 +1,11 @@
+import { request } from "@/api/request";
+
+export const GreatApi = {
+  // 大师列表
+  getGreatList: (data: any) =>
+    request("/wxShow/master/pageList", "POST", data),
+
+  // 大师详情
+  getGreatDetail: (id: Number) =>
+    request(`/wxShow/master/detail/${id}`, "GET", { }),
+};

+ 12 - 0
小程序/jingtailan/src/api/api/explore/index.ts

@@ -0,0 +1,12 @@
+import { request } from "@/api/request";
+
+export const ExploreApi = {
+  // 获得探索菜单
+  getExplore: () => request("/wxShow/config/getExplore", "GET", {}),
+
+  getModelList: (data: any) => request("/wxShow/block/pageList", "POST", data),
+ 
+  // 获得国礼详情
+  getModelDetail: (id: Number) =>
+    request(`/wxShow/block/detail/${id}`, "GET", {}),
+};

+ 12 - 0
小程序/jingtailan/src/api/api/home/index.ts

@@ -0,0 +1,12 @@
+import { request } from "@/api/request";
+
+export const HomeApi = {
+  // 获得探索菜单
+  getExplore: () => request("/wxShow/config/getExplore", "GET", {}),
+  // 统计浏览量
+  sendVisit: () =>
+    request("/wxShow/trend/saveType", "POST", {
+      num: "wxfalangchang",
+      type: "visit",
+    }),
+};

+ 11 - 0
小程序/jingtailan/src/api/api/login/index.ts

@@ -0,0 +1,11 @@
+import { request } from "@/api/request";
+
+export const LogonApi = {
+  // 检查登录
+  checkToken: () => request("/wx/checkToken", "GET", {}),
+
+  // 授权登录
+  login: (code: any) => request(`/wx/login/${code}`,"GET",{})
+};
+
+

+ 35 - 0
小程序/jingtailan/src/api/api/mine/index.ts

@@ -0,0 +1,35 @@
+import { request } from "@/api/request";
+
+export const MineApi = {
+  // 文物收藏
+  getGoodstList: (data: any) => request("/cms/my/goods/pageList", "POST", data),
+
+  // 内容收藏
+  getContentList: (data: any) =>
+    request("/cms/my/collect/pageList", "POST", data),
+
+  // 提交留言
+  submitMeg: (content: String, nickName: String) =>
+    request(`/cms/my/msg?content=${content}&nickName=${nickName}`, "POST", {}),
+
+  // 收藏行为
+  collectUpdate: (data: any) => request("/cms/my/collectUpdate", "POST", data),
+
+  // 检查koten
+  checkToken: () => request("/wx/checkToken", "GET", {}),
+
+  // 更新用户信息
+  getUserInfo: () => request("/cms/my/getUserInfo", "GET", {}),
+
+  // 更新用户信息
+  updateUser: (data: any) => request("/cms/my/update", "POST", data),
+
+  // 用户微信头像上传
+  uploadAvatarUrl: (data: any) => request("/cms/my/upload", "POST", data),
+
+  // 收藏详情
+  collectDetail: (data: any) => request("/cms/my/collect/detail", "POST", data),
+
+  // 第三方平台详情信息
+  tripartiteList:() => request("/wxShow/platform", "POST", {})
+};

+ 18 - 0
小程序/jingtailan/src/api/api/visit/index.ts

@@ -0,0 +1,18 @@
+import { request } from "@/api/request";
+
+export const VisitApi = {
+  // 获取历史json数据
+  getHistoryData: () =>
+    request(
+      "https://4d-tjw.oss-cn-shenzhen.aliyuncs.com/project/bjfljtl/history.json",
+      "GET",
+      {}
+    ),
+  // 获得公司简介
+  getCompanyProfile: () => request("/wxShow/block/company", "GET", {}),
+  // 获得公司历史年代专题
+  getChronology: () => request("/wxShow/getDictAge", "GET", {}),
+  // 获得年代专题下的各事件
+  getLogsList: (id: number) =>
+    request(`/wxShow/companyHistory/${id}`, "POST", {}),
+};

+ 1 - 0
小程序/jingtailan/src/api/record.ts

@@ -0,0 +1 @@
+export const baseIMGUrl ='https://houseoss.4dkankan.com/project/bjfljtl/img'

+ 106 - 0
小程序/jingtailan/src/api/request.ts

@@ -0,0 +1,106 @@
+import { MineApi } from "./api/mine";
+
+//设置基地址
+export const baseUrl = "https://wxfalangchang.4dage.com/api";
+export const baseIMGUrl = "https://wxfalangchang.4dage.com";
+
+//封装请求
+function request(
+  url: string,
+  method: "GET" | "POST",
+  data: string | object | ArrayBuffer
+) {
+  return new Promise((resolve, reject) => {
+    let token = uni.getStorageSync("JTL_token");
+    //发起uni请求
+    uni.request({
+      url: baseUrl + url, //路径
+      method,
+      data,
+      header: {
+        // 根据实际接口设计 key 取 token 或者 authorization
+        token: token,
+        "Content-Type": "application/json",
+      },
+      //进入接口成功
+      success: (res) => {
+        if (res.statusCode == 200) {
+          if (res.data.code === 5001 || res.data.code === 5002) {
+            uni.showToast({
+              title: "信息过期,请重新登录",
+              icon: "none",
+              duration: 1000,
+            });
+            setTimeout(async () => {
+              // 身份过期了要移除
+              uni.removeStorage({
+                key: "JTL_token",
+              });
+              uni.removeStorage({
+                key: "JTL_userInfo",
+              });
+              const pages = getCurrentPages();
+              let currentPage = pages[pages.length - 1];
+              if (currentPage.route != "pages/mine/index") {
+                uni.reLaunch({
+                  url: "/pages/mine/index",
+                });
+              }
+            }, 300);
+          } else {
+            resolve(res);
+          }
+        } else if (res.statusCode == 5001) {
+          resolve(res);
+        } else if (res.statusCode == 500) {
+          uni.showToast({
+            title: "服务器错误",
+            icon: "none",
+            duration: 1000,
+          });
+          resolve(res);
+        } else if (res.statusCode == 202) {
+          uni.showToast({
+            title: "服务器错误",
+            icon: "none",
+            duration: 1000,
+          });
+          resolve(res);
+        } else {
+          uni.showToast({
+            title: "服务器错误",
+            icon: "none",
+            duration: 1000,
+          });
+          resolve(res);
+        }
+      },
+      // 进入接口失败
+      fail: (err) => {
+        uni.showToast({
+          title: "服务器错误",
+          icon: "none",
+          duration: 1000,
+        });
+        reject(err);
+      },
+    });
+  });
+}
+
+// 加载器开关
+
+// 封装全局请求拦截器
+uni.addInterceptor("request", {
+  // 请求之前的一些处理操作
+  invoke(requestConfig: any) {
+    uni.showLoading({
+      title: "请稍等...",
+    });
+  },
+  success() {
+    uni.hideLoading();
+  },
+});
+//抛出
+export { request };

+ 191 - 0
小程序/jingtailan/src/components/ModelDeatil copy.vue

@@ -0,0 +1,191 @@
+<script setup lang="ts">
+import { ref } from "vue";
+import * as baseInfo from "@/api/record";
+import { baseIMGUrl } from "@/api/request";
+
+import { MineApi } from "@/api/api/mine";
+import { onMounted } from "vue";
+
+// 传入参数
+const props = defineProps({
+  detail: {
+    type: Object,
+    default: {},
+  },
+  type: {
+    type: String,
+    default: "craft",
+  },
+  modelId: {
+    type: Number,
+    default: 0,
+  },
+});
+
+// 判断是否被收藏过
+const isCollected = async () => {
+  console.log("经过了判断");
+  // 拿到全部收藏
+  const res: any = await MineApi.getContentList({
+    pageNum: 1,
+    pageSize: 1000000,
+    searchKey: "",
+  });
+  setTimeout(async () => {
+    if (res.data.code === 0) {
+      const greatList = await res.data.data.records.find((item: any) => {
+        return item.moduleId == props.modelId;
+      });
+      if (greatList) {
+        isCollectedInfo.value = true;
+        return;
+      }
+      return;
+    } else {
+      return;
+    }
+  });
+};
+
+const isCollectedInfo = ref(false);
+const data = ref({
+  has: 0,
+  moduleId: 1,
+  moduleType: props.type,
+  name: "",
+});
+
+// 收藏
+const collect = async () => {
+  isCollectedInfo.value = !isCollectedInfo.value;
+  data.value.has = isCollectedInfo.value ? 1 : 0;
+  data.value.moduleId = props.detail.entity.id;
+  data.value.name = props.detail.entity.name;
+  // 检查token
+  const ress: any = await MineApi.checkToken();
+  if (ress.data.data) {
+    const res: any = await MineApi.collectUpdate(data.value);
+    if (res.data.code === 0) {
+      uni.showToast({
+        title: isCollectedInfo.value ? "收藏成功" : "取消成功",
+        icon: "none",
+      });
+    }
+  } else {
+    console.log('输出详情页面')
+    uni.showToast({
+      title: "身份过期,请重新登录",
+      icon: "none",
+    });
+    uni.removeStorage({
+      key: "JTL_token",
+    });
+    uni.removeStorage({
+      key: "JTL_userInfo",
+    });
+    setTimeout(() => {
+      uni.reLaunch({
+        url: "../../../mine/index",
+      });
+    }, 1000);
+  }
+};
+
+// 图片单张预览
+const previewImg = (previewImgUrl: String) => {
+  let _this = this;
+  let imgsArray = [];
+  //根据api拼接
+  imgsArray[0] = baseIMGUrl + previewImgUrl;
+  uni.previewImage({
+    current: 0,
+    urls: imgsArray,
+    showmenu: false
+  });
+};
+
+onMounted(() => {
+  isCollected();
+  console.log(props.detail.entity.content);
+});
+</script>
+
+<template>
+  <view class="all" v-if="JSON.stringify(detail) != '{}'">
+    <view class="top" v-if="detail.entity?.video != ''">
+      <video :src="detail.entity?.video ? baseIMGUrl + detail.entity?.video : ''"></video>
+    </view>
+    <view class="bottom">
+      <view class="bottom-title">{{ detail.entity?.name }}</view>
+      <view class="bottom-text">{{ detail.entity?.content }}</view>
+      <image :src="baseIMGUrl + item.filePath" mode="widthFix" v-for="item in detail.file" :key="item.id"
+        @tap="previewImg(item.filePath)" />
+    </view>
+    <view class="levitated-box">
+      <image :src="baseInfo.baseIMGUrl +
+        `/bottomInco/collectIcon${isCollectedInfo ? 'Ac' : ''}.png`
+        " mode="scaleToFill" @tap="collect" />
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.all {
+  width: 100%;
+  height: 100vh;
+  background: #f7f1e6;
+
+  .top {
+    width: 100%;
+    height: 35vh;
+
+    video {
+      width: 100%;
+      height: 100%;
+    }
+  }
+
+  .bottom {
+    width: 100%;
+    box-sizing: border-box;
+    padding: 10px 40px;
+    background: #f7f1e6;
+    position: relative;
+
+    &-title {
+      width: 100%;
+      text-align: center;
+      font-weight: bold;
+      margin-bottom: 20px;
+    }
+
+    &-text {
+      font-size: 12px;
+      line-height: 23px;
+      margin-bottom: 20px;
+      white-space: pre-wrap;
+    }
+  }
+
+  image {
+    width: 100%;
+  }
+
+  // 悬浮球
+  .levitated-box {
+    background-color: #00000080;
+    border-radius: 50px;
+    width: 50px;
+    height: 50px;
+    padding: 10px;
+    box-sizing: border-box;
+    position: fixed;
+    right: 30px;
+    bottom: 50px;
+
+    image {
+      height: 100%;
+    }
+  }
+}
+</style>

+ 282 - 0
小程序/jingtailan/src/components/ModelDeatil.vue

@@ -0,0 +1,282 @@
+<script setup lang="ts">
+import { nextTick, ref, computed, watch } from "vue";
+import * as baseInfo from "@/api/record";
+import { baseIMGUrl } from "@/api/request";
+import commonn from "@/static/data/common";
+
+
+import { MineApi } from "@/api/api/mine";
+import { onMounted } from "vue";
+import { onShow } from "@dcloudio/uni-app";
+import { onUnmounted } from "vue";
+
+// 传入参数
+const props = defineProps({
+  detail: {
+    type: Object,
+    default: {
+      name: 'aa'
+    },
+  },
+  type: {
+    type: String,
+    default: "craft",
+  },
+  modelId: {
+    type: Number,
+    default: 0,
+  },
+});
+
+// const { detailF, typeF, modelIdF } = props
+
+const detailF = ref({})
+
+const musicStaRe = ref(false)
+
+let audio = null as any
+// const playAudio = () => {
+//   audio = uni.createInnerAudioContext()
+//   musicStaRe.value = commonn.musicSta
+//   if (musicStaRe.value) {
+//     // 先暂停背景音频
+//     commonn.innerAudioContext.pause()
+//     commonn.musicSta = false
+//   }
+//   // 设置播放音频链接
+
+//   audio.src = `https://houseoss.4dkankan.com/project/bjfljtl/audio/data/B1Seek/${detailF.value.entity.name}.mp3`;
+//   audio.autoplay = true
+//   audio.play()
+//   audio.onPlay(() => {
+//     console.log('在播啦')
+//   })
+//   // audio.play()
+
+//   // commonn.introAudioContext.src = `https://houseoss.4dkankan.com/project/bjfljtl/audio/data/B1Seek/${detailF.value.entity.name}.mp3`;
+//   // console.log(commonn.introAudioContext.src)
+//   // commonn.introAudioContext.currentTime = 0
+//   // commonn.introAudioContext.play()
+// }
+
+// watch(props, (newVal: any) => {
+//   if (newVal) {
+//     detailF.value = newVal.detail
+//     console.log(newVal.detail.entity.name)
+//     if (newVal.detail.entity.name == '四面方尊' || newVal.detail.entity.name == '民族团结' || newVal.detail.entity.name == '盛世欢歌') {
+//       playAudio()
+//     }
+//   }
+// }, { immediate: true })
+
+
+// 判断是否被收藏过
+const isCollected = async () => {
+  console.log("经过了判断");
+  // 拿到全部收藏
+  const res: any = await MineApi.getContentList({
+    pageNum: 1,
+    pageSize: 1000000,
+    searchKey: "",
+  });
+  setTimeout(async () => {
+    if (res.data.code === 0) {
+      const greatList = await res.data.data.records.find((item: any) => {
+        return item.moduleId == props.modelId;
+      });
+      if (greatList) {
+        isCollectedInfo.value = true;
+        return;
+      }
+      return;
+    } else {
+      return;
+    }
+  }, 50);
+};
+
+const isCollectedInfo = ref(false);
+const data = ref({
+  has: 0,
+  moduleId: 1,
+  moduleType: props.type,
+  name: "",
+});
+
+// 收藏
+const collect = async () => {
+  isCollectedInfo.value = !isCollectedInfo.value;
+  data.value.has = isCollectedInfo.value ? 1 : 0;
+  data.value.moduleId = props.detail.entity.id;
+  data.value.name = props.detail.entity.name;
+  // 检查token
+  const ress: any = await MineApi.checkToken();
+  if (ress.data.data) {
+    const res: any = await MineApi.collectUpdate(data.value);
+    if (res.data.code === 0) {
+      uni.showToast({
+        title: isCollectedInfo.value ? "收藏成功" : "取消成功",
+        icon: "none",
+      });
+    }
+  } else {
+    console.log("输出详情页面");
+    uni.showToast({
+      title: "身份过期,请重新登录",
+      icon: "none",
+    });
+    uni.removeStorage({
+      key: "JTL_token",
+    });
+    uni.removeStorage({
+      key: "JTL_userInfo",
+    });
+    setTimeout(() => {
+      uni.reLaunch({
+        url: "../../../mine/index",
+      });
+    }, 1000);
+  }
+};
+
+// 图片单张预览
+const previewImg = (previewImgUrl: String) => {
+  let _this = this;
+  let imgsArray = [];
+  //根据api拼接
+  imgsArray[0] = baseIMGUrl + previewImgUrl;
+  uni.previewImage({
+    current: 0,
+    urls: imgsArray,
+    showmenu: false
+
+  });
+};
+
+
+nextTick(() => {
+})
+onShow(() => {
+  console.log(props.detail, props.modelId,props.type)
+})
+onMounted(() => {
+  isCollected();
+  // console.log(JSON.parse(JSON.stringify(JSON.parse(JSON.stringify(props)).detail)).nane, props, props.modelId, props.type)
+  // setTimeout(() => {
+  //   detailF.value = props.detail
+  //   if (detailF.value.entity.name == '四面方尊' || detailF.value.entity.name == '民族团结' || detailF.value.entity.name == '盛世欢歌') {
+  //     audio = uni.createInnerAudioContext()
+  //     musicStaRe.value = commonn.musicSta
+  //     if (musicStaRe.value) {
+  //       // 先暂停背景音频
+  //       commonn.innerAudioContext.pause()
+  //       commonn.musicSta = false
+  //     }
+  //     // 设置播放音频链接
+  //     audio.src = `https://houseoss.4dkankan.com/project/bjfljtl/audio/data/B1Seek/${detailF.value.entity.name}.mp3`;
+  //     setTimeout(() => {
+  //       console.log(audio.src)
+  //       audio.autoplay = true
+  //       audio.play()
+  //     },50)
+  //   }
+  // }, 100)
+
+
+});
+
+// onUnmounted(() => {
+//   console.log(musicStaRe.value)
+//   if (musicStaRe.value) {
+//     commonn.innerAudioContext.play()
+//     commonn.musicSta = true
+//   }
+//   audio.pause()
+//   audio.src = ''
+//   audio.currentTime = 0
+//   audio = null
+// })
+</script>
+
+<template>
+  <view class="all" v-if="JSON.stringify(detail) != '{}'">
+    <view class="top" v-if="detail.entity?.video != ''">
+      <video :src="detail.entity?.video ? baseIMGUrl + detail.entity?.video : ''" @play="() => {
+        commonn.introAudioContext.pause()
+      }"
+        @pause="() => { commonn.introAudioContext.play(), commonn.introAudioContext.src = `https://houseoss.4dkankan.com/project/bjfljtl/audio/data/${props.type === 'block' ? 'B1Seek' : ''}/${detail.entity.name}.mp3`; }"></video>
+    </view>
+    <view class="bottom">
+      <view class="bottom-title">{{ detail.entity?.name }}</view>
+      <view class="bottom-text">{{ detail.entity?.content }}</view>
+      <image :src="baseIMGUrl + item.filePath" mode="widthFix" v-for="item in detail.file" :key="item.id"
+        @tap="previewImg(item.filePath)" />
+    </view>
+    <view class="levitated-box">
+      <image :src="baseInfo.baseIMGUrl +
+        `/bottomInco/collectIcon${isCollectedInfo ? 'Ac' : ''}.png`
+        " mode="scaleToFill" @tap="collect" />
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.all {
+  width: 100%;
+  height: 100vh;
+  background: #f7f1e6;
+
+  .top {
+    width: 100%;
+    height: 35vh;
+
+    video {
+      width: 100%;
+      height: 100%;
+    }
+  }
+
+  .bottom {
+    width: 100%;
+    box-sizing: border-box;
+    padding: 10px 40px;
+    background: #f7f1e6;
+    position: relative;
+
+    &-title {
+      width: 100%;
+      text-align: center;
+      font-weight: bold;
+      margin-bottom: 20px;
+    }
+
+    &-text {
+      font-size: 12px;
+      line-height: 23px;
+      margin-bottom: 20px;
+      white-space: pre-wrap;
+    }
+  }
+
+  image {
+    width: 100%;
+  }
+
+  // 悬浮球
+  .levitated-box {
+    background-color: #00000080;
+    border-radius: 50px;
+    width: 50px;
+    height: 50px;
+    padding: 10px;
+    box-sizing: border-box;
+    position: fixed;
+    right: 30px;
+    bottom: 50px;
+
+    image {
+      height: 100%;
+    }
+  }
+}
+</style>

+ 106 - 0
小程序/jingtailan/src/components/PageList.vue

@@ -0,0 +1,106 @@
+<script setup lang='ts'>
+import { baseIMGUrl } from '@/api/request'
+// 传入参数
+const props = defineProps({
+  background: {
+    type: Array<any>,
+    default: "",
+  },
+  list: {
+    type: Array<any>,
+    default: "",
+  },
+  next: {
+    type: String,
+    default: ""
+  }
+});
+
+const goTo = (path: String, id?: Number) => {
+  uni.navigateTo({ url: path + '?id=' + id })
+}
+
+</script>
+  
+<template>
+  <view class="all">
+    <view class="top">
+      <!-- <image :src="background" mode="widthFix" /> -->
+      <swiper class="swiper-box" :indicator-dots="background.length > 1 ? true : false" indicator-color="#b9b9b96c"
+        indicator-active-color="#000000" circular autoplay>
+        <swiper-item v-for="item in background" :key="item.id">
+          <image height="100%" :src="item" mode="aspectFill"></image>
+        </swiper-item>
+      </swiper>
+    </view>
+    <view class="bottom">
+      <view v-for="(item, index) in list" :key="index" class="bottom-item" >
+        <image :src="item?.thumb ? baseIMGUrl + item?.thumb : item.path" mode="aspectFit" @tap="goTo(next, item?.id)" />
+        <view class="text">{{ item?.text }}</view>
+      </view>
+    </view>
+  </view>
+</template>
+  
+<style lang='scss' scoped>
+.all {
+  width: 100%;
+
+  .top {
+    width: 100%;
+    height: 35vh;
+
+    .swiper-box {
+      width: 100%;
+      height: 100%;
+
+      image {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+  }
+
+  .bottom {
+    width: 100%;
+    margin-top: -15px;
+    box-sizing: border-box;
+    padding: 20px;
+    border-radius: 20px 20px 0 0;
+    background: #F7F1E6;
+
+    position: absolute;
+    z-index: 2;
+    min-height: calc(65vh + 15px);
+
+    // 两列
+    display: grid;
+    grid-template-columns: repeat(2, 50%);
+    grid-column-gap: 10px;
+    grid-row-gap: 5px;
+
+    &-item {
+      background: white;
+      border-radius: 5px;
+      height: 42vw;
+    }
+
+
+    image {
+      max-height: 300rpx;
+    }
+
+    .text {
+      font-size: 12px;
+      color: #00000080;
+    }
+
+  }
+
+  image {
+    width: 100%;
+    border-radius: 4px;
+  }
+}
+</style>

+ 208 - 0
小程序/jingtailan/src/components/PageListNoRow.vue

@@ -0,0 +1,208 @@
+<script setup lang="ts">
+import { baseIMGUrl } from "@/api/request";
+import { onLoad } from "@dcloudio/uni-app";
+import { ref, watch } from "vue";
+// 传入参数
+const props = defineProps({
+  background: {
+    type: Array<any>,
+    default: "",
+  },
+  list: {
+    type: Array<any>,
+    default: "",
+  },
+  next: {
+    type: String,
+    default: "",
+  },
+});
+
+const time = ref(0)
+
+
+// 开场动画
+const isAnimal = ref(false)
+
+// 图片阴影动画
+const isPicAnimal = ref(false)
+
+
+watch(time, (newVal, oldVal) => {
+  Number(newVal) <= 6 ? (isPicAnimal.value = true, setTimeout(() => { isPicAnimal.value = false; time.value += 1 }, 200)) : ''
+});
+
+const goTo = (path: String, id?: Number) => {
+  uni.navigateTo({ url: path + "?id=" + id });
+};
+onLoad(() => {
+  isAnimal.value = true
+  setTimeout(() => {
+    isAnimal.value = false
+  }, 500)
+  isPicAnimal.value = true
+  setTimeout(() => {
+    isPicAnimal.value = false
+    time.value += 1
+  }, 100)
+})
+</script>
+
+<template>
+  <view class="all" v-on:load="true">
+    <view class="top">
+      <!-- <image :src="background" mode="widthFix" /> -->
+      <image height="100%" :src="background[0]" mode="aspectFill" class="openAnimal"></image>
+
+      <!-- <swiper class="swiper-box" :indicator-dots="background.length > 1 ? true : false" indicator-color="#b9b9b96c"
+        indicator-active-color="#000000" circular autoplay>
+        <swiper-item v-for="item in background" :key="item.id">
+          <image height="100%" :src="item" mode="aspectFill"></image>
+        </swiper-item>
+      </swiper> -->
+    </view>
+    <view class="bottom" :class="{ 'animaled': isAnimal }">
+      <view class="bottom-item" :class="{ 'item-animal': isAnimal }" v-for="(item, index) in list" :key="index" :style="{
+        marginBottom:
+          index === list.length - 1 ? '' : item?.text ? '10px' : '',
+      }">
+        <image :src="item?.thumb ? baseIMGUrl + item?.thumb : item.path" mode="aspectFill" @tap="goTo(next, item?.id)"
+          :class="{ 'pic-animal': isPicAnimal && time === (index + 1) }" />
+        <view class="text">{{ item?.text }}</view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.all {
+  width: 100%;
+  background: #f7f1e6;
+
+  .top {
+    width: 100%;
+    height: 35vh;
+
+    .openAnimal {
+      animation: openAnimation 1.5s;
+    }
+
+    @keyframes openAnimation {
+      0% {
+        opacity: 0;
+      }
+
+      50% {
+        opacity: 0.5;
+
+      }
+
+      100% {
+        opacity: 1;
+      }
+    }
+
+    .swiper-box {
+      width: 100%;
+      height: 100%;
+
+      image {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+    image {
+      width: 100%;
+      height: 100%;
+    }
+  }
+
+  .bottom {
+    width: 100%;
+    margin-top: -15px;
+    box-sizing: border-box;
+    padding: 20px;
+    padding-top: 30px;
+    border-radius: 20px 20px 0 0;
+    background: #f7f1e6;
+    position: absolute;
+    z-index: 2;
+    min-height: calc(65vh + 15px);
+    box-shadow: 0px -4px 4px 0px rgba(0, 0, 0, 0.2);
+
+    .bottom-item {
+      margin-bottom: 20px;
+
+      .pic-animal {
+        animation: animateingPic .7s;
+      }
+
+      @keyframes animateingPic {
+        0% {
+          box-shadow: 0px 0px 1px 3px rgba(0, 0, 0, 0);
+        }
+
+        50% {
+          box-shadow: 0px 0px 1px 3px rgba(0, 0, 0, 0.788);
+        }
+
+        100% {
+          box-shadow: 0px 0px 1px 3px rgba(0, 0, 0, 0.5411764706);
+        }
+      }
+    }
+
+
+
+    image {
+      max-height: 300rpx;
+      box-shadow: 0px 0px 2px 3px rgba(0, 0, 0, 0.116);
+    }
+
+    .item-animal {
+      animation: animateingItem .7s;
+    }
+
+    @keyframes animateingItem {
+      0% {
+        margin-top: 40px;
+      }
+
+      100% {
+        margin-top: 0px;
+      }
+    }
+
+    .text {
+      font-size: 26rpx;
+      color: #00000080;
+      margin-top: 2px;
+    }
+  }
+
+  .animaled {
+    border-radius: 0;
+    margin-top: 0px;
+    animation: animateing .8s;
+  }
+
+  @keyframes animateing {
+
+    from {
+      border-radius: 0;
+      margin-top: 0px;
+    }
+
+    to {
+      border-radius: 20px 20px 0 0;
+      margin-top: -15px;
+    }
+  }
+
+  image {
+    width: 100%;
+    border-radius: 4px;
+  }
+}
+</style>

+ 349 - 0
小程序/jingtailan/src/components/TabBar.vue

@@ -0,0 +1,349 @@
+<script setup lang='ts'>
+import { onShow } from '@dcloudio/uni-app';
+import { onMounted } from 'vue';
+import { ref, watch } from 'vue';
+
+// 传入参数
+const props = defineProps({
+  page: {
+    type: String,
+    default: "homeIndex"
+  }
+});
+
+const selectIndex = ref("")
+const curIndex = ref(0)
+const tabBarList = ref([] as any)
+
+const animaled = ref(false)
+
+// 监听页面发生变化
+watch(props.page, (newValue: String) => {
+  selectIndex.value = String(newValue)
+
+}, { immediate: true, deep: true })
+
+watch(selectIndex, (newValue: String) => {
+  console.log('selectIndex')
+  // 页面发生变化时,进行动画
+  animaled.value = true
+  setTimeout(() => {
+    animaled.value = false
+  }, 1000)
+})
+
+onShow(() => {
+  selectIndex.value = props.page
+  animaled.value = true
+  setTimeout(() => {
+    animaled.value = false
+  }, 1000)
+})
+
+// 获取静态资源的base64
+const urlToBase64 = (url: string) => {
+  let imgBase64 = wx.getFileSystemManager().readFileSync(url, 'base64')
+  let base64Url = `data:image/png;base64,${imgBase64}`
+  return base64Url
+}
+
+onMounted(() => {
+  console.log(props.page)
+  selectIndex.value = props.page
+  console.log('开始开始')
+  tabBarList.value = [{
+    id: 0,
+    tabbarName: "今日", //tababr名称
+    iconPath: "/static/img/bottomInco/inco1.png", //tabbar icon
+    selectIconPath: "/static/img/bottomInco/inco1Ac.png", //tabbar 选择icon
+    pageIndex: "/pages/home/index", //页面路径
+    classAn: 'https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/icon0An/animation.png'
+  }, {
+    id: 1,
+    tabbarName: "游览", //tababr名称
+    iconPath: "/static/img/bottomInco/inco3.png", //tabbar icon
+    selectIconPath: "/static/img/bottomInco/inco3Ac.png", //tabbar 选择icon
+    pageIndex: "/pages/visit/index", //页面路径
+    classAn: 'https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/icon2An/animation.png'
+
+  }, {
+    id: 2,
+    tabbarName: "探索", //tababr名称
+    iconPath: "/static/img/bottomInco/inco2.png", //tabbar icon
+    selectIconPath: "/static/img/bottomInco/inco2Ac.png", //tabbar 选择icon
+    pageIndex: "/pages/explore/index", //页面路径
+    classAn: 'https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/icon1An/animation.png'
+
+  }, {
+    id: 3,
+    tabbarName: "赏析", //tababr名称
+    iconPath: "/static/img/bottomInco/inco4.png", //tabbar icon
+    selectIconPath: "/static/img/bottomInco/inco4Ac.png", //tabbar 选择icon
+    pageIndex: "/pages/analyse/index", //页面路径
+    classAn: 'https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/icon3An/animation.png'
+
+  }, {
+    id: 4,
+    tabbarName: "我的", //tababr名称
+    iconPath: "/static/img/bottomInco/inco5.png", //tabbar icon
+    selectIconPath: "/static/img/bottomInco/inco5Ac.png", //tabbar 选择icon
+    pageIndex: "/pages/mine/index", //页面路径
+    classAn: 'https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/icon4An/animation.png'
+  },]
+
+})
+
+const goPages = (pageIndex: string) => {
+  console.log('点击', pageIndex)
+  selectIndex.value = pageIndex
+  animaled.value = true
+  setTimeout(() => {
+    animaled.value = false
+  }, 1000)
+  uni.switchTab({
+    url: pageIndex
+  })
+}
+</script>
+
+<template>
+  <view class="tab_bar">
+    <view class="tabbarBox">
+      <view class="handleBox" v-for="(item, index) in tabBarList" :key="item.id">
+        <view class="menuBox" @click="goPages(item.pageIndex)">
+          <view class="menuIcon">
+            <div class="img" 
+              :style="{ backgroundImage: `url(${urlToBase64(item.selectIconPath)})`, backgroundSize: '250% 250%', backgroundPosition: '50% 50%' }"
+              v-if="item.pageIndex == selectIndex"></div>
+            <div class="img"
+              :style="{ backgroundImage: `url(${urlToBase64(item.iconPath)})`, backgroundSize: '250% 250%', backgroundPosition: '50% 50%' }"
+              v-else>
+            </div>
+            <div class="xuliezhen" v-if="animaled && selectIndex == item.pageIndex"
+              :style="{ backgroundImage: `url(${item.classAn})`, backgroundSize: '5000rpx 100%' }"></div>
+            <!-- <div class="xuliezhen"></div> -->
+            <!-- <div class="xuliezhen" :style="{ backgroundImage: `url(${item.classAn})`, backgroundSize: '5000rpx 100%' }"></div> -->
+
+
+            <!-- <image :class="{ 'icon-animal': animaled }" v-if="item.pageIndex == selectIndex" class="img"
+              :src="item.selectIconPath"></image>
+            <image v-else class="img" :src="item.iconPath"></image> -->
+          </view>
+          <view class="menuName">
+            <text :class="item.pageIndex == selectIndex ? 'TextColor' : 'Text'">{{ item.tabbarName }}</text>
+          </view>
+        </view>
+      </view>
+    </view>
+
+  </view>
+</template>
+
+<style lang='scss' scoped>
+$imgCount: 24;
+$leftWidth: -1200px;
+
+
+.tab_bar {
+  width: 100vw;
+  height: 150rpx;
+  position: fixed;
+  background-color: #FFFAF1;
+  bottom: 0;
+  /* 模糊大小就是靠的blur这个函数中的数值大小 */
+  // backdrop-filter: blur(10px);
+  // border-radius: 60rpx;
+
+  .tabbarBox {
+    display: flex;
+    margin-top: 20rpx;
+    justify-content: space-evenly;
+
+
+    .handleBox {
+      width: 20vw;
+      height: 110rpx;
+
+
+      .menuBox {
+        padding: 0rpx 20rpx;
+        width: 120rpx;
+        text-align: center;
+
+        .menuIcon {
+          display: flex;
+          justify-content: center;
+          margin-bottom: 5px;
+          position: relative;
+
+          .xuliezhen {
+            position: absolute;
+            left: 49.8%;
+            top: 49.8%;
+            transform: translate(-50%, -50%);
+            width: 200rpx;
+            height: 200rpx;
+            background-image: url('https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/icon0An/animation.png');
+            background-position-x: -5000rpx;
+            background-repeat: no-repeat;
+            background-size: 5000rpx 100%;
+            animation: mouse-in 1s;
+            animation-timing-function: steps(25);
+            animation-iteration-count: forwards;
+          }
+
+          @keyframes mouse-in {
+            from {
+              background-position-x: 0rpx;
+            }
+
+            to {
+              background-position-x: -5000rpx;
+            }
+          }
+
+          // .icon0An {
+          //   width: 80rpx;
+          //   height: 80rpx;
+          //   background-image: url('https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/icon0An/robot.png');
+          //   background-position-x: 0;
+          //   background-repeat: no-repeat;
+          //   background-size: cover;
+          //   animation: mouse-in 1s;
+          //   animation-timing-function: steps(60);
+          //   animation-iteration-count: forwards;
+          //   margin-top: 30%;
+          // }
+
+          // @keyframes mouse-in {
+          //   from {
+          //     background-position-x: 0;
+          //   }
+
+          //   to {
+          //     background-position-x: var(--leftWidth);
+          //   }
+          // }
+
+          .icon0An {
+            animation: icon0Aning 1s forwards;
+          }
+
+          @keyframes icon0Aning {
+            @for $i from 1 through $imgCount {
+              #{calc($i * 100%/$imgCount)} {
+                // background-image: url(/image/home/animation/#{$i}.png);
+                background-image: url('https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/icon0An/ (' +$i+').png');
+                background-size: 200% 200%;
+                background-position: 50% 50%;
+              }
+            }
+          }
+
+          .icon1An {
+            animation: icon1Aning 1s forwards;
+          }
+
+          @keyframes icon1Aning {
+            @for $i from 1 through $imgCount {
+              #{calc($i * 100%/$imgCount)} {
+                // background-image: url(/image/home/animation/#{$i}.png);
+                background-image: url('https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/icon1An/ (' +$i+').png');
+                background-size: 200% 200%;
+                background-position: 50% 50%;
+              }
+            }
+          }
+
+          .icon2An {
+            animation: icon2Aning 1s forwards;
+          }
+
+          @keyframes icon2Aning {
+            @for $i from 1 through $imgCount {
+              #{calc($i * 100%/$imgCount)} {
+                // background-image: url(/image/home/animation/#{$i}.png);
+                background-image: url('https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/icon2An/ (' +$i+').png');
+                background-size: 200% 200%;
+                background-position: 50% 50%;
+              }
+            }
+          }
+
+
+          .icon3An {
+            animation: icon3Aning 1s forwards;
+          }
+
+          @keyframes icon3Aning {
+            @for $i from 1 through $imgCount {
+              #{calc($i * 100%/$imgCount)} {
+                // background-image: url(/image/home/animation/#{$i}.png);
+                background-image: url('https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/icon0An/ (' +$i+').png');
+                background-size: 100% 100%;
+
+              }
+            }
+          }
+
+          .icon4An {
+            animation: icon4Aning 1s forwards;
+          }
+
+          @keyframes icon4Aning {
+            @for $i from 1 through $imgCount {
+              #{calc($i * 100%/$imgCount)} {
+                // background-image: url(/image/home/animation/#{$i}.png);
+                background-image: url('https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/icon0An/ (' +$i+').png');
+                background-size: 100% 100%;
+
+              }
+            }
+          }
+
+          .icon-animal {
+            animation: animateing 1s;
+          }
+
+          @keyframes animateing {
+
+
+            0% {
+              transform: scale(1);
+            }
+
+            50% {
+              transform: scale(1.3);
+            }
+
+            100% {
+              transform: scale(1);
+            }
+          }
+        }
+
+        .menuName {
+          margin-top: -25rpx;
+        }
+
+        .img {
+          width: 80rpx;
+          height: 80rpx;
+        }
+      }
+    }
+  }
+}
+
+.Text {
+  font-size: 24rpx;
+  font-family: Cochin, serif;
+  font-weight: 900;
+  color: rgba(0, 0, 0, 0.7);
+}
+
+.TextColor {
+  @extend .Text;
+  color: rgba(0, 0, 0, 0.7);
+}
+</style>

+ 73 - 0
小程序/jingtailan/src/components/TabBarTop.vue

@@ -0,0 +1,73 @@
+<script setup lang='ts'>
+import * as baseInfo from '@/api/record'
+
+// 传入参数
+const props = defineProps({
+  backgroundColor: {
+    type: String,
+    default: "",
+  },
+  title: {
+    type: String,
+    default: "",
+  },
+  isBack: {
+    type: Boolean,
+    default: false
+  },
+  color: {
+    type: String,
+    defaul: 'black'
+  },
+  backColor: {
+    type: String,
+    default: 'white'
+  },
+  site: {
+    type: String,
+    default: 'center'
+  },
+  bottomLine: {
+    type: String,
+    default: ''
+  }
+});
+
+const top = uni.getMenuButtonBoundingClientRect().top;
+const height = uni.getMenuButtonBoundingClientRect().height;
+
+const goBack = () => {
+  uni.navigateBack();
+}
+</script>
+  
+<template>
+  <view :style="{
+    borderBottom: props.bottomLine != '' ? props.bottomLine.toString() : '',
+  }">
+    <image @tap="goBack()" :style="{
+      position: 'absolute',
+      top: top + 'px',
+      width: height + 'px',
+      height: height + 'px',
+      marginLeft: '5px',
+      zIndex: 99
+    }" v-show="isBack" :src="baseInfo.baseIMGUrl + `/bottomInco/back${backColor == 'black' ? '1' : '2'}.png`" />
+    <view :style="{
+      width: props.site.toString() == 'left' ? 'calc(100% - 40px)' : '100%',
+      position: 'fixed',
+      top: top + 'px',
+      height: height + 'px',
+      display: 'flex',
+      justifyContent: props.site?.toString(),
+      alignItems: 'center',
+      fontWeight: 'bold',
+      boxSizing:'border-box',
+      marginLeft: props.site.toString() == 'left' ? '40px' : '',
+      backgroundColor: backgroundColor != '' ? backgroundColor : '',
+      color: props.color?.toString()
+    }">{{ props.title }}</view>
+  </view>
+</template>
+  
+<style lang='scss' scoped></style>

+ 77 - 0
小程序/jingtailan/src/components/TabBarTopHome.vue

@@ -0,0 +1,77 @@
+<script setup lang='ts'>
+import * as baseInfo from '@/api/record'
+
+// 传入参数
+const props = defineProps({
+  backgroundColor: {
+    type: String,
+    default: "",
+  },
+  title: {
+    type: String,
+    default: "",
+  },
+  isBack: {
+    type: Boolean,
+    default: false
+  },
+  color: {
+    type: String,
+    defaul: 'black'
+  },
+  backColor: {
+    type: String,
+    default: 'white'
+  },
+  site: {
+    type: String,
+    default: 'center'
+  },
+  bottomLine: {
+    type: String,
+    default: ''
+  }
+});
+
+const top = uni.getMenuButtonBoundingClientRect().top;
+const height = uni.getMenuButtonBoundingClientRect().height;
+
+const goBack = () => {
+  uni.navigateBack();
+}
+</script>
+  
+<template>
+  <view :style="{
+    borderBottom: props.bottomLine != '' ? props.bottomLine.toString() : '',
+  }">
+    <image @tap="goBack()" :style="{
+      position: 'absolute',
+      top: top + 'px',
+      width: height + 'px',
+      height: height + 'px',
+      marginLeft: '5px',
+      zIndex: 99
+    }" v-show="isBack" :src="baseInfo.baseIMGUrl + `/bottomInco/back${backColor == 'black' ? '1' : '2'}.png`" />
+    <view :style="{
+      width: props.site.toString() == 'left' ? 'calc(100% - 40px)' : '100%',
+      position: 'absolute',
+      top: top + 'px',
+      height: height + 'px',
+      display: 'flex',
+      justifyContent: props.site?.toString(),
+      alignItems: 'center',
+      fontWeight: 'bold',
+      boxSizing: 'border-box',
+      marginLeft: props.site.toString() == 'left' ? '40px' : '',
+      backgroundColor: backgroundColor != '' ? backgroundColor : '',
+      color: props.color?.toString(),
+      zIndex: 99,
+    }"><img :style="{
+  height: '100%',
+  width: '33vw'
+}" src="https://houseoss.4dkankan.com/project/bjfljtl/img/bottomInco/title-logo.png" alt="" /></view>
+  </view>
+</template>
+  
+<style lang='scss' scoped></style>

+ 502 - 0
小程序/jingtailan/src/components/mp-html/mp-html.vue

@@ -0,0 +1,502 @@
+<template>
+  <view id="_root" :class="(selectable ? '_select ' : '') + '_root'" :style="containerStyle">
+    <slot v-if="!nodes[0]" />
+    <!-- #ifndef APP-PLUS-NVUE -->
+    <node v-else :childs="nodes" :opts="[lazyLoad, loadingImg, errorImg, showImgMenu, selectable]" name="span" />
+    <!-- #endif -->
+    <!-- #ifdef APP-PLUS-NVUE -->
+    <web-view ref="web" src="/uni_modules/mp-html/static/app-plus/mp-html/local.html"
+      :style="'margin-top:-2px;height:' + height + 'px'" @onPostMessage="_onMessage" />
+    <!-- #endif -->
+  </view>
+</template>
+
+<script>
+/**
+ * mp-html v2.4.2
+ * @description 富文本组件
+ * @tutorial https://github.com/jin-yufeng/mp-html
+ * @property {String} container-style 容器的样式
+ * @property {String} content 用于渲染的 html 字符串
+ * @property {Boolean} copy-link 是否允许外部链接被点击时自动复制
+ * @property {String} domain 主域名,用于拼接链接
+ * @property {String} error-img 图片出错时的占位图链接
+ * @property {Boolean} lazy-load 是否开启图片懒加载
+ * @property {string} loading-img 图片加载过程中的占位图链接
+ * @property {Boolean} pause-video 是否在播放一个视频时自动暂停其他视频
+ * @property {Boolean} preview-img 是否允许图片被点击时自动预览
+ * @property {Boolean} scroll-table 是否给每个表格添加一个滚动层使其能单独横向滚动
+ * @property {Boolean | String} selectable 是否开启长按复制
+ * @property {Boolean} set-title 是否将 title 标签的内容设置到页面标题
+ * @property {Boolean} show-img-menu 是否允许图片被长按时显示菜单
+ * @property {Object} tag-style 标签的默认样式
+ * @property {Boolean | Number} use-anchor 是否使用锚点链接
+ * @event {Function} load dom 结构加载完毕时触发
+ * @event {Function} ready 所有图片加载完毕时触发
+ * @event {Function} imgtap 图片被点击时触发
+ * @event {Function} linktap 链接被点击时触发
+ * @event {Function} play 音视频播放时触发
+ * @event {Function} error 媒体加载出错时触发
+ */
+// #ifndef APP-PLUS-NVUE
+import node from './node/node'
+// #endif
+import Parser from './parser'
+const plugins = []
+// #ifdef APP-PLUS-NVUE
+const dom = weex.requireModule('dom')
+// #endif
+export default {
+  name: 'mp-html',
+  data() {
+    return {
+      nodes: [],
+      // #ifdef APP-PLUS-NVUE
+      height: 3
+      // #endif
+    }
+  },
+  props: {
+    containerStyle: {
+      type: String,
+      default: ''
+    },
+    content: {
+      type: String,
+      default: ''
+    },
+    copyLink: {
+      type: [Boolean, String],
+      default: true
+    },
+    domain: String,
+    errorImg: {
+      type: String,
+      default: ''
+    },
+    lazyLoad: {
+      type: [Boolean, String],
+      default: false
+    },
+    loadingImg: {
+      type: String,
+      default: ''
+    },
+    pauseVideo: {
+      type: [Boolean, String],
+      default: true
+    },
+    previewImg: {
+      type: [Boolean, String],
+      default: true
+    },
+    scrollTable: [Boolean, String],
+    selectable: [Boolean, String],
+    setTitle: {
+      type: [Boolean, String],
+      default: true
+    },
+    showImgMenu: {
+      type: [Boolean, String],
+      default: true
+    },
+    tagStyle: Object,
+    useAnchor: [Boolean, Number]
+  },
+  // #ifdef VUE3
+  emits: ['load', 'ready', 'imgtap', 'linktap', 'play', 'error'],
+  // #endif
+  // #ifndef APP-PLUS-NVUE
+  components: {
+    node
+  },
+  // #endif
+  watch: {
+    content(content) {
+      this.setContent(content)
+    }
+  },
+  created() {
+    this.plugins = []
+    for (let i = plugins.length; i--;) {
+      this.plugins.push(new plugins[i](this))
+    }
+  },
+  mounted() {
+    if (this.content && !this.nodes.length) {
+      this.setContent(this.content)
+    }
+  },
+  beforeDestroy() {
+    this._hook('onDetached')
+  },
+  methods: {
+    /**
+     * @description 将锚点跳转的范围限定在一个 scroll-view 内
+     * @param {Object} page scroll-view 所在页面的示例
+     * @param {String} selector scroll-view 的选择器
+     * @param {String} scrollTop scroll-view scroll-top 属性绑定的变量名
+     */
+    in(page, selector, scrollTop) {
+      // #ifndef APP-PLUS-NVUE
+      if (page && selector && scrollTop) {
+        this._in = {
+          page,
+          selector,
+          scrollTop
+        }
+      }
+      // #endif
+    },
+
+    /**
+     * @description 锚点跳转
+     * @param {String} id 要跳转的锚点 id
+     * @param {Number} offset 跳转位置的偏移量
+     * @returns {Promise}
+     */
+    navigateTo(id, offset) {
+      return new Promise((resolve, reject) => {
+        if (!this.useAnchor) {
+          reject(Error('Anchor is disabled'))
+          return
+        }
+        offset = offset || parseInt(this.useAnchor) || 0
+        // #ifdef APP-PLUS-NVUE
+        if (!id) {
+          dom.scrollToElement(this.$refs.web, {
+            offset
+          })
+          resolve()
+        } else {
+          this._navigateTo = {
+            resolve,
+            reject,
+            offset
+          }
+          this.$refs.web.evalJs('uni.postMessage({data:{action:"getOffset",offset:(document.getElementById(' + id + ')||{}).offsetTop}})')
+        }
+        // #endif
+        // #ifndef APP-PLUS-NVUE
+        let deep = ' '
+        // #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
+        deep = '>>>'
+        // #endif
+        const selector = uni.createSelectorQuery()
+          // #ifndef MP-ALIPAY
+          .in(this._in ? this._in.page : this)
+          // #endif
+          .select((this._in ? this._in.selector : '._root') + (id ? `${deep}#${id}` : '')).boundingClientRect()
+        if (this._in) {
+          selector.select(this._in.selector).scrollOffset()
+            .select(this._in.selector).boundingClientRect()
+        } else {
+          // 获取 scroll-view 的位置和滚动距离
+          selector.selectViewport().scrollOffset() // 获取窗口的滚动距离
+        }
+        selector.exec(res => {
+          if (!res[0]) {
+            reject(Error('Label not found'))
+            return
+          }
+          const scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + offset
+          if (this._in) {
+            // scroll-view 跳转
+            this._in.page[this._in.scrollTop] = scrollTop
+          } else {
+            // 页面跳转
+            uni.pageScrollTo({
+              scrollTop,
+              duration: 300
+            })
+          }
+          resolve()
+        })
+        // #endif
+      })
+    },
+
+    /**
+     * @description 获取文本内容
+     * @return {String}
+     */
+    getText(nodes) {
+      let text = '';
+      (function traversal(nodes) {
+        for (let i = 0; i < nodes.length; i++) {
+          const node = nodes[i]
+          if (node.type === 'text') {
+            text += node.text.replace(/&amp;/g, '&')
+          } else if (node.name === 'br') {
+            text += '\n'
+          } else {
+            // 块级标签前后加换行
+            const isBlock = node.name === 'p' || node.name === 'div' || node.name === 'tr' || node.name === 'li' || (node.name[0] === 'h' && node.name[1] > '0' && node.name[1] < '7')
+            if (isBlock && text && text[text.length - 1] !== '\n') {
+              text += '\n'
+            }
+            // 递归获取子节点的文本
+            if (node.children) {
+              traversal(node.children)
+            }
+            if (isBlock && text[text.length - 1] !== '\n') {
+              text += '\n'
+            } else if (node.name === 'td' || node.name === 'th') {
+              text += '\t'
+            }
+          }
+        }
+      })(nodes || this.nodes)
+      return text
+    },
+
+    /**
+     * @description 获取内容大小和位置
+     * @return {Promise}
+     */
+    getRect() {
+      return new Promise((resolve, reject) => {
+        uni.createSelectorQuery()
+          // #ifndef MP-ALIPAY
+          .in(this)
+          // #endif
+          .select('#_root').boundingClientRect().exec(res => res[0] ? resolve(res[0]) : reject(Error('Root label not found')))
+      })
+    },
+
+    /**
+     * @description 暂停播放媒体
+     */
+    pauseMedia() {
+      for (let i = (this._videos || []).length; i--;) {
+        this._videos[i].pause()
+      }
+      // #ifdef APP-PLUS
+      const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].pause()'
+      // #ifndef APP-PLUS-NVUE
+      let page = this.$parent
+      while (!page.$scope) page = page.$parent
+      page.$scope.$getAppWebview().evalJS(command)
+      // #endif
+      // #ifdef APP-PLUS-NVUE
+      this.$refs.web.evalJs(command)
+      // #endif
+      // #endif
+    },
+
+    /**
+     * @description 设置媒体播放速率
+     * @param {Number} rate 播放速率
+     */
+    setPlaybackRate(rate) {
+      this.playbackRate = rate
+      for (let i = (this._videos || []).length; i--;) {
+        this._videos[i].playbackRate(rate)
+      }
+      // #ifdef APP-PLUS
+      const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].playbackRate=' + rate
+      // #ifndef APP-PLUS-NVUE
+      let page = this.$parent
+      while (!page.$scope) page = page.$parent
+      page.$scope.$getAppWebview().evalJS(command)
+      // #endif
+      // #ifdef APP-PLUS-NVUE
+      this.$refs.web.evalJs(command)
+      // #endif
+      // #endif
+    },
+
+    /**
+     * @description 设置内容
+     * @param {String} content html 内容
+     * @param {Boolean} append 是否在尾部追加
+     */
+    setContent(content, append) {
+      if (!append || !this.imgList) {
+        this.imgList = []
+      }
+      const nodes = new Parser(this).parse(content)
+      // #ifdef APP-PLUS-NVUE
+      if (this._ready) {
+        this._set(nodes, append)
+      }
+      // #endif
+      this.$set(this, 'nodes', append ? (this.nodes || []).concat(nodes) : nodes)
+
+      // #ifndef APP-PLUS-NVUE
+      this._videos = []
+      this.$nextTick(() => {
+        this._hook('onLoad')
+        this.$emit('load')
+      })
+
+      if (this.lazyLoad || this.imgList._unloadimgs < this.imgList.length / 2) {
+        // 设置懒加载,每 350ms 获取高度,不变则认为加载完毕
+        let height = 0
+        const callback = rect => {
+          if (!rect || !rect.height) rect = {}
+          // 350ms 总高度无变化就触发 ready 事件
+          if (rect.height === height) {
+            this.$emit('ready', rect)
+          } else {
+            height = rect.height
+            setTimeout(() => {
+              this.getRect().then(callback).catch(callback)
+            }, 350)
+          }
+        }
+        this.getRect().then(callback).catch(callback)
+      } else {
+        // 未设置懒加载,等待所有图片加载完毕
+        if (!this.imgList._unloadimgs) {
+          this.getRect().then(rect => {
+            this.$emit('ready', rect)
+          }).catch(() => {
+            this.$emit('ready', {})
+          })
+        }
+      }
+      // #endif
+    },
+
+    /**
+     * @description 调用插件钩子函数
+     */
+    _hook(name) {
+      for (let i = plugins.length; i--;) {
+        if (this.plugins[i][name]) {
+          this.plugins[i][name]()
+        }
+      }
+    },
+
+    // #ifdef APP-PLUS-NVUE
+    /**
+     * @description 设置内容
+     */
+    _set(nodes, append) {
+      this.$refs.web.evalJs('setContent(' + JSON.stringify(nodes).replace(/%22/g, '') + ',' + JSON.stringify([this.containerStyle.replace(/(?:margin|padding)[^;]+/g, ''), this.errorImg, this.loadingImg, this.pauseVideo, this.scrollTable, this.selectable]) + ',' + append + ')')
+    },
+
+    /**
+     * @description 接收到 web-view 消息
+     */
+    _onMessage(e) {
+      const message = e.detail.data[0]
+      switch (message.action) {
+        // web-view 初始化完毕
+        case 'onJSBridgeReady':
+          this._ready = true
+          if (this.nodes) {
+            this._set(this.nodes)
+          }
+          break
+        // 内容 dom 加载完毕
+        case 'onLoad':
+          this.height = message.height
+          this._hook('onLoad')
+          this.$emit('load')
+          break
+        // 所有图片加载完毕
+        case 'onReady':
+          this.getRect().then(res => {
+            this.$emit('ready', res)
+          }).catch(() => {
+            this.$emit('ready', {})
+          })
+          break
+        // 总高度发生变化
+        case 'onHeightChange':
+          this.height = message.height
+          break
+        // 图片点击
+        case 'onImgTap':
+          this.$emit('imgtap', message.attrs)
+          if (this.previewImg) {
+            uni.previewImage({
+              current: parseInt(message.attrs.i),
+              urls: this.imgList,
+              showmenu: false
+
+            })
+          }
+          break
+        // 链接点击
+        case 'onLinkTap': {
+          const href = message.attrs.href
+          this.$emit('linktap', message.attrs)
+          if (href) {
+            // 锚点跳转
+            if (href[0] === '#') {
+              if (this.useAnchor) {
+                dom.scrollToElement(this.$refs.web, {
+                  offset: message.offset
+                })
+              }
+            } else if (href.includes('://')) {
+              // 打开外链
+              if (this.copyLink) {
+                plus.runtime.openWeb(href)
+              }
+            } else {
+              uni.navigateTo({
+                url: href,
+                fail() {
+                  uni.switchTab({
+                    url: href
+                  })
+                }
+              })
+            }
+          }
+          break
+        }
+        case 'onPlay':
+          this.$emit('play')
+          break
+        // 获取到锚点的偏移量
+        case 'getOffset':
+          if (typeof message.offset === 'number') {
+            dom.scrollToElement(this.$refs.web, {
+              offset: message.offset + this._navigateTo.offset
+            })
+            this._navigateTo.resolve()
+          } else {
+            this._navigateTo.reject(Error('Label not found'))
+          }
+          break
+        // 点击
+        case 'onClick':
+          this.$emit('tap')
+          this.$emit('click')
+          break
+        // 出错
+        case 'onError':
+          this.$emit('error', {
+            source: message.source,
+            attrs: message.attrs
+          })
+      }
+    }
+    // #endif
+  }
+}
+</script>
+
+<style>
+/* #ifndef APP-PLUS-NVUE */
+/* 根节点样式 */
+._root {
+  padding: 1px 0;
+  overflow-x: auto;
+  overflow-y: hidden;
+  -webkit-overflow-scrolling: touch;
+}
+
+/* 长按复制 */
+._select {
+  user-select: text;
+}
+
+/* #endif */
+</style>

+ 604 - 0
小程序/jingtailan/src/components/mp-html/node/node.vue

@@ -0,0 +1,604 @@
+<template>
+  <view :id="attrs.id" :class="'_block _' + name + ' ' + attrs.class" :style="attrs.style">
+    <block v-for="(n, i) in childs" v-bind:key="i">
+      <!-- 图片 -->
+      <!-- 占位图 -->
+      <image v-if="n.name === 'img' && !n.t && ((opts[1] && !ctrl[i]) || ctrl[i] < 0)" class="_img" :style="n.attrs.style"
+        :src="ctrl[i] < 0 ? opts[2] : opts[1]" mode="widthFix" />
+      <!-- 显示图片 -->
+      <!-- #ifdef H5 || (APP-PLUS && VUE2) -->
+      <img v-if="n.name === 'img'" :id="n.attrs.id" :class="'_img ' + n.attrs.class"
+        :style="(ctrl[i] === -1 ? 'display:none;' : '') + n.attrs.style" :src="n.attrs.src || (ctrl.load ? n.attrs['data-src'] : '')"
+        :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
+      <!-- #endif -->
+      <!-- #ifndef H5 || (APP-PLUS && VUE2) -->
+      <!-- 表格中的图片,使用 rich-text 防止大小不正确 -->
+      <rich-text v-if="n.name === 'img' && n.t" :style="'display:' + n.t"
+        :nodes="[{ attrs: { style: n.attrs.style, src: n.attrs.src }, name: 'img' }]" :data-i="i" @tap.stop="imgTap" />
+      <!-- #endif -->
+      <!-- #ifndef H5 || APP-PLUS -->
+      <image v-else-if="n.name === 'img'" :id="n.attrs.id" :class="'_img ' + n.attrs.class"
+        :style="(ctrl[i] === -1 ? 'display:none;' : '') + 'width:' + (ctrl[i] || 1) + 'px;height:1px;' + n.attrs.style" :src="n.attrs.src"
+        :mode="!n.h ? 'widthFix' : (!n.w ? 'heightFix' : '')" :lazy-load="opts[0]" :webp="n.webp"
+        :show-menu-by-longpress="opts[3] && !n.attrs.ignore" :image-menu-prevent="!opts[3] || n.attrs.ignore" :data-i="i"
+        @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
+      <!-- #endif -->
+      <!-- #ifdef APP-PLUS && VUE3 -->
+      <image v-else-if="n.name === 'img'" :id="n.attrs.id" :class="'_img ' + n.attrs.class"
+        :style="(ctrl[i] === -1 ? 'display:none;' : '') + 'width:' + (ctrl[i] || 1) + 'px;' + n.attrs.style"
+        :src="n.attrs.src || (ctrl.load ? n.attrs['data-src'] : '')" :mode="!n.h ? 'widthFix' : (!n.w ? 'heightFix' : '')" :data-i="i"
+        @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
+      <!-- #endif -->
+      <!-- 文本 -->
+      <!-- #ifdef MP-WEIXIN -->
+      <text v-else-if="n.text" :user-select="opts[4] == 'force' && isiOS" decode>{{ n.text }}</text>
+      <!-- #endif -->
+      <!-- #ifndef MP-WEIXIN || MP-BAIDU || MP-ALIPAY || MP-TOUTIAO -->
+      <text v-else-if="n.text" decode>{{ n.text }}</text>
+      <!-- #endif -->
+      <text v-else-if="n.name === 'br'">\n</text>
+      <!-- 链接 -->
+      <view v-else-if="n.name === 'a'" :id="n.attrs.id" :class="(n.attrs.href ? '_a ' : '') + n.attrs.class" hover-class="_hover"
+        :style="'display:inline;' + n.attrs.style" :data-i="i" @tap.stop="linkTap">
+        <node name="span" :childs="n.children" :opts="opts" style="display:inherit" />
+      </view>
+      <!-- 视频 -->
+      <!-- #ifdef APP-PLUS -->
+      <view v-else-if="n.html" :id="n.attrs.id" :class="'_video ' + n.attrs.class" :style="n.attrs.style" v-html="n.html"
+        @vplay.stop="play" />
+      <!-- #endif -->
+      <!-- #ifndef APP-PLUS -->
+      <video v-else-if="n.name === 'video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style"
+        :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted"
+        :object-fit="n.attrs['object-fit']" :poster="n.attrs.poster" :src="n.src[ctrl[i] || 0]" :data-i="i" @play="play"
+        @error="mediaError" />
+      <!-- #endif -->
+      <!-- #ifdef H5 || APP-PLUS -->
+      <iframe v-else-if="n.name === 'iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen"
+        :frameborder="n.attrs.frameborder" :src="n.attrs.src" />
+      <embed v-else-if="n.name === 'embed'" :style="n.attrs.style" :src="n.attrs.src" />
+      <!-- #endif -->
+      <!-- #ifndef MP-TOUTIAO || ((H5 || APP-PLUS) && VUE3) -->
+      <!-- 音频 -->
+      <audio v-else-if="n.name === 'audio'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style"
+        :author="n.attrs.author" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name"
+        :poster="n.attrs.poster" :src="n.src[ctrl[i] || 0]" :data-i="i" @play="play" @error="mediaError" />
+      <!-- #endif -->
+      <view v-else-if="(n.name === 'table' && n.c) || n.name === 'li'" :id="n.attrs.id" :class="'_' + n.name + ' ' + n.attrs.class"
+        :style="n.attrs.style">
+        <node v-if="n.name === 'li'" :childs="n.children" :opts="opts" />
+        <view v-else v-for="(tbody, x) in n.children" v-bind:key="x" :class="'_' + tbody.name + ' ' + tbody.attrs.class"
+          :style="tbody.attrs.style">
+          <node v-if="tbody.name === 'td' || tbody.name === 'th'" :childs="tbody.children" :opts="opts" />
+          <block v-else v-for="(tr, y) in tbody.children" v-bind:key="y">
+            <view v-if="tr.name === 'td' || tr.name === 'th'" :class="'_' + tr.name + ' ' + tr.attrs.class" :style="tr.attrs.style">
+              <node :childs="tr.children" :opts="opts" />
+            </view>
+            <view v-else :class="'_' + tr.name + ' ' + tr.attrs.class" :style="tr.attrs.style">
+              <view v-for="(td, z) in tr.children" v-bind:key="z" :class="'_' + td.name + ' ' + td.attrs.class"
+                :style="td.attrs.style">
+                <node :childs="td.children" :opts="opts" />
+              </view>
+            </view>
+          </block>
+        </view>
+      </view>
+
+      <!-- 富文本 -->
+      <!-- #ifdef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
+      <rich-text v-else-if="!n.c && !handler.isInline(n.name, n.attrs.style)" :id="n.attrs.id" :style="n.f"
+        :user-select="opts[4]" :nodes="[n]" />
+      <!-- #endif -->
+      <!-- #ifndef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
+      <rich-text v-else-if="!n.c" :id="n.attrs.id" :style="'display:inline;' + n.f" :preview="false" :selectable="opts[4]"
+        :user-select="opts[4]" :nodes="[n]" />
+      <!-- #endif -->
+      <!-- 继续递归 -->
+      <view v-else-if="n.c === 2" :id="n.attrs.id" :class="'_block _' + n.name + ' ' + n.attrs.class"
+        :style="n.f + ';' + n.attrs.style">
+        <node v-for="(n2, j) in n.children" v-bind:key="j" :style="n2.f" :name="n2.name" :attrs="n2.attrs"
+          :childs="n2.children" :opts="opts" />
+      </view>
+      <node v-else :style="n.f" :name="n.name" :attrs="n.attrs" :childs="n.children" :opts="opts" />
+    </block>
+  </view>
+</template>
+<script module="handler" lang="wxs">
+// 行内标签列表
+var inlineTags = {
+  abbr: true,
+  b: true,
+  big: true,
+  code: true,
+  del: true,
+  em: true,
+  i: true,
+  ins: true,
+  label: true,
+  q: true,
+  small: true,
+  span: true,
+  strong: true,
+  sub: true,
+  sup: true
+}
+/**
+ * @description 判断是否为行内标签
+ */
+module.exports = {
+  isInline: function (tagName, style) {
+    return inlineTags[tagName] || (style || '').indexOf('display:inline') !== -1
+  }
+}
+</script>
+<script>
+
+import node from './node'
+export default {
+  name: 'node',
+  options: {
+    // #ifdef MP-WEIXIN
+    virtualHost: true,
+    // #endif
+    // #ifdef MP-TOUTIAO
+    addGlobalClass: false
+    // #endif
+  },
+  data () {
+    return {
+      ctrl: {},
+      // #ifdef MP-WEIXIN
+      isiOS: uni.getSystemInfoSync().system.includes('iOS')
+      // #endif
+    }
+  },
+  props: {
+    name: String,
+    attrs: {
+      type: Object,
+      default () {
+        return {}
+      }
+    },
+    childs: Array,
+    opts: Array
+  },
+  components: {
+
+    // #ifndef (H5 || APP-PLUS) && VUE3
+    node
+    // #endif
+  },
+  mounted () {
+    this.$nextTick(() => {
+      for (this.root = this.$parent; this.root.$options.name !== 'mp-html'; this.root = this.root.$parent);
+    })
+    // #ifdef H5 || APP-PLUS
+    if (this.opts[0]) {
+      let i
+      for (i = this.childs.length; i--;) {
+        if (this.childs[i].name === 'img') break
+      }
+      if (i !== -1) {
+        this.observer = uni.createIntersectionObserver(this).relativeToViewport({
+          top: 500,
+          bottom: 500
+        })
+        this.observer.observe('._img', res => {
+          if (res.intersectionRatio) {
+            this.$set(this.ctrl, 'load', 1)
+            this.observer.disconnect()
+          }
+        })
+      }
+    }
+    // #endif
+  },
+  beforeDestroy () {
+    // #ifdef H5 || APP-PLUS
+    if (this.observer) {
+      this.observer.disconnect()
+    }
+    // #endif
+  },
+  methods:{
+    // #ifdef MP-WEIXIN
+    toJSON () { return this },
+    // #endif
+    /**
+     * @description 播放视频事件
+     * @param {Event} e
+     */
+    play (e) {
+      this.root.$emit('play')
+      // #ifndef APP-PLUS
+      if (this.root.pauseVideo) {
+        let flag = false
+        const id = e.target.id
+        for (let i = this.root._videos.length; i--;) {
+          if (this.root._videos[i].id === id) {
+            flag = true
+          } else {
+            this.root._videos[i].pause() // 自动暂停其他视频
+          }
+        }
+        // 将自己加入列表
+        if (!flag) {
+          const ctx = uni.createVideoContext(id
+            // #ifndef MP-BAIDU
+            , this
+            // #endif
+          )
+          ctx.id = id
+          if (this.root.playbackRate) {
+            ctx.playbackRate(this.root.playbackRate)
+          }
+          this.root._videos.push(ctx)
+        }
+      }
+      // #endif
+    },
+
+    /**
+     * @description 图片点击事件
+     * @param {Event} e
+     */
+    imgTap (e) {
+      const node = this.childs[e.currentTarget.dataset.i]
+      if (node.a) {
+        this.linkTap(node.a)
+        return
+      }
+      if (node.attrs.ignore) return
+      // #ifdef H5 || APP-PLUS
+      node.attrs.src = node.attrs.src || node.attrs['data-src']
+      // #endif
+      this.root.$emit('imgtap', node.attrs)
+      // 自动预览图片
+      if (this.root.previewImg) {
+        uni.previewImage({
+          // #ifdef MP-WEIXIN
+          showmenu: this.root.showImgMenu,
+          // #endif
+          // #ifdef MP-ALIPAY
+          enablesavephoto: this.root.showImgMenu,
+          enableShowPhotoDownload: this.root.showImgMenu,
+          // #endif
+          current: parseInt(node.attrs.i),
+          urls: this.root.imgList,
+          showmenu: false
+
+        })
+      }
+    },
+
+    /**
+     * @description 图片长按
+     */
+    imgLongTap (e) {
+      // #ifdef APP-PLUS
+      const attrs = this.childs[e.currentTarget.dataset.i].attrs
+      if (this.opts[3] && !attrs.ignore) {
+        uni.showActionSheet({
+          itemList: ['保存图片'],
+          success: () => {
+            const save = path => {
+              uni.saveImageToPhotosAlbum({
+                filePath: path,
+                success () {
+                  uni.showToast({
+                    title: '保存成功'
+                  })
+                }
+              })
+            }
+            if (this.root.imgList[attrs.i].startsWith('http')) {
+              uni.downloadFile({
+                url: this.root.imgList[attrs.i],
+                success: res => save(res.tempFilePath)
+              })
+            } else {
+              save(this.root.imgList[attrs.i])
+            }
+          }
+        })
+      }
+      // #endif
+    },
+
+    /**
+     * @description 图片加载完成事件
+     * @param {Event} e
+     */
+    imgLoad (e) {
+      const i = e.currentTarget.dataset.i
+      /* #ifndef H5 || (APP-PLUS && VUE2) */
+      if (!this.childs[i].w) {
+        // 设置原宽度
+        this.$set(this.ctrl, i, e.detail.width)
+      } else /* #endif */ if ((this.opts[1] && !this.ctrl[i]) || this.ctrl[i] === -1) {
+        // 加载完毕,取消加载中占位图
+        this.$set(this.ctrl, i, 1)
+      }
+      this.checkReady()
+    },
+
+    /**
+     * @description 检查是否所有图片加载完毕
+     */
+    checkReady () {
+      if (this.root && !this.root.lazyLoad) {
+        this.root._unloadimgs -= 1
+        if (!this.root._unloadimgs) {
+          setTimeout(() => {
+            this.root.getRect().then(rect => {
+              this.root.$emit('ready', rect)
+            }).catch(() => {
+              this.root.$emit('ready', {})
+            })
+          }, 350)
+        }
+      }
+    },
+
+    /**
+     * @description 链接点击事件
+     * @param {Event} e
+     */
+    linkTap (e) {
+      const node = e.currentTarget ? this.childs[e.currentTarget.dataset.i] : {}
+      const attrs = node.attrs || e
+      const href = attrs.href
+      this.root.$emit('linktap', Object.assign({
+        innerText: this.root.getText(node.children || []) // 链接内的文本内容
+      }, attrs))
+      if (href) {
+        if (href[0] === '#') {
+          // 跳转锚点
+          this.root.navigateTo(href.substring(1)).catch(() => { })
+        } else if (href.split('?')[0].includes('://')) {
+          // 复制外部链接
+          if (this.root.copyLink) {
+            // #ifdef H5
+            window.open(href)
+            // #endif
+            // #ifdef MP
+            uni.setClipboardData({
+              data: href,
+              success: () =>
+                uni.showToast({
+                  title: '链接已复制'
+                })
+            })
+            // #endif
+            // #ifdef APP-PLUS
+            plus.runtime.openWeb(href)
+            // #endif
+          }
+        } else {
+          // 跳转页面
+          uni.navigateTo({
+            url: href,
+            fail () {
+              uni.switchTab({
+                url: href,
+                fail () { }
+              })
+            }
+          })
+        }
+      }
+    },
+
+    /**
+     * @description 错误事件
+     * @param {Event} e
+     */
+    mediaError (e) {
+      const i = e.currentTarget.dataset.i
+      const node = this.childs[i]
+      // 加载其他源
+      if (node.name === 'video' || node.name === 'audio') {
+        let index = (this.ctrl[i] || 0) + 1
+        if (index > node.src.length) {
+          index = 0
+        }
+        if (index < node.src.length) {
+          this.$set(this.ctrl, i, index)
+          return
+        }
+      } else if (node.name === 'img') {
+        // #ifdef H5 && VUE3
+        if (this.opts[0] && !this.ctrl.load) return
+        // #endif
+        // 显示错误占位图
+        if (this.opts[2]) {
+          this.$set(this.ctrl, i, -1)
+        }
+        this.checkReady()
+      }
+      if (this.root) {
+        this.root.$emit('error', {
+          source: node.name,
+          attrs: node.attrs,
+          // #ifndef H5 && VUE3
+          errMsg: e.detail.errMsg
+          // #endif
+        })
+      }
+    }
+  }
+}
+</script>
+<style>
+/* a 标签默认效果 */
+._a {
+  padding: 1.5px 0 1.5px 0;
+  color: #366092;
+  word-break: break-all;
+}
+
+/* a 标签点击态效果 */
+._hover {
+  text-decoration: underline;
+  opacity: 0.7;
+}
+
+/* 图片默认效果 */
+._img {
+  max-width: 100%;
+  -webkit-touch-callout: none;
+}
+
+/* 内部样式 */
+
+._block {
+  display: block;
+}
+
+._b,
+._strong {
+  font-weight: bold;
+}
+
+._code {
+  font-family: monospace;
+}
+
+._del {
+  text-decoration: line-through;
+}
+
+._em,
+._i {
+  font-style: italic;
+}
+
+._h1 {
+  font-size: 2em;
+}
+
+._h2 {
+  font-size: 1.5em;
+}
+
+._h3 {
+  font-size: 1.17em;
+}
+
+._h5 {
+  font-size: 0.83em;
+}
+
+._h6 {
+  font-size: 0.67em;
+}
+
+._h1,
+._h2,
+._h3,
+._h4,
+._h5,
+._h6 {
+  display: block;
+  font-weight: bold;
+}
+
+._image {
+  height: 1px;
+}
+
+._ins {
+  text-decoration: underline;
+}
+
+._li {
+  display: list-item;
+}
+
+._ol {
+  list-style-type: decimal;
+}
+
+._ol,
+._ul {
+  display: block;
+  padding-left: 40px;
+  margin: 1em 0;
+}
+
+._q::before {
+  content: '"';
+}
+
+._q::after {
+  content: '"';
+}
+
+._sub {
+  font-size: smaller;
+  vertical-align: sub;
+}
+
+._sup {
+  font-size: smaller;
+  vertical-align: super;
+}
+
+._thead,
+._tbody,
+._tfoot {
+  display: table-row-group;
+}
+
+._tr {
+  display: table-row;
+}
+
+._td,
+._th {
+  display: table-cell;
+  vertical-align: middle;
+}
+
+._th {
+  font-weight: bold;
+  text-align: center;
+}
+
+._ul {
+  list-style-type: disc;
+}
+
+._ul ._ul {
+  margin: 0;
+  list-style-type: circle;
+}
+
+._ul ._ul ._ul {
+  list-style-type: square;
+}
+
+._abbr,
+._b,
+._code,
+._del,
+._em,
+._i,
+._ins,
+._label,
+._q,
+._span,
+._strong,
+._sub,
+._sup {
+  display: inline;
+}
+
+/* #ifdef APP-PLUS */
+._video {
+  width: 300px;
+  height: 225px;
+}
+
+/* #endif */</style>

文件差异内容过多而无法显示
+ 1335 - 0
小程序/jingtailan/src/components/mp-html/parser.js


+ 8 - 0
小程序/jingtailan/src/env.d.ts

@@ -0,0 +1,8 @@
+/// <reference types="vite/client" />
+
+declare module '*.vue' {
+  import { DefineComponent } from 'vue'
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
+  const component: DefineComponent<{}, {}, any>
+  export default component
+}

+ 11 - 0
小程序/jingtailan/src/main.ts

@@ -0,0 +1,11 @@
+import { createSSRApp } from "vue";
+import App from "./App.vue";
+import 'animate.css';
+
+
+export function createApp() {
+  const app = createSSRApp(App);
+  return {
+    app,
+  };
+}

+ 73 - 0
小程序/jingtailan/src/manifest.json

@@ -0,0 +1,73 @@
+{
+    "name" : "",
+    "appid" : "",
+    "description" : "",
+    "versionName" : "1.0.0",
+    "versionCode" : "100",
+    "transformPx" : false,
+    /* 5+App特有相关 */
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueStyleCompiler" : "uni-app",
+        "compilerVersion" : 3,
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        /* 模块配置 */
+        "modules" : {},
+        /* 应用发布信息 */
+        "distribute" : {
+            /* android打包配置 */
+            "android" : {
+                "permissions" : [
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ]
+            },
+            /* ios打包配置 */
+            "ios" : {},
+            /* SDK配置 */
+            "sdkConfigs" : {}
+        }
+    },
+    /* 快应用特有相关 */
+    "quickapp" : {},
+    /* 小程序特有相关 */
+    "mp-weixin" : {
+        "appid" : "",
+        "setting" : {
+            "urlCheck" : false
+        },
+        "usingComponents" : true,
+        "libVersion": "lastest"
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "uniStatistics": {  
+        "enable": false
+    },
+    "vueVersion" : "3"
+}

+ 232 - 0
小程序/jingtailan/src/pages.json

@@ -0,0 +1,232 @@
+{
+  "pages": [
+    {
+      "path": "pages/home/index",
+      "style": {
+        "navigationBarTitleText": "今日",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/explore/index",
+      "style": {
+        "navigationBarTitleText": "探索",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/visit/index",
+      "style": {
+        "navigationBarTitleText": "游览",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/visit/exhibition/index",
+      "style": {
+        "navigationBarTitleText": "三维链接",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/visit/history/index",
+      "style": {
+        "navigationBarTitleText": "企业回顾",
+        "navigationStyle": "custom",
+        "app-plus": {
+          "titleNView": {
+            "splitLine": true
+          }
+        }
+      }
+    },
+    {
+      "path": "pages/visit/guide/index",
+      "style": {
+        "navigationBarTitleText": "导览",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/analyse/index",
+      "style": {
+        "navigationBarTitleText": "赏析",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/analyse/detail/index",
+      "style": {
+        "navigationBarTitleText": "XX篇",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/analyse/detail/culturalRelicDetail/index",
+      "style": {
+        "navigationBarTitleText": "藏品详情",
+        "navigationStyle": "custom"
+
+      },
+      "usingComponents": {
+        "mp-html": "mp-html"
+      }
+    },
+    {
+      "path": "pages/analyse/detail/culturalRelicDetail/index3D",
+      "style": {
+        "navigationBarTitleText": "藏品详情",
+        "navigationStyle": "custom"
+
+      },
+      "usingComponents": {
+        "mp-html": "mp-html"
+      }
+    },
+    {
+      "path": "pages/mine/index",
+      "style": {
+        "navigationBarTitleText": "我的",
+        "navigationBarTextStyle": "black",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/mine/content/index",
+      "style": {
+        "navigationBarTitleText": "我的收藏"
+      }
+    },
+    {
+      "path": "pages/mine/perfectInfo/index",
+      "style": {
+        "navigationBarTitleText": "修改信息"
+      }
+    },
+    {
+      "path": "pages/mine/culturalRelic/index",
+      "style": {
+        "navigationBarTitleText": "我的收藏"
+      }
+    },
+    {
+      "path": "pages/explore/gift/index",
+      "style": {
+        "navigationBarTitleText": "国礼"
+      }
+    },
+    {
+      "path": "pages/explore/gift/detail/index",
+      "style": {
+        "navigationBarTitleText": ""
+      }
+    },
+    {
+      "path": "pages/explore/history/index",
+      "style": {
+        "navigationBarTitleText": "历史"
+      }
+    },
+    {
+      "path": "pages/explore/history/detail/index",
+      "style": {
+        "navigationBarTitleText": "历史详情"
+      }
+    },
+    {
+      "path": "pages/explore/great/index",
+      "style": {
+        "navigationBarTitleText": "大师"
+      }
+    },
+    {
+      "path": "pages/explore/great/detail/index",
+      "style": {
+        "navigationBarTitleText": "",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/explore/craft/index",
+      "style": {
+        "navigationBarTitleText": "工艺",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/explore/craft/detail/index",
+      "style": {
+        "navigationBarTitleText": "工艺"
+      }
+    },
+    {
+      "path": "pages/explore/order/index",
+      "style": {
+        "navigationBarTitleText": "定制"
+      }
+    },
+    {
+      "path": "pages/explore/order/detail/index",
+      "style": {
+        "navigationBarTitleText": "定制"
+      }
+    },
+    {
+      "path": "pages/explore/project/index",
+      "style": {
+        "navigationBarTitleText": "工程"
+      }
+    },
+    {
+      "path": "pages/explore/project/detail/index",
+      "style": {
+        "navigationBarTitleText": ""
+      }
+    }
+  ],
+  "tabBar": {
+    "custom": true,
+    "list": [
+      {
+        "text": "今日",
+        "pagePath": "pages/home/index",
+        "iconPath": "static/img/bottomInco/inco1.png",
+        "selectedIconPath": "static/img/bottomInco/inco1Ac.png"
+      },
+      {
+        "text": "游览",
+        "pagePath": "pages/visit/index",
+        "iconPath": "static/img/bottomInco/inco3.png",
+        "selectedIconPath": "static/img/bottomInco/inco3Ac.png"
+      },
+      {
+        "text": "探索",
+        "pagePath": "pages/explore/index",
+        "iconPath": "static/img/bottomInco/inco2.png",
+        "selectedIconPath": "static/img/bottomInco/inco2Ac.png"
+      },
+      {
+        "text": "赏析",
+        "pagePath": "pages/analyse/index",
+        "iconPath": "static/img/bottomInco/inco4.png",
+        "selectedIconPath": "static/img/bottomInco/inco4Ac.png"
+      },
+      {
+        "text": "我的",
+        "pagePath": "pages/mine/index",
+        "iconPath": "static/img/bottomInco/inco5.png",
+        "selectedIconPath": "static/img/bottomInco/inco5Ac.png"
+      }
+    ],
+    "color": "#474747",
+    "selectedColor": "#474747",
+    "backgroundColor": "#F7F1E6",
+    "borderStyle": "black"
+  },
+  "globalStyle": {
+    "navigationBarTextStyle": "black",
+    "navigationBarTitleText": "uni-app",
+    "navigationBarBackgroundColor": "#F7F1E6",
+    "backgroundColor": "#F7F1E6"
+  }
+}

+ 288 - 0
小程序/jingtailan/src/pages/analyse/detail/culturalRelicDetail/index copy.vue

@@ -0,0 +1,288 @@
+<script setup lang="ts">
+import { onLoad } from "@dcloudio/uni-app";
+import { ref } from "vue";
+import * as baseInfo from "@/api/record";
+import { baseIMGUrl } from "@/api/request";
+
+import { AnalyseApi } from "@/api/api/analyse/index";
+import { MineApi } from "@/api/api/mine";
+
+// const top = (uni.getMenuButtonBoundingClientRect().top + uni.getMenuButtonBoundingClientRect().height) + 'px';
+
+const info = ref({} as any);
+const modelId = ref(0);
+const path = ref("");
+
+onLoad(async (option) => {
+  const res: any = await AnalyseApi.getGoodDetail(option?.id);
+  if (res.data.code === 0) {
+    modelId.value = option?.id;
+    info.value = res.data.data;
+    info.value.content = formatRichText(res.data.data.content);
+    console.log(info.value.content);
+    isCollected();
+    checkToken();
+    setTimeout(() => {
+      path.value = `https://houseoss.4dkankan.com/project/bjfljtl/guildsvg/collection.html?id=${
+        info.value.id
+      }&&isCollected=${isCollectedInfo.value ? 1 : 0}&&isLogin=${
+        isLogin.value ? 1 : 0
+      }`;
+      console.log(path.value);
+    }, 500);
+  }
+});
+// 收藏
+// 判断是否被收藏过
+const isCollected = async () => {
+  // 拿到全部收藏
+  const res: any = await MineApi.getGoodstList({
+    pageNum: 1,
+    pageSize: 1000000,
+    searchKey: "",
+  });
+  if (res.data.code === 0) {
+    const greatList = await res.data.data.records.find((item: any) => {
+      return item.moduleId == modelId.value;
+    });
+    if (greatList) {
+      isCollectedInfo.value = true;
+      return;
+    }
+    return;
+  } else {
+    return;
+  }
+};
+const isCollectedInfo = ref(false);
+const data = ref({
+  has: 0,
+  moduleId: 1,
+  moduleType: "goods",
+  name: "",
+});
+
+const isLogin = ref(false);
+const checkToken = async () => {
+  const res: any = await MineApi.checkToken();
+  if (res.data.data) {
+    isLogin.value = true;
+    return;
+  }
+  isLogin.value = false;
+  return;
+};
+
+const collect = async (has: boolean) => {
+  isCollectedInfo.value = has;
+  data.value.has = isCollectedInfo.value ? 1 : 0;
+  data.value.moduleId = info.value.id;
+  data.value.name = info.value.name;
+  // 检查token
+  checkToken();
+  if (isLogin.value) {
+    const res: any = await MineApi.collectUpdate(data.value);
+    if (res.data.code === 0) {
+      // uni.showToast({
+      //   title: isCollectedInfo.value ? '收藏成功' : '取消成功',
+      //   icon: 'none'
+      // })
+    }
+  } else {
+    uni.showToast({
+      title: "身份过期,请重新登录",
+      icon: "none",
+    });
+    uni.removeStorage({
+      key: "JTL_token",
+    });
+    uni.removeStorage({
+      key: "JTL_userInfo",
+    });
+    setTimeout(() => {
+      uni.reLaunch({
+        url: "../../../mine/index",
+      });
+    }, 1000);
+  }
+};
+
+// h5点击收藏按钮回调
+const getMessage = (e: any) => {
+  console.log(e.detail.data[e.detail.data.length - 1].action);
+  collect(e.detail.data[e.detail.data.length - 1].action == 1 ? true : false);
+};
+
+// 富文本解析
+const formatRichText = (html: any) => {
+  let newContent = html.replace(
+    /<img[^>]*>/gi,
+    function (match: any, capture: any) {
+      match = match
+        .replace(/style="[^"]+"/gi, "")
+        .replace(/style='[^']+'/gi, "");
+      match = match
+        .replace(/width="[^"]+"/gi, "")
+        .replace(/width='[^']+'/gi, "");
+      match = match
+        .replace(/height="[^"]+"/gi, "")
+        .replace(/height='[^']+'/gi, "");
+      // 给图片加域名
+      let isExist = match.includes("https://");
+      if (!isExist) {
+        match = match.replace(
+          /(src=")/gi,
+          'src="https://wxfalangchang.4dage.com'
+        );
+      }
+      return match;
+    }
+  );
+  newContent = newContent.replace(
+    /style="[^"]+"/gi,
+    function (match: any, capture: any) {
+      match = match
+        .replace(/width:[^;]+;/gi, "max-width:100%;")
+        .replace(/width:[^;]+;/gi, "max-width:100%;");
+      return match;
+    }
+  );
+  newContent = newContent.replace(/<br[^>]*\/>/gi, "");
+  newContent = newContent.replace(
+    /\<img/gi,
+    '<img style="max-width:100%;height:auto;display:inline-block;margin:10rpx auto;"'
+  );
+  return newContent;
+};
+
+// 图片单张预览
+const previewImg = (previewImgUrl: String) => {
+  let imgsArray = [];
+  //根据api拼接
+  imgsArray[0] = baseIMGUrl + previewImgUrl;
+  uni.previewImage({
+    current: 0,
+    urls: imgsArray,
+    showmenu: false
+
+  });
+};
+
+const html = "<div>Hello World!</div>";
+</script>
+
+<template>
+  <view
+    class="all"
+    :style="{ background: info.modelUrl != '' ? '' : '#F7F1E6' }"
+  >
+    <!-- <TabBarTop title="藏品详情" :isBack="true" :backColor="info.modelUrl ? '' : 'black'" /> -->
+    <!-- 有modelUrl,传递detail -->
+    <web-view v-if="info.modelUrl != ''" :src="path" @message="getMessage" />
+
+    <!-- 无modelUrl -->
+    <view :class="info.modelUrl != '' ? 'bottom' : 'bottom2'">
+      <view class="title">
+        {{ info.name }}
+      </view>
+      <image
+        :style="{ marginTop: '10px' }"
+        :src="baseIMGUrl + info.thumb"
+        @click="previewImg(info.thumb)"
+        mode="widthFix"
+      />
+      <mp-html
+        container-style="white-space:pre-wrap;font-size:26rpx;margin-top: 10px;line-height: 45rpx"
+        :content="info.content"
+      ></mp-html>
+    </view>
+    <view class="levitated-box">
+      <image
+        :src="
+          baseInfo.baseIMGUrl +
+          `/bottomInco/collectIcon${isCollectedInfo ? 'Ac' : ''}.png`
+        "
+        mode="scaleToFill"
+        @tap="collect(!isCollectedInfo)"
+      />
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.all {
+  width: 100vw;
+  height: 100vh;
+
+  .top {
+    width: 100%;
+    height: 65vh;
+    background: gray;
+  }
+
+  .bottom {
+    width: 100%;
+    height: calc(35vh + 15px);
+    z-index: 99;
+    border-radius: 15px 15px 0 0;
+    box-shadow: 0px -4px 4px 0px rgba(0, 0, 0, 0.2);
+    background: #f7f1e6;
+    padding: 40px;
+    box-sizing: border-box;
+    overflow: auto;
+    margin-top: -15px;
+
+    .title {
+      width: 100%;
+      text-align: center;
+      font-weight: bold;
+      margin-bottom: 10px;
+    }
+
+    .disc {
+      font-size: 14px;
+      text-indent: 2em;
+    }
+  }
+
+  .bottom2 {
+    width: 100%;
+    height: 100%;
+    box-sizing: border-box;
+    padding-left: 40px;
+    padding-right: 40px;
+    overflow: auto;
+    // padding-top: 10px;
+
+    .title {
+      width: 100%;
+      text-align: center;
+      font-weight: bold;
+      // margin-bottom: 10px;
+    }
+
+    .disc {
+      font-size: 14px;
+      text-indent: 2em;
+    }
+  }
+
+  // 悬浮球
+  .levitated-box {
+    background-color: #00000080;
+    border-radius: 50px;
+    width: 50px;
+    height: 50px;
+    padding: 10px;
+    box-sizing: border-box;
+    position: fixed;
+    right: 30px;
+    bottom: 50px;
+
+    image {
+      width: 100%;
+      height: 100%;
+    }
+  }
+}
+</style>

+ 414 - 0
小程序/jingtailan/src/pages/analyse/detail/culturalRelicDetail/index.vue

@@ -0,0 +1,414 @@
+<script setup lang="ts">
+import { onLoad } from "@dcloudio/uni-app";
+import { onUnmounted, ref, watch } from "vue";
+import * as baseInfo from "@/api/record";
+import { baseIMGUrl } from "@/api/request";
+import commonn from "@/static/data/common";
+
+
+import { AnalyseApi } from "@/api/api/analyse/index";
+import { MineApi } from "@/api/api/mine";
+
+import TabBarTop from "@/components/TabBarTop.vue";
+
+// const top = (uni.getMenuButtonBoundingClientRect().top + uni.getMenuButtonBoundingClientRect().height) + 'px';
+
+const info = ref({} as any);
+const modelId = ref(0);
+const path = ref("");
+
+
+const musicStaRe = ref(false)
+// 前四个播放音乐
+const playAudio = (name: string) => {
+  if (name == '凤凰尊' || name == '国泰榴芳尊' || name == '赤玄卷草兽纹罐' || name == '普天同庆大瓶') {
+    musicStaRe.value = commonn.musicSta
+    if (musicStaRe.value) {
+      // 先暂停背景音频
+      commonn.innerAudioContext.pause()
+      commonn.musicSta = false
+    }
+    // 设置播放音频链接
+    commonn.introAudioContext.src = `https://houseoss.4dkankan.com/project/bjfljtl/audio/data/D1Analyse/${name}.mp3`;
+    commonn.introAudioContext.currentTime = 0
+    commonn.introAudioContext.play()
+  }
+}
+
+onLoad(async (option) => {
+  const res: any = await AnalyseApi.getGoodDetail(option?.id);
+  if (res.data.code === 0) {
+    modelId.value = option?.id;
+    info.value = res.data.data;
+    info.value.content = formatRichText(res.data.data.content);
+    console.log(info.value.content);
+    isCollected();
+    checkToken();
+    setTimeout(() => {
+      path.value = `https://houseoss.4dkankan.com/project/bjfljtl/guildsvg/collection.html?id=${info.value.id
+        }&&isCollected=${isCollectedInfo.value ? 1 : 0}&&isLogin=${isLogin.value ? 1 : 0
+        }`;
+    }, 500);
+    playAudio(info.value.name)
+  }
+});
+// 收藏
+// 判断是否被收藏过
+const isCollected = async () => {
+  // 拿到全部收藏
+  const res: any = await MineApi.getGoodstList({
+    pageNum: 1,
+    pageSize: 1000000,
+    searchKey: "",
+  });
+  if (res.data.code === 0) {
+    const greatList = await res.data.data.records.find((item: any) => {
+      return item.moduleId == modelId.value;
+    });
+    if (greatList) {
+      isCollectedInfo.value = true;
+      return;
+    }
+    return;
+  } else {
+    return;
+  }
+};
+const isCollectedInfo = ref(false);
+const data = ref({
+  has: 0,
+  moduleId: 1,
+  moduleType: "goods",
+  name: "",
+});
+
+const isLogin = ref(false);
+const checkToken = async () => {
+  const res: any = await MineApi.checkToken();
+  if (res.data.data) {
+    isLogin.value = true;
+    return;
+  }
+  isLogin.value = false;
+  return;
+};
+
+const collect = async (has: boolean) => {
+  isCollectedInfo.value = has;
+  data.value.has = isCollectedInfo.value ? 1 : 0;
+  data.value.moduleId = info.value.id;
+  data.value.name = info.value.name;
+  // 检查token
+  checkToken();
+  if (isLogin.value) {
+    const res: any = await MineApi.collectUpdate(data.value);
+    if (res.data.code === 0) {
+      // uni.showToast({
+      //   title: isCollectedInfo.value ? '收藏成功' : '取消成功',
+      //   icon: 'none'
+      // })
+    }
+  } else {
+    uni.showToast({
+      title: "身份过期,请重新登录",
+      icon: "none",
+    });
+    uni.removeStorage({
+      key: "JTL_token",
+    });
+    uni.removeStorage({
+      key: "JTL_userInfo",
+    });
+    setTimeout(() => {
+      uni.reLaunch({
+        url: "../../../mine/index",
+      });
+    }, 1000);
+  }
+};
+
+// 富文本解析
+const formatRichText = (html: any) => {
+  let newContent = html.replace(
+    /<img[^>]*>/gi,
+    function (match: any, capture: any) {
+      match = match
+        .replace(/style="[^"]+"/gi, "")
+        .replace(/style='[^']+'/gi, "");
+      match = match
+        .replace(/width="[^"]+"/gi, "")
+        .replace(/width='[^']+'/gi, "");
+      match = match
+        .replace(/height="[^"]+"/gi, "")
+        .replace(/height='[^']+'/gi, "");
+      // 给图片加域名
+      let isExist = match.includes("https://");
+      if (!isExist) {
+        match = match.replace(
+          /(src=")/gi,
+          'src="https://wxfalangchang.4dage.com'
+        );
+      }
+      return match;
+    }
+  );
+  newContent = newContent.replace(
+    /style="[^"]+"/gi,
+    function (match: any, capture: any) {
+      match = match
+        .replace(/width:[^;]+;/gi, "max-width:100%;")
+        .replace(/width:[^;]+;/gi, "max-width:100%;");
+      return match;
+    }
+  );
+  newContent = newContent.replace(/<br[^>]*\/>/gi, "");
+  newContent = newContent.replace(
+    /\<img/gi,
+    '<img style="max-width:100%;height:auto;display:inline-block;margin:10rpx auto;"'
+  );
+  return newContent;
+};
+
+const bottomHeight = ref("40vh");
+const scaleValue = ref(0);
+
+const scaleProduct = (e: any) => {
+  if (e.detail.scale == 0.7) {
+    scaleValue.value = 0;
+    setTimeout(() => {
+      bottomHeight.value = "40vh";
+    }, 200);
+  } else if (e.detail.scale == 1.3) {
+    bottomHeight.value = "5vh";
+  } else {
+    bottomHeight.value = "5vh";
+  }
+};
+
+const openImage = () => {
+  scaleValue.value = 1.3;
+};
+const closeImage = () => {
+  scaleValue.value = 0.7;
+};
+onUnmounted(() => {
+  if (musicStaRe.value) {
+    commonn.innerAudioContext.play()
+    commonn.musicSta = true
+  }
+  commonn.introAudioContext.pause()
+})
+</script>
+
+<template>
+  <view class="all">
+    <!-- 纹理图 -->
+    <image class="all-bg" :src="baseInfo.baseIMGUrl + `/data/D1Analyse/2/texture.png`" mode="scaleToFill" />
+    <TabBarTop title="藏品详情" :isBack="true" color="#fff" />
+    <!-- 有modelUrl,传递detail -->
+
+    <!-- 无modelUrl -->
+    <!-- 产品细节图 -->
+    <movable-area scale-area class="m-area">
+      <movable-view direction="all" scale scale-min="0.7" scale-max="2" :scale-value="scaleValue" class="m-view"
+        @scale="scaleProduct">
+        <image class="product-image" :src="baseIMGUrl + info.thumb" mode="widthFix" />
+      </movable-view>
+    </movable-area>
+
+    <!-- 图片放大 -->
+    <div class="open-img" @tap="openImage" v-if="bottomHeight == '40vh'">
+      <image :src="baseInfo.baseIMGUrl + '/data/D1Analyse/2/plus.png'" mode="widthFix" />
+    </div>
+
+    <!-- 关闭放大图片 -->
+    <div class="close-img" @tap="closeImage" v-if="bottomHeight == '5vh'">
+      <image :src="baseInfo.baseIMGUrl + '/data/D1Analyse/2/close.png'" mode="widthFix" />
+    </div>
+
+    <view :class="info.modelUrl != '' ? 'bottom' : 'bottom2'" :style="{ height: bottomHeight }">
+      <view class="title">
+        {{ info.name }}
+      </view>
+      <!-- <image
+        :style="{ marginTop: '10px' }"
+        :src="baseIMGUrl + info.thumb"
+        @click="previewImg(info.thumb)"
+        mode="widthFix"
+      /> -->
+      <mp-html style="overflow: auto; height: 70%; width: 100%"
+        container-style="white-space:pre-wrap;font-size:26rpx;margin-top: 10px;line-height: 45rpx"
+        :content="info.content"></mp-html>
+    </view>
+    <view class="levitated-box">
+      <image :src="baseInfo.baseIMGUrl +
+        `/bottomInco/collectIcon${isCollectedInfo ? 'Ac' : ''}.png`
+        " mode="scaleToFill" @tap="collect(!isCollectedInfo)" />
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.all {
+  width: 100vw;
+  height: 100vh;
+  box-sizing: border-box;
+  // background: linear-gradient(to top, white, #3e3e3e);
+  // background: linear-gradient( 180deg, rgba(47,40,40,0.6) 0%, #FFFFFF 100%);
+  background: linear-gradient(to bottom, rgba(47, 40, 40,0.5), rgba(191, 189, 189,0.8) , rgba(223, 221, 221, 0.92) , rgb(255, 255, 255));
+
+
+  .all-bg {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    top: 0;
+    bottom: 0;
+  }
+
+  .m-area {
+    width: 50vw;
+    height: 50vw;
+    position: absolute;
+    top: 25vw;
+    left: 25vw;
+
+    .m-view {
+      width: 130%;
+      height: 100%;
+
+      .product-image {
+        width: 100%;
+        margin: auto;
+        position: relative;
+      }
+    }
+  }
+
+  .open-img {
+    width: 40px;
+    height: 40px;
+    background: rgba(224, 124, 103, 0.5);
+    box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.25);
+    position: fixed;
+    right: 10px;
+    bottom: 45vh;
+    border-radius: 50%;
+
+    display: flex;
+    justify-content: center;
+    align-content: center;
+
+    image {
+      width: 60%;
+      height: 60%;
+      margin: auto;
+    }
+  }
+
+  .close-img {
+    width: 25px;
+    height: 25px;
+    background: rgba(138, 138, 138, 0.733);
+    box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.25);
+    position: fixed;
+    right: 20px;
+    top: 20vh;
+    border-radius: 50%;
+    z-index: 15;
+
+    display: flex;
+    justify-content: center;
+    align-content: center;
+
+    image {
+      width: 60%;
+      margin: auto;
+    }
+  }
+
+  .product-image {
+    width: 65vw;
+    margin: auto;
+    position: relative;
+  }
+
+  .top {
+    width: 100%;
+    height: 65vh;
+    display: flex;
+    justify-content: center;
+  }
+
+  .bottom {
+    width: 100%;
+    height: calc(35vh + 15px);
+    z-index: 99;
+    border-radius: 15px 15px 0 0;
+    box-shadow: 0px -4px 4px 0px rgba(0, 0, 0, 0.2);
+    background: #f7f1e6;
+    padding: 40px;
+    box-sizing: border-box;
+    overflow: auto;
+    margin-top: -15px;
+    transition: height 3s;
+
+    .title {
+      width: 100%;
+      text-align: center;
+      font-weight: bold;
+      margin-bottom: 10px;
+    }
+
+    .disc {
+      font-size: 14px;
+      text-indent: 2em;
+    }
+  }
+
+  .bottom2 {
+    width: 100%;
+    height: 40%;
+    box-sizing: border-box;
+    overflow: auto;
+    position: absolute;
+    bottom: 0;
+    padding: 15px 40px;
+    border-radius: 30px 30px 0 0;
+    background: #f7f1e6;
+    box-shadow: 0px -4px 4px 0px rgba(0, 0, 0, 0.2);
+    transform: 2s;
+    // padding-top: 10px;
+
+    .title {
+      width: 100%;
+      text-align: center;
+      font-weight: bold;
+      // margin-bottom: 10px;
+    }
+
+    .disc {
+      font-size: 14px;
+      text-indent: 2em;
+    }
+  }
+
+  // 悬浮球
+  .levitated-box {
+    background-color: #00000080;
+    border-radius: 50px;
+    width: 50px;
+    height: 50px;
+    padding: 10px;
+    box-sizing: border-box;
+    position: fixed;
+    right: 30px;
+    bottom: 50px;
+
+    image {
+      width: 100%;
+      height: 100%;
+    }
+  }
+}
+</style>

+ 131 - 0
小程序/jingtailan/src/pages/analyse/detail/culturalRelicDetail/index3D.vue

@@ -0,0 +1,131 @@
+<script setup lang="ts">
+import { onLoad } from "@dcloudio/uni-app";
+import { ref } from "vue";
+
+import { AnalyseApi } from "@/api/api/analyse/index";
+import { MineApi } from "@/api/api/mine";
+
+// const top = (uni.getMenuButtonBoundingClientRect().top + uni.getMenuButtonBoundingClientRect().height) + 'px';
+
+const info = ref({} as any);
+const modelId = ref(0);
+const path = ref("");
+
+onLoad(async (option) => {
+  const res: any = await AnalyseApi.getGoodDetail(option?.id);
+  if (res.data.code === 0) {
+    modelId.value = option?.id;
+    info.value = res.data.data;
+    console.log(info.value.content);
+    isCollected();
+    checkToken();
+    setTimeout(() => {
+      path.value = `https://houseoss.4dkankan.com/project/bjfljtl/guildsvg/collection.html?id=${
+        info.value.id
+      }&&isCollected=${isCollectedInfo.value ? 1 : 0}&&isLogin=${
+        isLogin.value ? 1 : 0
+      }`;
+      console.log(path.value);
+    }, 500);
+  }
+});
+// 收藏
+// 判断是否被收藏过
+const isCollected = async () => {
+  // 拿到全部收藏
+  const res: any = await MineApi.getGoodstList({
+    pageNum: 1,
+    pageSize: 1000000,
+    searchKey: "",
+  });
+  if (res.data.code === 0) {
+    const greatList = await res.data.data.records.find((item: any) => {
+      return item.moduleId == modelId.value;
+    });
+    if (greatList) {
+      isCollectedInfo.value = true;
+      return;
+    }
+    return;
+  } else {
+    return;
+  }
+};
+const isCollectedInfo = ref(false);
+const data = ref({
+  has: 0,
+  moduleId: 1,
+  moduleType: "goods",
+  name: "",
+});
+
+const isLogin = ref(false);
+const checkToken = async () => {
+  const res: any = await MineApi.checkToken();
+  if (res.data.data) {
+    isLogin.value = true;
+    return;
+  }
+  isLogin.value = false;
+  return;
+};
+
+const collect = async (has: boolean) => {
+  isCollectedInfo.value = has;
+  data.value.has = isCollectedInfo.value ? 1 : 0;
+  data.value.moduleId = info.value.id;
+  data.value.name = info.value.name;
+  // 检查token
+  checkToken();
+  if (isLogin.value) {
+    const res: any = await MineApi.collectUpdate(data.value);
+    if (res.data.code === 0) {
+      // uni.showToast({
+      //   title: isCollectedInfo.value ? '收藏成功' : '取消成功',
+      //   icon: 'none'
+      // })
+    }
+  } else {
+    uni.showToast({
+      title: "身份过期,请重新登录",
+      icon: "none",
+    });
+    uni.removeStorage({
+      key: "JTL_token",
+    });
+    uni.removeStorage({
+      key: "JTL_userInfo",
+    });
+    setTimeout(() => {
+      uni.reLaunch({
+        url: "../../../mine/index",
+      });
+    }, 1000);
+  }
+};
+
+// h5点击收藏按钮回调
+const getMessage = (e: any) => {
+  console.log(e.detail.data[e.detail.data.length - 1].action);
+  collect(e.detail.data[e.detail.data.length - 1].action == 1 ? true : false);
+};
+
+
+</script>
+
+<template>
+  <view
+    class="all"
+  >
+    <!-- <TabBarTop title="藏品详情" :isBack="true" :backColor="info.modelUrl ? '' : 'black'" /> -->
+    <!-- 有modelUrl,传递detail -->
+    <web-view v-if="info.modelUrl != ''" :src="path" @message="getMessage" />
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.all {
+  width: 100vw;
+  height: 100vh;
+}
+</style>

+ 249 - 0
小程序/jingtailan/src/pages/analyse/detail/index.vue

@@ -0,0 +1,249 @@
+<script setup lang="ts">
+import { onLoad, onReachBottom } from "@dcloudio/uni-app";
+import { ref } from "vue";
+
+import TabBarTop from "@/components/TabBarTop.vue";
+import * as baseInfo from "@/api/record";
+import { baseIMGUrl } from "@/api/request";
+
+import { AnalyseApi } from "@/api/api/analyse/index";
+
+const name = ref("");
+const topBGUrl = ref("");
+const detail = ref({} as any);
+
+const PageListInfo = ref({
+  pageNum: 1,
+  pageSize: 10,
+  searchKey: "",
+  type: "盛世",
+});
+
+const greatList = ref([] as any);
+const totle = ref(0);
+
+onLoad(async (option) => {
+  const res: any = await AnalyseApi.getAnalyseDetail(option?.id);
+  if (res.data.code === 0) {
+    detail.value = res.data.data;
+  }
+  PageListInfo.value.type = option?.name;
+  const res2: any = await AnalyseApi.getGoodsList(PageListInfo.value);
+  if (res2.data.code === 0) {
+    greatList.value = res2.data.data.records;
+    totle.value = res2.data.data.total;
+  }
+
+  name.value = option?.name;
+  switch (option?.name) {
+    case "盛世":
+      topBGUrl.value =
+        baseInfo.baseIMGUrl + "/data/D1Analyse/1/flourishingAc.png";
+      break;
+    case "低谷":
+      topBGUrl.value = baseInfo.baseIMGUrl + "/data/D1Analyse/1/downAc.png";
+      break;
+    case "重生":
+      topBGUrl.value = baseInfo.baseIMGUrl + "/data/D1Analyse/1/rebirthAc.png";
+      break;
+    case "发展":
+      topBGUrl.value = baseInfo.baseIMGUrl + "/data/D1Analyse/1/developAc.png";
+      break;
+    case "巅峰":
+      topBGUrl.value = baseInfo.baseIMGUrl + "/data/D1Analyse/1/peakAc.png";
+      break;
+    case "国礼":
+      topBGUrl.value = baseInfo.baseIMGUrl + "/data/D1Analyse/1/giftAc.png";
+      break;
+  }
+});
+
+const scrolltolower = async () => {
+  if (
+    greatList.value.length > totle.value ||
+    greatList.value.length === totle.value
+  ) {
+    uni.showToast({
+      title: "没有更多了",
+      icon: "none",
+    });
+  } else {
+    PageListInfo.value.pageNum += 1;
+    const res: any = await AnalyseApi.getGoodsList(PageListInfo.value);
+    const passNumber =
+      (PageListInfo.value.pageNum - 1) * PageListInfo.value.pageSize;
+    const over = totle.value - passNumber;
+    if (res.data.code === 0) {
+      greatList.value = [...greatList.value, ...res.data.data.records];
+    }
+  }
+};
+
+const goTo = async (id: number) => {
+  const res: any = await AnalyseApi.getGoodDetail(id);
+  if (res.data.code == 0) {
+    if (res.data.data.modelUrl == "") {
+      uni.navigateTo({
+        url: `culturalRelicDetail/index?id=${id}`,
+      });
+    } else {
+      uni.navigateTo({
+        url: `culturalRelicDetail/index3D?id=${id}`,
+      });
+    }
+  }
+};
+</script>
+
+<template>
+  <view class="all">
+    <TabBarTop :title="name + '篇'" :isBack="true" backColor="black" />
+    <!-- 背景 -->
+    <image
+      class="bg-img"
+      src="https://houseoss.4dkankan.com/project/bjfljtl/img/data/D1Analyse/2/bg.jpg"
+      mode="widthFix"
+    />
+    <image class="icon-img" :src="topBGUrl" mode="widthFix" />
+    <view class="content">
+      <view class="top">
+        <text> {{ typeof detail.entity.content != 'undefined' ? detail.entity.content : "" }}</text>
+      </view>
+      <scroll-view
+        class="bottom"
+        :scroll-top="0"
+        scroll-y="true"
+        @scrolltolower="scrolltolower"
+      >
+        <view style="text-align: center" v-if="greatList.length === 0"
+          >暂无数据</view
+        >
+        <view v-else class="list">
+          <view
+            class="list-item"
+            v-for="item in greatList"
+            :key="item.id"
+            @tap="goTo(item.id)"
+          >
+            <image :src="baseIMGUrl + item.thumb" mode="widthFix" rel="preload" />
+            <view class="list-name">{{ item.name }}</view>
+          </view>
+        </view>
+      </scroll-view>
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.all {
+  width: 100vw;
+  height: 100vh;
+  position: relative;
+  overflow: hidden;
+
+  .bg-img {
+  }
+
+  .icon-img {
+    width: 32%;
+    position: absolute;
+    z-index: 2;
+    top: 140rpx;
+    left: 60rpx;
+  }
+
+  image {
+    width: 100%;
+    overflow: hidden;
+    // position: absolute;
+  }
+
+  .content {
+    width: 100%;
+    position: absolute;
+    bottom: 0;
+    display: flex;
+    flex-direction: column;
+
+    .top {
+      width: 100%;
+      display: flex;
+      justify-content: right;
+
+      text {
+        width: 80%;
+        text-indent: 2em;
+        box-sizing: border-box;
+        margin: auto;
+        margin-bottom: 20rpx;
+        font-size: 26rpx;
+        line-height: 38rpx;
+        display: -webkit-box;
+
+        -webkit-box-orient: vertical;
+
+        -webkit-line-clamp: 4;
+
+        overflow: hidden;
+
+        white-space: pre-wrap;
+      }
+    }
+
+    .bottom {
+      width: 100%;
+      height: 60vh;
+      z-index: 99;
+      border-radius: 15px 15px 0 0;
+      box-shadow: 0px -4px 4px 0px rgba(0, 0, 0, 0.2);
+      background: #f7f1e6;
+      padding: 20px;
+      box-sizing: border-box;
+      overflow: auto;
+
+      .list {
+        margin: auto;
+        width: 100%;
+        /* 声明一个容器 */
+        display: grid;
+        grid-template-columns: repeat(2, 50%);
+        /* 声明行间距和列间距 */
+        grid-column-gap: 5px;
+        grid-row-gap: 10px;
+
+        &-item {
+          width: 90%;
+          position: relative;
+          background: white;
+          height: 40vw;
+          text-align: center;
+          border-radius: 5px;
+          // background: linear-gradient(to top, #2F2828 50%, #BFBDBD 80%, #DFDDDD 92%, #FFFFFF 100%);
+          // background: linear-gradient(to bottom, #2F2828 60%, #FFFFFF);
+          background: linear-gradient( 180deg, rgba(47,40,40,0.6) 0%, #FFFFFF 100%);
+
+          image {
+            width: 50%;
+            margin: 10px auto;
+          }
+
+          .list-name {
+            width: 100%;
+            position: absolute;
+            bottom: 0;
+            line-height: 30px;
+            text-align: center;
+            background: rgba(0, 0, 0, 0.65);
+            color: #ffffff;
+            border-radius: 0 0 4px 4px;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            font-size: 28rpx;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 270 - 0
小程序/jingtailan/src/pages/analyse/index.vue

@@ -0,0 +1,270 @@
+<script setup lang="ts">
+import * as baseInfo from "@/api/record";
+import TabBarTopHome from "@/components/TabBarTopHome.vue";
+import { onLoad, onShow } from "@dcloudio/uni-app";
+
+import { AnalyseApi } from "@/api/api/analyse/index";
+import { ref } from "vue";
+
+import TabBar from "@/components/TabBar.vue";
+
+
+const curIndex = ref("国礼");
+const models = ref([] as any);
+
+
+// 点击前动画跳转
+const isSkipAni = ref(false)
+
+const goTo = (path: String, current: string) => {
+  curIndex.value = current;
+  isSkipAni.value = true
+  setTimeout(() => {
+    uni.navigateTo({ url: path });
+    isSkipAni.value = false
+  }, 500)
+};
+
+
+onLoad(async (options) => {
+  const res: any = await AnalyseApi.getAnalyseList();
+  if (res.data.code === 0) {
+    models.value = res.data.data;
+  }
+  //自动清除定时器
+  const key = uni.getStorageSync("FIRST_KEY");
+  if (key) {
+    uni.removeStorage({
+      key: "FIRST_KEY",
+    });
+  }
+});
+const page = ref('')
+onShow(() => {
+  page.value = '/pages/analyse/index'
+})
+</script>
+
+<template>
+  <scroll-view class="all" :show-scrollbar="false">
+    <TabBarTopHome title="赏析" />
+    <image :src="baseInfo.baseIMGUrl + '/data/D1Analyse/bg.jpg'" mode="widthFix" />
+    <div :class="{ 'animated': isSkipAni }"></div>
+    <!-- 国礼 -->
+    <view class="analyse-item" :class="{ 'analyse-item-animal': isSkipAni && curIndex == '国礼' }"
+      :style="{ top: '190rpx', left: '64rpx', width: curIndex === '国礼' ? '' : '210rpx', zIndex: isSkipAni && curIndex == '国礼' ? 4 : 2 }"
+      @tap="goTo(`detail/index?name=国礼&id=${models[5].id}`, '国礼')">
+      <image :src="baseInfo.baseIMGUrl +
+        `/data/D1Analyse/1/gift${curIndex === '国礼' ? 'Ac' : ''}.png`
+        " mode="widthFix" />
+      <div class="aperture-wai"></div>
+      <img class="aperture-wai-bg" src="https://houseoss.4dkankan.com/project/bjfljtl/img/data/D1Analyse/cicleBg.png"
+        alt="">
+      <!-- 动画跳转动画 -->
+      <!-- <div :class="{ 'animated': isSkipAni && curIndex == '国礼' }"></div> -->
+    </view>
+
+    <!-- 低谷 -->
+    <view class="analyse-item" :class="{ 'analyse-item-animal': isSkipAni && curIndex == '低谷' }"
+      :style="{ top: '320rpx', right: '32rpx', zIndex: isSkipAni && curIndex == '低谷' ? 4 : 2 }"
+      @tap="goTo(`detail/index?name=低谷&id=${models[1].id}`, '低谷')">
+      <image :src="baseInfo.baseIMGUrl +
+        `/data/D1Analyse/1/down${curIndex === '低谷' ? 'Ac' : ''}.png`
+        " mode="widthFix" />
+      <div class="aperture-wai"></div>
+      <img class="aperture-wai-bg" src="https://houseoss.4dkankan.com/project/bjfljtl/img/data/D1Analyse/cicleBg.png"
+        alt="">
+      <!-- 动画跳转动画 -->
+      <!-- <div :class="{ 'animated': isSkipAni && curIndex == '低谷' }"></div> -->
+    </view>
+
+    <!-- 重生 -->
+    <view class="analyse-item" :class="{ 'analyse-item-animal': isSkipAni && curIndex == '重生' }"
+      :style="{ top: '570rpx', right: '140rpx', zIndex: isSkipAni && curIndex == '重生' ? 4 : 2 }"
+      @tap="goTo(`detail/index?name=重生&id=${models[2].id}`, '重生')">
+      <image :src="baseInfo.baseIMGUrl +
+        `/data/D1Analyse/1/rebirth${curIndex === '重生' ? 'Ac' : ''}.png`
+        " mode="widthFix" />
+      <div class="aperture-wai"></div>
+      <img class="aperture-wai-bg" src="https://houseoss.4dkankan.com/project/bjfljtl/img/data/D1Analyse/cicleBg.png"
+        alt="">
+      <!-- 动画跳转动画 -->
+      <!-- <div :class="{ 'animated': isSkipAni && curIndex == '重生' }"></div> -->
+    </view>
+
+    <!-- 发展 -->
+    <view class="analyse-item" :class="{ 'analyse-item-animal': isSkipAni && curIndex == '发展' }"
+      :style="{ top: '690rpx', left: '86rpx', zIndex: isSkipAni && curIndex == '发展' ? 4 : 2 }"
+      @tap="goTo(`detail/index?name=发展&id=${models[3].id}`, '发展')">
+      <image :src="baseInfo.baseIMGUrl +
+        `/data/D1Analyse/1/develop${curIndex === '发展' ? 'Ac' : ''}.png`
+        " mode="widthFix" />
+      <div class="aperture-wai"></div>
+      <img class="aperture-wai-bg" src="https://houseoss.4dkankan.com/project/bjfljtl/img/data/D1Analyse/cicleBg.png"
+        alt="">
+      <!-- 动画跳转动画 -->
+      <!-- <div :class="{ 'animated': isSkipAni && curIndex == '发展' }"></div> -->
+    </view>
+
+    <!-- 巅峰 -->
+    <view class="analyse-item" :class="{ 'analyse-item-animal': isSkipAni && curIndex == '巅峰' }"
+      :style="{ top: '950rpx', right: '256rpx', zIndex: isSkipAni && curIndex == '巅峰' ? 4 : 2 }"
+      @tap="goTo(`detail/index?name=巅峰&id=${models[4].id}`, '巅峰')">
+      <image :src="baseInfo.baseIMGUrl +
+        `/data/D1Analyse/1/peak${curIndex === '巅峰' ? 'Ac' : ''}.png`
+        " mode="widthFix" />
+      <div class="aperture-wai"></div>
+      <img class="aperture-wai-bg" src="https://houseoss.4dkankan.com/project/bjfljtl/img/data/D1Analyse/cicleBg.png"
+        alt="">
+      <!-- 动画跳转动画 -->
+      <!-- <div :class="{ 'animated': isSkipAni && curIndex == '巅峰' }"></div> -->
+    </view>
+
+
+    <!-- 盛世 -->
+    <view class="analyse-item" :class="{ 'analyse-item-animal': isSkipAni && curIndex == '盛世' }"
+      :style="{ top: '1188rpx', left: '60rpx', zIndex: isSkipAni && curIndex == '盛世' ? 4 : 2 }"
+      @tap="goTo(`detail/index?name=盛世&id=${models[0].id}`, '盛世')">
+      <image :src="baseInfo.baseIMGUrl +
+        `/data/D1Analyse/1/flourishing${curIndex === '盛世' ? 'Ac' : ''}.png`
+        " mode="widthFix" />
+      <div class="aperture-wai"></div>
+      <img class="aperture-wai-bg" src="https://houseoss.4dkankan.com/project/bjfljtl/img/data/D1Analyse/cicleBg.png"
+        alt="">
+      <!-- 动画跳转动画 -->
+      <!-- <div :class="{ 'animated': isSkipAni && curIndex == '盛世' }"></div> -->
+    </view>
+
+  </scroll-view>
+  <TabBar :page="page" />
+</template>
+
+<style lang="scss" scoped>
+.all {
+  width: 100vw;
+  height: calc(100vh - 150rpx);
+  overflow: hidden;
+  position: relative;
+
+  ::-webkit-scrollbar {
+    display: none !important;
+  }
+
+  image {
+    width: calc(100% + 1px);
+    margin-left: -1px;
+    margin-bottom: -4px;
+  }
+
+
+  .analyse-item-animal {
+    animation: animateingItem .1s;
+  }
+
+  @keyframes animateingItem {
+    0% {
+      transform: scale(1);
+    }
+
+    50% {
+      transform: scale(0);
+    }
+
+    100% {
+      transform: scale(1);
+    }
+  }
+
+  .analyse-item {
+    width: 270rpx;
+    position: absolute;
+
+
+
+    image {
+      width: 100%;
+      position: relative;
+      z-index: 2;
+    }
+
+    // 光圈
+    .aperture-wai {
+      width: 196rpx;
+      height: 196rpx;
+      // box-shadow: 0 0 10px 10px rgba(255, 255, 255, 1);
+      border-radius: 50%;
+      position: absolute;
+      top: 50%;
+      // top: -24%;
+      left: 49.5%;
+      transform: translate(-50%, -50%);
+      z-index: 2;
+      // background: url('https://houseoss.4dkankan.com/project/bjfljtl/img/data/D1Analyse/cicleBg.png');
+      // background-image: linear-gradient(to bottom, #fbb8b8, white);
+      background-size: 100% 100%;
+      animation-name: fadenum;
+      animation-duration: 2s;
+      animation-iteration-count: infinite;
+      animation-direction: alternate;
+    }
+
+    @keyframes fadenum {
+      from {
+        box-shadow: 0 0 18px 18px rgba(255, 255, 255, 0.856);
+      }
+
+      to {
+        box-shadow: 0 0 8px 8px rgb(255, 255, 255);
+      }
+    }
+
+    .aperture-wai-bg {
+      width: 110%;
+      height: 110%;
+      border-radius: 50%;
+      position: absolute;
+      top: 50%;
+      // top: -24%;
+      left: 49.5%;
+      transform: translate(-50%, -50%);
+      z-index: 1;
+    }
+
+
+
+  }
+
+  .animated {
+    width: 100vw;
+    height: 100vh;
+    // border-radius: 50%;
+    background: white;
+    box-shadow: 0 0 5px 5px rgb(255, 255, 255);
+    position: absolute;
+    top: 0;
+    // top: -70%;
+    // left: -20%;
+    // transform: translate(-50%, -50%);
+    z-index: 3;
+    animation: animateing .7s;
+  }
+
+  @keyframes animateing {
+    // 0% {
+    //   opacity: 0;
+    // }
+
+    0% {
+      opacity: 0;
+    }
+
+    50% {
+      opacity: 1;
+    }
+
+    100% {
+      opacity: 0;
+    }
+  }
+}
+</style>

+ 68 - 0
小程序/jingtailan/src/pages/explore/craft/detail/index.vue

@@ -0,0 +1,68 @@
+<script setup lang='ts'>
+import { onLoad } from '@dcloudio/uni-app'
+import { onUnmounted, ref } from 'vue';
+import ModelDeatil from '@/components/ModelDeatil.vue'
+import commonn from "@/static/data/common";
+
+
+
+import { CraftApi } from '@/api/api/explore/craft'
+
+const models = ref({} as any)
+
+const modelId = ref(0)
+
+const musicStaRe = ref(false)
+const playAudio = (name: string) => {
+
+  musicStaRe.value = commonn.musicSta
+  if (musicStaRe.value) {
+    console.log(musicStaRe.value)
+    // 先暂停背景音频
+    commonn.innerAudioContext.pause()
+    commonn.musicSta = false
+  }
+  commonn.introAudioContext.src = `https://houseoss.4dkankan.com/project/bjfljtl/audio/data/B1Seek/${name}.mp3`
+  commonn.innerAudioContext.currentTime = 0
+  commonn.introAudioContext.autoplay = true
+
+  commonn.introAudioContext.play()
+}
+
+onLoad(async (option) => {
+  modelId.value = option?.id;
+  const res: any = await CraftApi.getCraftDetail(option?.id)
+  if (res.data.code === 0) {
+    models.value = res.data.data
+    uni.setNavigationBarTitle({
+      title: models.value.entity.name
+    });
+    playAudio(models.value.entity.name)
+
+  } else {
+    uni.showToast({
+      title: res.data.msg,
+      icon: 'none'
+    })
+    setTimeout(() => {
+      uni.navigateBack();
+    }, 500)
+  }
+})
+
+
+onUnmounted(() => {
+  if (musicStaRe.value) {
+    commonn.innerAudioContext.play()
+    commonn.musicSta = true
+  }
+  commonn.introAudioContext.pause()
+})
+
+</script>
+  
+<template>
+  <ModelDeatil :detail="models" type="craft" :modelId="modelId" />
+</template>
+  
+<style lang='scss' scoped></style>

+ 258 - 0
小程序/jingtailan/src/pages/explore/craft/index.vue

@@ -0,0 +1,258 @@
+<script setup lang="ts">
+import * as baseInfo from "@/api/record";
+import TabBarTop from "@/components/TabBarTop.vue";
+import { onLoad } from "@dcloudio/uni-app";
+
+import { CraftApi } from "@/api/api/explore/craft";
+import { ref, watch } from "vue";
+const curIndex = ref("");
+
+
+// 点击前动画跳转
+const isSkipAni = ref(false)
+
+const goTo = (path: String, current: string) => {
+  curIndex.value = current;
+  isSkipAni.value = true
+  setTimeout(() => {
+    uni.navigateTo({ url: path });
+    isSkipAni.value = false
+  }, 500)
+};
+
+const PageListInfo = ref({
+  pageNum: 1,
+  pageSize: 10,
+  searchKey: "",
+  startTime: "",
+  endTime: "",
+});
+
+const models = ref([] as any);
+const timer = ref(0)
+const isPicAnimal1 = ref(false)
+const isPicAnimal2 = ref(false)
+const isPicAnimal3 = ref(false)
+const isPicAnimal4 = ref(false)
+const isPicAnimal5 = ref(false)
+const isPicAnimal6 = ref(false)
+
+watch(timer, (newVal, oldVal) => {
+  if (newVal <= 6) {
+    switch (newVal) {
+      case 1:
+        isPicAnimal1.value = true;
+        setTimeout(() => {
+          timer.value += 1
+        }, 200)
+        setTimeout(() => {
+
+          isPicAnimal1.value = false;
+        }, 2000)
+        break;
+      case 2:
+        isPicAnimal2.value = true;
+        setTimeout(() => {
+          timer.value += 1
+        }, 200)
+        setTimeout(() => {
+
+          isPicAnimal2.value = false;
+        }, 2000)
+        break;
+      case 3:
+        isPicAnimal3.value = true;
+        setTimeout(() => {
+          timer.value += 1
+        }, 200)
+        setTimeout(() => {
+
+          isPicAnimal3.value = false;
+        }, 2000)
+        break;
+      case 4:
+        isPicAnimal4.value = true;
+        setTimeout(() => {
+          timer.value += 1
+        }, 200)
+        setTimeout(() => {
+
+          isPicAnimal4.value = false;
+        }, 2000)
+        break;
+      case 5:
+        isPicAnimal5.value = true;
+        setTimeout(() => {
+          timer.value += 1
+        }, 200)
+        setTimeout(() => {
+
+          isPicAnimal5.value = false;
+        }, 2000)
+        break;
+      case 6:
+        isPicAnimal6.value = true;
+        setTimeout(() => {
+          timer.value += 1
+        }, 200)
+        setTimeout(() => {
+
+          isPicAnimal6.value = false;
+        }, 2000)
+        break;
+    }
+  }
+
+});
+
+onLoad(async (options) => {
+  const res: any = await CraftApi.getCraftList(PageListInfo);
+  if (res.data.code === 0) {
+    models.value = res.data.data.records;
+    console.log(models);
+  }
+  isPicAnimal1.value = true
+  timer.value += 1
+});
+</script>
+
+<template>
+  <!-- <view @tap="goTo('detail/index')">去了解</view> -->
+  <view class="all">
+    <TabBarTop title="工艺" :isBack="true" />
+    <image :src="baseInfo.baseIMGUrl + '/data/B1Seek/craft/bg.jpg'" mode="widthFix" />
+    <div :class="{ 'animated': isSkipAni }"></div>
+    <!-- 设计 -->
+    <view class="item" :class="{ 'pic-animal': isPicAnimal1 }"
+      :style="{ top: '31%', right: '24%', zIndex: isSkipAni && curIndex == '设计' ? 4 : 2 }"
+      @tap="goTo(`detail/index?name=设计&id=${models[0].id}`, '设计')">
+      <image :style="{ width: curIndex === '设计' ? '135%' : '100%' }" :src="baseInfo.baseIMGUrl +
+        `/data/B1Seek/craft/icon/1${curIndex === '设计' ? '_Ac' : ''}.png`
+        " mode="widthFix" />
+    </view>
+
+    <!-- 制胎 -->
+    <view class="item" :class="{ 'pic-animal': isPicAnimal2 }"
+      :style="{ top: '42%', left: '22%', zIndex: isSkipAni && curIndex == '制胎' ? 4 : 2 }"
+      @tap="goTo(`detail/index?name=制胎&id=${models[1].id}`, '制胎')">
+      <image :style="{ width: curIndex === '制胎' ? '135%' : '' }" :src="baseInfo.baseIMGUrl +
+        `/data/B1Seek/craft/icon/2${curIndex === '制胎' ? '_Ac' : ''}.png`
+        " mode="widthFix" />
+    </view>
+    <!-- 掐丝·焊丝 -->
+    <view class="item" :class="{ 'pic-animal': isPicAnimal3 }"
+      :style="{ top: '53%', right: '24%', zIndex: isSkipAni && curIndex == '掐丝' ? 4 : 2 }"
+      @tap="goTo(`detail/index?name=掐丝·焊丝&id=${models[2].id}`, '掐丝')">
+      <image :style="{ width: curIndex === '掐丝' ? '135%' : '' }" :src="baseInfo.baseIMGUrl +
+        `/data/B1Seek/craft/icon/3${curIndex === '掐丝' ? '_Ac' : ''}.png`
+        " mode="widthFix" />
+    </view>
+
+    <!-- 点蓝·烧蓝 -->
+    <view class="item" :class="{ 'pic-animal': isPicAnimal4 }"
+      :style="{ top: '64%', left: '22%', zIndex: isSkipAni && curIndex == '点蓝' ? 4 : 2 }"
+      @tap="goTo(`detail/index?name=点蓝·烧蓝&id=${models[3].id}`, '点蓝')">
+      <image :style="{ width: curIndex === '点蓝' ? '135%' : '' }" :src="baseInfo.baseIMGUrl +
+        `/data/B1Seek/craft/icon/4${curIndex === '点蓝' ? '_Ac' : ''}.png`
+        " mode="widthFix" />
+    </view>
+    <!-- 磨光 -->
+    <view class="item" :class="{ 'pic-animal': isPicAnimal5 }"
+      :style="{ top: '75%', right: '24%', zIndex: isSkipAni && curIndex == '磨光' ? 4 : 2 }"
+      @tap="goTo(`detail/index?name=磨光&id=${models[4].id}`, '磨光')">
+      <image :style="{ width: curIndex === '磨光' ? '135%' : '' }" :src="baseInfo.baseIMGUrl +
+        `/data/B1Seek/craft/icon/5${curIndex === '磨光' ? '_Ac' : ''}.png`
+        " mode="widthFix" />
+    </view>
+    <!-- 镀金 -->
+    <view class="item" :class="{ 'pic-animal': isPicAnimal6 }" style="top: 85.5%; left: 22%"
+      @tap="goTo(`detail/index?name=镀金&id=${models[5].id}`, '镀金')">
+      <image :style="{ width: curIndex === '镀金' ? '135%' : '' }" :src="baseInfo.baseIMGUrl +
+        `/data/B1Seek/craft/icon/6${curIndex === '镀金' ? '_Ac' : ''}.png`
+        " mode="widthFix" />
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.all {
+  width: 100vw;
+  position: relative;
+
+  image {
+    width: calc(100% + 1px);
+    margin-left: -1px;
+    margin-bottom: -4px;
+  }
+
+  .item {
+    position: absolute;
+    width: 25vw;
+    height: 25vw;
+    background: rgba(0, 128, 0, 0);
+    top: 0;
+    border-radius: 50px;
+
+    image {
+      width: 121%;
+      height: 100%;
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -49%);
+    }
+  }
+
+  .pic-animal {
+    animation: animateingPic 2s;
+  }
+
+  @keyframes animateingPic {
+    0% {
+      box-shadow: 0px 0px 10px 10px rgba(255, 255, 255, 0);
+    }
+
+    50% {
+      box-shadow: 0px 0px 20px 10px rgba(255, 255, 255, 0.788);
+    }
+
+    100% {
+      box-shadow: 0px 0px 20px 10px rgba(255, 255, 255, 0);
+    }
+  }
+
+  .animated {
+    width: 100vw;
+    height: 100%;
+    // border-radius: 50%;
+    background: white;
+    box-shadow: 0 0 5px 5px rgb(255, 255, 255);
+    position: absolute;
+    top: 0;
+    // top: -70%;
+    // left: -20%;
+    // transform: translate(-50%, -50%);
+    z-index: 3;
+    animation: animateing .7s;
+  }
+
+  @keyframes animateing {
+    // 0% {
+    //   opacity: 0;
+    // }
+
+    0% {
+      opacity: 0;
+    }
+
+    50% {
+      opacity: 1;
+    }
+
+    100% {
+      opacity: 0;
+    }
+  }
+
+}
+</style>

+ 65 - 0
小程序/jingtailan/src/pages/explore/gift/detail/index.vue

@@ -0,0 +1,65 @@
+<script setup lang='ts'>
+import { ExploreApi } from '@/api/api/explore';
+import ModelDeatil from '@/components/ModelDeatil.vue'
+import { onLoad } from '@dcloudio/uni-app';
+import { onUnmounted, ref } from 'vue';
+import commonn from "@/static/data/common";
+
+
+const models = ref({} as any)
+const modelId = ref(0)
+const isAudioName = ref('')
+
+
+const musicStaRe = ref(false)
+const playAudio = (name: string) => {
+
+  musicStaRe.value = commonn.musicSta
+  if (musicStaRe.value) {
+    console.log(musicStaRe.value)
+    // 先暂停背景音频
+    commonn.innerAudioContext.pause()
+    commonn.musicSta = false
+  }
+  commonn.introAudioContext.src = `https://houseoss.4dkankan.com/project/bjfljtl/audio/data/B1Seek/${name}.mp3`
+  commonn.introAudioContext.currentTime = 0
+  commonn.introAudioContext.autoplay = true
+  commonn.introAudioContext.play()
+}
+
+onLoad(async (options) => {
+  const res: any = await ExploreApi.getModelDetail(options?.id);
+  modelId.value = options?.id
+  if (res.data.code === 0) {
+    models.value = res.data.data
+    console.log(models.value.entity.name)
+    if (models.value.entity.name == '四面方尊' || models.value.entity.name == '民族团结' || models.value.entity.name == '盛世欢歌')
+      playAudio(models.value.entity.name)
+
+  } else {
+    uni.showToast({
+      title: res.data.msg,
+      icon: 'none'
+    })
+    setTimeout(() => {
+      uni.navigateBack();
+    }, 500)
+  }
+})
+
+onUnmounted(() => {
+  if (musicStaRe.value) {
+    commonn.innerAudioContext.play()
+    commonn.musicSta = true
+  }
+  commonn.introAudioContext.pause()
+})
+</script>
+
+
+
+<template>
+  <ModelDeatil :isAudio="isAudioName == '' ? '' : isAudioName" :detail="models" type="block" :modelId="modelId" />
+</template>
+  
+<style lang='scss' scoped></style>

+ 65 - 0
小程序/jingtailan/src/pages/explore/gift/index.vue

@@ -0,0 +1,65 @@
+<script setup lang='ts'>
+import * as baseInfo from '@/api/record';
+
+import PageListNoRow from '@/components/PageListNoRow.vue';
+import { onLoad, onReachBottom } from '@dcloudio/uni-app';
+import { ref } from 'vue';
+
+import { ExploreApi } from '@/api/api/explore'
+import { GiftApi } from '@/api/api/explore/gift';
+import { baseIMGUrl } from '@/api/request';
+const PageListInfo = ref({
+  pageNum: 1,
+  pageSize: 10,
+  searchKey: '',
+  type: 'national'
+})
+
+
+
+const greatList = ref([] as any)
+const totle = ref(0)
+const BGS = ref([] as any)
+
+
+
+onLoad(async (option) => {
+   // 获取背景图
+   const ress: any = await GiftApi.getGoodDetail(option?.id)
+  if (ress.data.code === 0) {
+    ress.data.data.file.forEach((item: any) => {
+      BGS.value.push(baseIMGUrl + item.filePath)
+    });
+  }
+  const res:any = await ExploreApi.getModelList(PageListInfo.value)
+  if(res.data.code === 0 ){
+    greatList.value = res.data.data.records
+    totle.value = res.data.data.total
+  }
+})
+
+// 滑动到底部 分页加载更多
+onReachBottom(async () => {
+  if (greatList.value.length > totle.value || greatList.value.length === totle.value) {
+    uni.showToast({
+      title: '没有更多了',
+      icon: 'none'
+    })
+  } else {
+    PageListInfo.value.pageNum += 1;
+    const res: any = await ExploreApi.getModelList(PageListInfo.value);
+    greatList.value = [...greatList.value, ...res.data.data.records]
+   
+  }
+})
+</script>
+  
+<template>
+  <!-- <PageList
+    :background="BGS"
+    :list="greatList" next="detail/index"></PageList> -->
+    <PageListNoRow :background="BGS" :list="greatList" next="detail/index">
+  </PageListNoRow>
+</template>
+  
+<style lang='scss' scoped></style>

+ 202 - 0
小程序/jingtailan/src/pages/explore/great/detail/index.vue

@@ -0,0 +1,202 @@
+<script setup lang='ts'>
+import { onLoad, onReady } from '@dcloudio/uni-app'
+import { ref, type Ref } from 'vue';
+
+import TabBarTop from '@/components/TabBarTop.vue';
+
+import * as baseInfo from '@/api/record';
+import { baseIMGUrl } from '@/api/request';
+
+import { GreatApi } from '@/api/api/explore/great';
+import { MineApi } from '@/api/api/mine';
+
+const detail = ref({} as any)
+const modelId = ref(0)
+
+
+
+// 理想状态:传入id
+onLoad(async (options) => {
+  const res: any = await GreatApi.getGreatDetail(options?.id);
+  modelId.value= options?.id;
+  if (res.data.code === 0) {
+    detail.value = res.data.data;
+  } else {
+    uni.showToast({
+      title: res.data.msg,
+      icon: 'none'
+    })
+    setTimeout(() => {
+      uni.navigateBack();
+    }, 500)
+  }
+
+  isCollected();
+})
+
+const bottomBoxHeight = ref('40vh')
+
+// 进度条滚动
+const scrollEvt = (e: any) => {
+  if (parseInt(bottomBoxHeight.value) < 80) {
+    bottomBoxHeight.value = parseInt(bottomBoxHeight.value) + 5 + 'vh';
+    console.log(bottomBoxHeight.value)
+  } else {
+    return;
+  }
+}
+
+
+// 收藏
+// 判断是否被收藏过
+const isCollected = async () => {
+  // 拿到全部收藏
+  const res: any = await MineApi.getContentList({
+    pageNum: 1,
+    pageSize: 1000000,
+    searchKey: '',
+  })
+  if (res.data.code === 0) {
+    const greatList = await res.data.data.records.find((item: any) => {
+      return item.moduleId == modelId.value
+    })
+    if (greatList) {
+      isCollectedInfo.value = true
+      return
+    }
+    return
+
+  } else {
+    return
+  }
+}
+
+const isCollectedInfo = ref(false)
+const data = ref({
+  has: 0,
+  moduleId: 1,
+  moduleType: "master",
+  name: ""
+})
+
+
+const collect = async () => {
+  isCollectedInfo.value = !isCollectedInfo.value;
+  data.value.has = isCollectedInfo.value ? 1 : 0;
+  data.value.moduleId = detail.value.entity.id;
+  data.value.name = detail.value.entity.name;
+  // 检查token
+  const ress: any = await MineApi.checkToken();
+  if (ress.data.data) {
+    const res: any = await MineApi.collectUpdate(data.value)
+    if (res.data.code === 0) {
+      uni.showToast({
+        title: isCollectedInfo ? '收藏成功' : '取消成功',
+        icon: 'none'
+      })
+    }
+  } else {
+    uni.showToast({
+      title: '身份过期,请重新登录',
+      icon: 'none'
+    })
+    uni.removeStorage({
+      key: 'JTL_token'
+    })
+    uni.removeStorage({
+      key: 'JTL_userInfo'
+    })
+    setTimeout(() => {
+      uni.reLaunch({
+        url: '../../../mine/index'
+      })
+    }, 1000)
+  }
+}
+
+// 图片单张预览
+const previewImg = (previewImgUrl: String) => {
+  let imgsArray = [];
+  //根据api拼接
+  imgsArray[0] = baseIMGUrl + previewImgUrl
+  uni.previewImage({
+    current: 0,
+    urls: imgsArray,
+    showmenu: false
+
+  });
+}
+
+</script>
+  
+<template>
+  <TabBarTop :isBack="true" />
+  <view class="all" v-if="JSON.stringify(detail) != '{}'">
+    <image :src="baseIMGUrl + detail.entity?.imgBack" mode="aspectFill" />
+    <scroll-view class="bottom" scroll-y="true" @scroll="scrollEvt">
+      <view class="bottom-text">{{ detail.entity?.content }}</view>
+      <image :src="baseIMGUrl + item.filePath" mode="widthFix" v-for="item in detail.file" :key="item.id"
+        @tap="previewImg(item.filePath)" />
+    </scroll-view>
+    <view class="levitated-box">
+      <image :src="baseInfo.baseIMGUrl + `/bottomInco/collectIcon${isCollectedInfo ? 'Ac' : ''}.png`" mode="widthFix"
+        @tap="collect" />
+    </view>
+  </view>
+</template>
+  
+<style lang='scss' scoped>
+.all {
+  width: 100vw;
+  height: 100vh;
+  // background: #C7965B;
+  background: #c7965b;
+  position: relative;
+
+  .bottom {
+    width: 100%;
+    margin-top: -15px;
+    height: v-bind(bottomBoxHeight);
+    overflow: auto;
+    box-sizing: border-box;
+    padding: 28px 38px 30px 38px;
+    border-radius: 20px 20px 0 0;
+    background: #F7F1E680;
+    position: absolute;
+    bottom: 0;
+
+    image {
+      box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.5);
+    }
+
+    &-text {
+      font-size: 14px;
+      margin-bottom: 20px;
+      white-space: pre-wrap;
+    }
+
+  }
+
+  image {
+    width: 100%;
+    height: 100%;
+  }
+
+  // 悬浮球
+  .levitated-box {
+    background-color: #00000080;
+    border-radius: 50px;
+    width: 50px;
+    height: 50px;
+    padding: 10px;
+    box-sizing: border-box;
+    position: fixed;
+    right: 30px;
+    bottom: 50px;
+
+    image {
+      height: 100%;
+    }
+  }
+}
+</style>

+ 77 - 0
小程序/jingtailan/src/pages/explore/great/index.vue

@@ -0,0 +1,77 @@
+<script setup lang='ts'>
+import PageListNoRow from '@/components/PageListNoRow.vue'
+import { onLoad, onReachBottom } from '@dcloudio/uni-app';
+
+import { GreatApi } from '@/api/api/explore/great/index'
+import { ref } from 'vue';
+import { GiftApi } from '@/api/api/explore/gift';
+import { baseIMGUrl } from '@/api/request';
+
+const PageListInfo = ref({
+  pageNum: 1,
+  pageSize: 10,
+  searchKey: '',
+  startTime: '',
+  endTime: ''
+})
+
+
+const totle = ref(0)
+const greatList = ref([] as any)
+const BGS = ref([] as any)
+
+
+onLoad(async (options) => {
+  // 获取背景图
+  const ress: any = await GiftApi.getGoodDetail(options?.id)
+  if (ress.data.code === 0) {
+    ress.data.data.file.forEach((item: any) => {
+      BGS.value.push(baseIMGUrl + item.filePath)
+    });
+  }
+  const res: any = await GreatApi.getGreatList(PageListInfo);
+  if (res.data.code === 0) {
+    greatList.value = res.data.data.records
+    totle.value = res.data.data.total
+  }
+})
+// 滑动到底部 分页加载更多
+onReachBottom(async () => {
+  if (greatList.value.length > totle.value || greatList.value.length === totle.value) {
+    uni.showToast({
+      title: '没有更多了',
+      icon: 'none'
+    })
+  } else {
+    PageListInfo.value.pageNum += 1;
+    const res: any = await GreatApi.getGreatList(PageListInfo.value);
+    greatList.value = [...greatList.value, ...res.data.data.records]
+
+    // const passNumber = (PageListInfo.value.pageNum - 1) * PageListInfo.value.pageSize;
+    // const over = totle.value - passNumber
+    // if (res.data.code === 0) {
+    //   if (over > PageListInfo.value.pageSize) {
+    //     // 当前接口数据全部推入
+    //     greatList.value = [...greatList.value, ...res.data.data.records]
+    //   }else {
+    //     // 取前over个
+    //     const overList = greatList.value.slice(0,over);
+    //     greatList.value = [...greatList.value, ...overList]
+    //   }
+    // }
+  }
+})
+</script>
+  
+<template>
+  <PageListNoRow :background="BGS" :list="greatList" next="detail/index"></PageListNoRow>
+</template>
+  
+<style lang='scss' scoped>
+.more-box {
+  width: 100vw;
+  text-align: center;
+  font-size: 20rpx;
+  color: rgba(214, 212, 212, 0.671);
+}
+</style>

+ 34 - 0
小程序/jingtailan/src/pages/explore/history/detail/index.vue

@@ -0,0 +1,34 @@
+<script setup lang='ts'>
+import { ExploreApi } from '@/api/api/explore';
+import ModelDeatil from '@/components/ModelDeatil.vue'
+import { onLoad } from '@dcloudio/uni-app';
+import { ref } from 'vue';
+
+const models = ref({} as any)
+const modelId = ref(0)
+
+
+onLoad(async (options) => {
+  const res: any = await ExploreApi.getModelDetail(options?.id);
+  modelId.value = options?.id
+  if (res.data.code === 0) {
+    models.value = res.data.data
+  } else {
+    uni.showToast({
+      title: res.data.msg,
+      icon: 'none'
+    })
+    setTimeout(() => {
+      uni.navigateBack();
+    }, 500)
+  }
+})
+</script>
+
+
+
+<template>
+  <ModelDeatil :detail="models" type="block" :modelId="modelId" />
+</template>
+  
+<style lang='scss' scoped></style>

+ 67 - 0
小程序/jingtailan/src/pages/explore/history/index.vue

@@ -0,0 +1,67 @@
+<script setup lang='ts'>
+import PageListNoRow from '@/components/PageListNoRow.vue'
+
+import { baseIMGUrl } from '@/api/request';
+
+import { ExploreApi } from '@/api/api/explore'
+import { GiftApi } from '@/api/api/explore/gift'
+import { onLoad, onReachBottom } from '@dcloudio/uni-app';
+import { ref } from 'vue';
+
+const PageListInfo = ref({
+  pageNum: 1,
+  pageSize: 10,
+  searchKey: '',
+  type: 'history'
+})
+
+const greatList = ref([] as any)
+const totle = ref(0)
+const BGS = ref([] as any)
+
+
+// 给数据的每个对象添加text属性,用于表示列表显示文字
+const addText = () => {
+  greatList.value.map((item: any) => {
+    item['text'] = item.name
+  })
+}
+
+onLoad(async (option) => {
+  // 获取背景图
+  const ress: any = await GiftApi.getGoodDetail(option?.id)
+  if (ress.data.code === 0) {
+    ress.data.data.file.forEach((item: any) => {
+      BGS.value.push(baseIMGUrl + item.filePath)
+    });
+  }
+  const res: any = await ExploreApi.getModelList(PageListInfo.value)
+  if (res.data.code === 0) {
+    greatList.value = res.data.data.records
+    totle.value = res.data.data.total
+    addText()
+  }
+})
+
+// 滑动到底部 分页加载更多
+onReachBottom(async () => {
+  if (greatList.value.length > totle.value || greatList.value.length === totle.value) {
+    uni.showToast({
+      title: '没有更多了',
+      icon: 'none'
+    })
+  } else {
+    PageListInfo.value.pageNum += 1;
+    const res: any = await ExploreApi.getModelList(PageListInfo.value);
+    greatList.value = [...greatList.value, ...res.data.data.records]
+
+  }
+})
+</script>
+  
+<template>
+  <PageListNoRow :background="BGS" :list="greatList" next="detail/index">
+  </PageListNoRow>
+</template>
+  
+<style lang='scss' scoped></style>

+ 122 - 0
小程序/jingtailan/src/pages/explore/index.vue

@@ -0,0 +1,122 @@
+<script setup lang='ts'>
+import { HomeApi } from '@/api/api/home/index';
+import { baseIMGUrl } from '@/api/request';
+import TabBarTopHome from "@/components/TabBarTopHome.vue";
+import { onLoad, onReady, onShow } from '@dcloudio/uni-app';
+
+import TabBar from "@/components/TabBar.vue";
+
+
+import { ref } from 'vue';
+
+const top = uni.getMenuButtonBoundingClientRect().top;
+const height = uni.getMenuButtonBoundingClientRect().height;
+
+const goTo = (path: String) => {
+  uni.navigateTo({
+    //保留当前页面,跳转到应用内的某个页面
+    url: path
+  })
+}
+
+const models = ref([] as any)
+
+
+onLoad(async (options) => {
+  const res: any = await HomeApi.getExplore();
+  if (res.data.code === 0) {
+    models.value = res.data.data;
+  }
+  // 自动跳转后自动清除定时器
+  const key = uni.getStorageSync('FIRST_KEY')
+  if (key) {
+    uni.removeStorage({
+      key: 'FIRST_KEY'
+    })
+  }
+})
+
+const page = ref('')
+onShow(() => {
+  page.value = '/pages/explore/index'
+})
+</script>
+  
+<template>
+  <view class="all">
+    <!-- <TabBarTop title="探索" color="rgba(0,0,0,0.6)"   /> -->
+    <TabBarTopHome title="探索" />
+    <view style="padding-left: 10px; padding-right: 10px;margin-top: 12vh;">
+      <view class="top">
+        <image @tap="goTo(`gift/index?id=${models[1].id}`)" :src="baseIMGUrl + models[1]?.thumb" mode="widthFix" />
+      </view>
+      <view class="center-box">
+        <view class="center-box-row" style="margin-bottom: 15px;">
+          <image @tap="goTo(`history/index?id=${models[2].id}`)" :src="baseIMGUrl + models[2]?.thumb" mode="widthFix" />
+          <image @tap="goTo(`great/index?id=${models[3].id}`)" :src="baseIMGUrl + models[3]?.thumb" mode="widthFix" />
+        </view>
+        <view class="center-box-row">
+          <image @tap="goTo(`craft/index?id=${models[4].id}`)" :src="baseIMGUrl + models[4]?.thumb" mode="widthFix" />
+          <image @tap="goTo(`order/index?id=${models[5].id}`)" :src="baseIMGUrl + models[5]?.thumb" mode="widthFix" />
+        </view>
+      </view>
+      <view class="top">
+        <image @tap="goTo(`project/index?id=${models[6].id}`)" :src="baseIMGUrl + models[6]?.thumb" mode="widthFix" />
+      </view>
+    </view>
+    <TabBar :page="page" />
+  </view>
+</template>
+  
+<style lang='scss' scoped>
+::-webkit-scrollbar {
+  display: none !important;
+}
+.all {
+  width: 100vw;
+  height: calc(100vh - 150rpx);
+  padding-bottom: 20px;
+  box-sizing: border-box;
+  background: #F7F1E6;
+  overflow: auto;
+
+  .top {
+    width: 100%;
+    height: 30%;
+
+    image {
+      width: 100%;
+      height: 100%;
+      border-radius: 6px;
+      box-shadow: 0px 3px 2px 0px rgb(0 0 0 / 25%);
+    }
+  }
+
+  .box {
+    border: 1px dotted gray;
+  }
+
+  .center-box {
+    width: 100%;
+    // height: calc(40% - 20px);
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    margin: 15px 0;
+
+    &-row {
+      width: 100%;
+      height: 100%;
+      display: flex;
+      justify-content: space-between;
+
+      image {
+        width: 48%;
+        box-shadow: 0px 3px 2px 0px rgb(0 0 0 / 25%);
+        border-radius: 6px;
+      }
+
+    }
+  }
+}
+</style>

+ 33 - 0
小程序/jingtailan/src/pages/explore/order/detail/index.vue

@@ -0,0 +1,33 @@
+<script setup lang='ts'>
+import { ExploreApi } from '@/api/api/explore';
+import ModelDeatil from '@/components/ModelDeatil.vue'
+import { onLoad } from '@dcloudio/uni-app';
+import { ref } from 'vue';
+
+const models = ref({} as any)
+const modelId = ref(0)
+
+onLoad(async (options) => {
+  const res: any = await ExploreApi.getModelDetail(options?.id);
+  modelId.value = options?.id
+  if (res.data.code === 0) {
+    models.value = res.data.data
+  } else {
+    uni.showToast({
+      title: res.data.msg,
+      icon: 'none'
+    })
+    setTimeout(() => {
+      uni.navigateBack();
+    }, 500)
+  }
+})
+</script>
+
+
+
+<template>
+  <ModelDeatil :detail="models" type="block" :modelId="modelId"/>
+</template>
+  
+<style lang='scss' scoped></style>

+ 61 - 0
小程序/jingtailan/src/pages/explore/order/index.vue

@@ -0,0 +1,61 @@
+<script setup lang='ts'>
+import PageListNoRow from '@/components/PageListNoRow.vue'
+
+
+import { ExploreApi } from '@/api/api/explore'
+import { ref } from 'vue';
+import { onLoad, onReachBottom } from '@dcloudio/uni-app';
+import { GiftApi } from '@/api/api/explore/gift';
+import { baseIMGUrl } from '@/api/request';
+const PageListInfo = ref({
+  pageNum: 1,
+  pageSize: 10,
+  searchKey: '',
+  type: 'custom'
+})
+
+
+
+const greatList = ref([] as any)
+const totle = ref(0)
+const BGS = ref([] as any)
+
+
+onLoad(async (option) => {
+   // 获取背景图
+   const ress: any = await GiftApi.getGoodDetail(option?.id)
+  if (ress.data.code === 0) {
+    ress.data.data.file.forEach((item: any) => {
+      BGS.value.push(baseIMGUrl + item.filePath)
+    });
+  }
+  const res:any = await ExploreApi.getModelList(PageListInfo.value)
+  if(res.data.code === 0 ){
+    greatList.value = res.data.data.records
+    totle.value = res.data.data.total
+
+  }
+})
+
+
+// 滑动到底部 分页加载更多
+onReachBottom(async () => {
+  if (greatList.value.length > totle.value || greatList.value.length === totle.value) {
+    uni.showToast({
+      title: '没有更多了',
+      icon: 'none'
+    })
+  } else {
+    PageListInfo.value.pageNum += 1;
+    const res: any = await ExploreApi.getModelList(PageListInfo.value);
+    greatList.value = [...greatList.value, ...res.data.data.records]
+
+  }
+})
+</script>
+  
+<template>
+  <PageListNoRow :background="BGS" :list="greatList" next="detail/index"></PageListNoRow>
+</template>
+  
+<style lang='scss' scoped></style>

+ 35 - 0
小程序/jingtailan/src/pages/explore/project/detail/index.vue

@@ -0,0 +1,35 @@
+<script setup lang='ts'>
+import { ExploreApi } from '@/api/api/explore';
+import ModelDeatil from '@/components/ModelDeatil.vue'
+import { onLoad } from '@dcloudio/uni-app';
+import { ref } from 'vue';
+
+const models = ref({} as any)
+const modelId = ref(0)
+
+
+onLoad(async (options) => {
+  const res: any = await ExploreApi.getModelDetail(options?.id);
+  modelId.value = options?.id
+
+  if (res.data.code === 0) {
+    models.value = res.data.data
+  } else {
+    uni.showToast({
+      title: res.data.msg,
+      icon: 'none'
+    })
+    setTimeout(() => {
+      uni.navigateBack();
+    }, 500)
+  }
+})
+</script>
+
+
+
+<template>
+  <ModelDeatil :detail="models" type="block" :modelId="modelId"/>
+</template>
+  
+<style lang='scss' scoped></style>

+ 97 - 0
小程序/jingtailan/src/pages/explore/project/detail/index2.vue

@@ -0,0 +1,97 @@
+<script setup lang='ts'>
+import * as baseInfo from '@/api/record';
+
+const data = {
+  titles: [
+    '北京昆泰国际大型环境装饰艺术',
+    '《花开富贵》景泰蓝艺术喷水池工程'
+  ],
+  imgList: [
+    baseInfo.baseIMGUrl + '/data/B1Seek/project/sw1.png', baseInfo.baseIMGUrl + '/data/B1Seek/project/sw2.png', baseInfo.baseIMGUrl + '/data/B1Seek/project/sw3.png', baseInfo.baseIMGUrl + '/data/B1Seek/project/sw1.png', baseInfo.baseIMGUrl + '/data/B1Seek/project/sw2.png', baseInfo.baseIMGUrl + '/data/B1Seek/project/sw3.png'
+  ],
+  paragraph: [
+    '《花开富贵》景泰蓝艺术喷水池工程是景泰蓝工艺主体,锻铜、堑铜装饰,灯光及喷泉系统工程相结合的大型环境艺术工程。位于朝外C区“昆泰国际”前广场。俯瞰是一个巨大的钥匙型组合,总长28米,最宽处8.2米,总面积约80平方米。',
+    '《花开富贵》俯瞰是一个巨大的钥匙型组合,总长28米,最宽处8.2米,总面积约80平方米。'
+  ],
+  contentImg: [
+    baseInfo.baseIMGUrl + '/data/B1Seek/project/1/1.png', baseInfo.baseIMGUrl + '/data/B1Seek/project/1/2.png'
+  ]
+}
+</script>
+  
+<template>
+  <view class="all">
+    <view class="title" v-for="item in data.titles" :key="item">{{ item }}</view>
+    <view class="image-box">
+      <image class="big-image" :src="data.imgList[0]" mode="aspectFill" />
+      <view class="imgs-box">
+        <view v-for="(item, index) in data.imgList" :key="item">
+          <image :src="item" mode="aspectFill" />
+        </view>
+      </view>
+    </view>
+    <view class="content-box" v-for="index in (data.paragraph.length + 1)" :key="index">
+      <view class="paragraph">
+        {{ data.paragraph[index - 1] }}
+      </view>
+      <image :src="data.contentImg[index - 1]" mode="widthFit" />
+    </view>
+  </view>
+</template>
+  
+<style lang='scss' scoped>
+.all {
+  background: #F7F1E6;
+
+  .title {
+    width: 100%;
+    text-align: center;
+    font-size: 14px;
+    font-weight: bold;
+  }
+
+  .image-box {
+    width: 100%;
+    margin-top: 20px;
+
+    .big-image {
+      width: 100%;
+      height: 40vh;
+    }
+
+    .imgs-box {
+      padding: 0 20px;
+      height: 10vh;
+      overflow: auto;
+      display: flex;
+
+      image {
+        height: 100%;
+        width: 20vw;
+        margin-right: 10px;
+      }
+    }
+
+
+  }
+
+  .content-box {
+    padding: 0 20px;
+
+    .paragraph {
+      width: 100%;
+      padding: 20px;
+      box-sizing: border-box;
+      margin-bottom: 10px;
+      font-size: 12px;
+      line-height: 20px;
+    }
+
+    image {
+      width: 100%;
+    }
+  }
+
+
+}
+</style>

+ 160 - 0
小程序/jingtailan/src/pages/explore/project/index.vue

@@ -0,0 +1,160 @@
+<script setup lang="ts">
+import { ExploreApi } from "@/api/api/explore";
+import { GiftApi } from "@/api/api/explore/gift";
+import * as baseInfo from "@/api/record";
+import { baseIMGUrl } from "@/api/request";
+import { onLoad, onReachBottom } from "@dcloudio/uni-app";
+import { ref } from "vue";
+
+const goTo = (path: String) => {
+  uni.navigateTo({ url: path });
+};
+
+const PageListInfo = ref({
+  pageNum: 1,
+  pageSize: 10,
+  searchKey: "",
+  type: "project",
+});
+const totle = ref(0);
+const greatList = ref([] as any);
+const BGS = ref([] as any);
+
+onLoad(async (option) => {
+  // 获取背景图
+  const ress: any = await GiftApi.getGoodDetail(option?.id);
+  if (ress.data.code === 0) {
+    ress.data.data.file.forEach((item: any) => {
+      BGS.value.push(baseIMGUrl + item.filePath);
+    });
+  }
+  const res: any = await ExploreApi.getModelList(PageListInfo.value);
+  if (res.data.code === 0) {
+    greatList.value = res.data.data.records;
+    totle.value = res.data.data.total;
+  }
+});
+// 滑动到底部 分页加载更多
+onReachBottom(async () => {
+  console.log("怎么不加载", greatList.value.length, totle.value);
+  if (
+    greatList.value.length > totle.value ||
+    greatList.value.length === totle.value
+  ) {
+    uni.showToast({
+      title: "没有更多了",
+      icon: "none",
+    });
+  } else {
+    PageListInfo.value.pageNum += 1;
+    const res: any = await ExploreApi.getModelList(PageListInfo.value);
+    greatList.value = [...greatList.value, ...res.data.data.records];
+  }
+});
+</script>
+
+<template>
+  <view class="all">
+    <view class="top">
+      <image height="100%" :src="BGS[0]" mode="aspectFill" class="openAnimal"></image>
+      <!-- <image :src="background" mode="widthFix" /> -->
+      <!-- <swiper class="swiper-box" :indicator-dots="BGS.length > 1 ? true : false" indicator-active-color="#FFFFFF" circular
+        autoplay>
+        <swiper-item v-for="item in BGS">
+          <image height="100%" :src="item" mode="aspectFill"></image>
+        </swiper-item>
+      </swiper> -->
+    </view>
+    <view class="bottom">
+      <view v-for="(item, index) in greatList" :key="index" :style="{ position: 'relative', height: '40vw' }">
+        <image :src="baseIMGUrl + item?.thumb" @tap="goTo(`detail/index?id=${item.id}`)" mode="aspectFill" />
+        <view class="text">{{ item?.name }}</view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.all {
+  width: 100%;
+
+  .top {
+    width: 100%;
+    height: 35vh;
+
+    .openAnimal {
+      animation: openAnimation 1.5s;
+    }
+
+    @keyframes openAnimation {
+      0% {
+        opacity: 0;
+      }
+
+      50% {
+        opacity: 0.5;
+
+      }
+
+      100% {
+        opacity: 1;
+      }
+    }
+
+    .swiper-box {
+      width: 100%;
+      height: 100%;
+
+      image {
+        width: 100%;
+        height: 100%;
+        border-radius: 4px;
+      }
+    }
+
+    image {
+      width: 100%;
+      height: 100%;
+      border-radius: 4px;
+    }
+  }
+
+  .bottom {
+    width: 100%;
+    margin-top: -15px;
+    box-sizing: border-box;
+    padding: 20px;
+    padding-top: 30px;
+    border-radius: 20px 20px 0 0;
+    background: #f7f1e6;
+    position: absolute;
+    z-index: 2;
+    display: grid;
+    grid-template-rows: 40vw 40vw;
+    grid-template-columns: calc(50% - 10px) calc(50% - 10px);
+    grid-gap: 20px 20px;
+    min-height: calc(65vh + 15px);
+
+    image {
+      width: 100%;
+      height: 100%;
+      border-radius: 4px;
+    }
+
+    .text {
+      width: 100%;
+      position: absolute;
+      font-size: 28rpx;
+      line-height: 30px;
+      color: white;
+      overflow: hidden;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+      text-align: center;
+      bottom: 0;
+      background-color: rgba(0, 0, 0, 0.65);
+      border-radius: 0 0 4px 4px;
+    }
+  }
+}
+</style>

+ 635 - 0
小程序/jingtailan/src/pages/home/index.vue

@@ -0,0 +1,635 @@
+<script setup lang='ts'>
+import TabBarTopHome from '@/components/TabBarTopHome.vue';
+import { baseIMGUrl } from '@/api/request';
+import { HomeApi } from '@/api/api/home/index';
+import { onLoad, onShow } from '@dcloudio/uni-app';
+import { ref } from 'vue';
+import TabBar from "@/components/TabBar.vue";
+import commonn from "@/static/data/common";
+
+const models = ref([] as any)
+
+const timer = ref()
+
+const baseUrl = `https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/`
+// 背景动画
+const bgAnimaled = ref(false)
+const changeAnimaled = ref(false)
+// 瓶子动画
+const bottleAnimaled = ref(false)
+// 切换动画
+const changBottleAn = ref(false)
+const nameChangeAn = ref(false)
+// 瓶子放大动画
+const bottleBig = ref(false)
+// 月光动画
+const moonAn1 = ref(false) // 放大过程
+const moonAn2 = ref(false) // 下跌过程
+
+const musicState = ref(false)
+
+// 瓶子切换列表
+const bottles = ref([
+  {
+    id: 1,
+    namePic: `${baseUrl}text2.png`,
+    bottlePic: `${baseUrl}2.png`,
+    disc1: '国家主席习近平在达沃斯国际会议中心出席世界经济论坛2017年年会开幕式,',
+    disc2: '向世界经济论坛赠送了一座《四面方尊》',
+    bgUrl: `${baseUrl}bg2.png`,
+    detailId: 47
+  },
+  {
+    id: 0,
+    namePic: `${baseUrl}text1.png`,
+    bottlePic: `${baseUrl}1.png`,
+    disc1: '中央政府',
+    disc2: '赠送西藏自治区大型礼品',
+    bgUrl: `${baseUrl}bg1.png`,
+    detailId: 49
+  },
+  {
+    id: 4,
+    namePic: `${baseUrl}text5.png`,
+    bottlePic: `${baseUrl}5.png`,
+    disc1: '中央政府',
+    disc2: '赠送宁夏回族自治区大型礼品',
+    bgUrl: `${baseUrl}bg2.png`,
+    detailId: 48
+  }, {
+    id: 2,
+    namePic: `${baseUrl}text3.png`,
+    bottlePic: `${baseUrl}3.png`,
+    disc1: '中央政府',
+    disc2: '赠送新疆维吾尔自治区大型礼品',
+    bgUrl: `${baseUrl}bg3.png`,
+    detailId: 50
+  }, {
+    id: 3,
+    namePic: `${baseUrl}text4.png`,
+    bottlePic: `${baseUrl}4.png`,
+    disc1: '中央政府',
+    disc2: '赠送广西壮族自治区大型礼品',
+    bgUrl: `${baseUrl}bg3.png`,
+    detailId: 43
+  }
+])
+
+// 开始滑动的y
+const startY = ref(0)
+const endY = ref(0)
+
+const handleTouchStart = (event: any) => {
+  startY.value = event.changedTouches[0].pageY
+}
+
+const handleTouchMove = (event: any) => {
+
+}
+const handleTouchEnd = (event: any) => {
+  endY.value = event.changedTouches[0].pageY
+  console.log(endY.value - startY.value)
+  if (endY.value - startY.value < -20) {
+    changBottleAn.value = true
+    moonAn1.value = true
+    setTimeout(() => {
+      moonAn2.value = true
+      moonAn1.value = false
+      setTimeout(() => {
+        moonAn2.value = false
+      }, 500)
+    }, 300)
+    setTimeout(() => {
+      curIndex.value = curIndex.value == (bottles.value.length - 1) ? 0 : curIndex.value + 1
+      setTimeout(() => {
+        nameChangeAn.value = true
+        setTimeout(() => {
+          nameChangeAn.value = false
+        }, 500)
+      }, 500)
+    }, 500)
+    setTimeout(() => {
+      changBottleAn.value = false
+      bottleBig.value = true
+      setTimeout(() => {
+        bottleBig.value = false
+      }, 500)
+    }, 1000)
+  }
+}
+
+
+const curIndex = ref(0)
+
+// 预加载所有图片
+const preloadImg = (bottles: any) => {
+  // bottles.forEach((item: any) => {
+  //   const img = new Image()
+  //   img.src = item.bgUrl
+  // })
+}
+
+
+
+onLoad(async (options) => {
+  const res: any = await HomeApi.getExplore();
+  if (res.data.code === 0) {
+    models.value = res.data.data;
+  }
+  preloadImg(bottles.value)
+  // 分配第一个瓶子
+  // curBottle.value = bottles.value[0]
+  curIndex.value = 0
+
+  const res2: any = await HomeApi.sendVisit();
+
+  // setTimeout(() => {
+  //   // 3s后如果缓存中还存在FIRST_KEY,那么就跳转
+  //   const key = uni.getStorageSync('FIRST_KEY')
+  //   if (key) {
+  //     console.log('该跳了')
+  //     uni.switchTab({
+  //       url: '../visit/index'
+  //     })
+  //   }
+  // }, 3000)
+
+})
+
+const musicPlay = () => {
+  // console.log('背景音乐播放')
+  commonn.innerAudioContext.play()
+  commonn.musicSta = true
+  musicState.value = true
+}
+
+const musicPause = () => {
+  // console.log('背景音乐关闭')
+  commonn.innerAudioContext.pause()
+  commonn.musicSta = false
+  musicState.value = false
+}
+
+const page = ref('')
+onShow(() => {
+  page.value = '/pages/home/index'
+  musicState.value = commonn.musicSta
+  if (!commonn.musicSta) {
+    commonn.innerAudioContext.currentTime = 0
+    commonn.innerAudioContext.play()
+    commonn.musicSta = true
+    musicState.value = true
+  }
+  bottleAnimaled.value = true
+  setTimeout(() => {
+    // 背景动画开启
+    bgAnimaled.value = true
+    changeAnimaled.value = true
+    setTimeout(() => {
+      changeAnimaled.value = false
+      bgAnimaled.value = false
+      bottleAnimaled.value = false
+    }, 2000)
+  }, 100)
+})
+
+// 跳转至国礼详情页
+const goDetail = (path: string, id: number) => {
+  console.log('跳转')
+  uni.navigateTo({ url: path + "?id=" + id });
+}
+</script>
+  
+<template>
+  <scroll-view class="all" :show-scrollbar="false">
+    <view class="all" v-if="models" @touchstart="handleTouchStart" @touchmove="handleTouchMove"
+      @touchend="handleTouchEnd">
+      <!-- <TabBarTop title="今日" />、 -->
+      <TabBarTopHome title="探索" />
+      <!-- <img class="parclose-box" :class="{ 'parclose-box-an': bgAnimaled }"
+      src="https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/parclose.png" alt="" mode="widthFix"> -->
+      <div class="parclose-box" :class="{ 'parclose-box-an': bgAnimaled && bottles[curIndex].id == 0, }">
+        <img class="bgImg" :src="bottles[curIndex].bgUrl" alt="" mode="widthFix">
+        <img class="moonImg" :class="{ 'parclose-change-an': moonAn1, 'parclose-change-an2': moonAn2 }"
+          :src="`${baseUrl}moon.png`" alt="" mode="heightFix">
+      </div>
+      <!-- 背景层 -->
+      <div class="bg-coverage">
+        <!-- 故宫 -->
+        <img class="gugon" :class="{ 'bg-coverage-gugon': bgAnimaled }"
+          src="https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/gugong.png" alt="" mode="widthFix">
+        <!-- 山下 -->
+        <img class="shanxia" :class="{ 'bg-coverage-gugon': bgAnimaled }"
+          src="https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/mDown.png" alt="" mode="widthFix">
+        <!-- 山上 -->
+        <img class="shanshang" :class="{ 'bg-coverage-shanshang': bgAnimaled }"
+          src="https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/mUp.png" alt="" mode="widthFix">
+        <!-- 云 -->
+        <img class="cloud" :class="{ 'bg-coverage-cloud': bgAnimaled }"
+          src="https://houseoss.4dkankan.com/project/bjfljtl/img/data/A1Day/cloud.png" alt="" mode="widthFix">
+      </div>
+      <!-- 瓶子层 -->
+      <div class="bottle-coverage">
+        <!-- 作品名称 -->
+        <img class="bottle-name" :class="{ 'bottle-name-an': changeAnimaled, 'name-change-an': nameChangeAn }"
+          :style="{ display: changBottleAn && !nameChangeAn ? 'none' : '' }" :src="bottles[curIndex].namePic" alt=""
+          @tap="goDetail('/pages/explore/gift/detail/index', bottles[curIndex].detailId)" mode="widthFix">
+        <view v-show="!changBottleAn && !nameChangeAn" class="bottle-name-view">
+
+        </view>
+        <!-- 文字 -->
+        <div class="disc-box" :class="{ 'bottle-change-an': changBottleAn }"
+          :style="{ fontSize: bottles[curIndex].id == 1 ? '25rpx' : 'auto', height: bottles[curIndex].id == 4 ? '45%' : '' }">
+          <!-- 作品 -->
+          <img class="bottle-box"
+            :class="{ 'bottle-box-an': bottleAnimaled && bottles[curIndex].id == 0, 'bottleItem-change-an': bottleBig }"
+            :src="bottles[curIndex].bottlePic" alt="" mode="heightFix">
+          <div :class="{ 'disc-boxx': bgAnimaled }">
+            <div class="disc-top">{{ bottles[curIndex].disc1 }}</div>
+            <div class="disc-bottom">{{ bottles[curIndex].disc2 }}</div>
+          </div>
+        </div>
+      </div>
+    </view>
+    <TabBar :page="page" />
+    <div class="music-box">
+      <image v-show="!musicState" @click="musicPlay()" src="@/static/img/bottomInco/musicAc.png" alt="" />
+      <image v-show="musicState" @click="musicPause()" src="@/static/img/bottomInco/music.png" alt="" />
+    </div>
+    <!-- <audio src="https://houseoss.4dkankan.com/project/bjfljtl/audio/bgMusic.mp3" style="display: none;" autoplay></audio> -->
+  </scroll-view>
+</template>
+  
+<style lang='scss' scoped>
+div,
+image {
+  overflow: hidden;
+}
+
+image {
+  will-change: transform;
+}
+
+
+::-webkit-scrollbar {
+  display: none !important;
+}
+
+
+.all {
+  width: 100vw;
+  height: calc(100vh - 150rpx);
+  background-color: #ffffff;
+  overflow: hidden;
+
+
+  .parclose-box {
+    width: 100vw;
+    height: calc(100vh - 150rpx);
+    position: absolute;
+    top: 0;
+    left: 0;
+    overflow: hidden;
+
+    // display: none;
+    .bgImg {
+      width: 100%;
+      max-height: 100%;
+      overflow: hidden;
+    }
+
+    .moonImg {
+      height: 50%;
+      max-height: 50%;
+      position: absolute;
+      overflow: hidden;
+      top: 15%;
+      left: 50%;
+      transform: translateX(-50%);
+      overflow: hidden;
+    }
+
+    // 切换瓶子(前半段)
+    .parclose-change-an {
+      animation: parclose-change-animal 0.5s;
+    }
+
+    @keyframes parclose-change-animal {
+      0% {
+        // left: 50%;
+        transform: scale(1) translateX(-50%);
+        display: block;
+      }
+
+      100% {
+        transform: scale(1.3) translateX(-39%);
+      }
+    }
+
+    .parclose-change-an2 {
+      animation: parclose-change-animal2 1s;
+
+      @keyframes parclose-change-animal2 {
+        0% {
+          // left: 50%;
+          top: -50%;
+          transform: scale(1) translateX(-50%);
+          display: none;
+        }
+
+        100% {
+          transform: scale(1) translateX(-50%);
+          display: block;
+        }
+      }
+    }
+  }
+
+  .parclose-box-an {
+    animation: parclose-box-animal .7s;
+  }
+
+  @keyframes parclose-box-animal {
+    0% {
+      transform: scale(10);
+    }
+
+    100% {
+      transform: scale(1);
+
+    }
+  }
+
+
+
+
+  .bg-coverage {
+    width: 100%;
+    height: 100%;
+    position: relative;
+    overflow: hidden;
+
+    .bg-coverage-gugon {
+      animation: animateingItem 1s;
+    }
+
+    @keyframes animateingItem {
+      0% {
+        bottom: -100%;
+      }
+
+      100% {
+        bottom: 0%;
+      }
+    }
+
+    .bg-coverage-shanshang {
+      animation: animateingItemShanshang 1.5s;
+    }
+
+    @keyframes animateingItemShanshang {
+      0% {
+        bottom: -100%;
+      }
+
+      100% {
+        bottom: 30%;
+      }
+    }
+
+
+    .bg-coverage-cloud {
+      animation: animateingItemCloud 1.5s;
+    }
+
+    @keyframes animateingItemCloud {
+      0% {
+        display: none;
+        transform: scale(3);
+      }
+
+      100% {
+        display: block;
+        transform: scale(1);
+
+      }
+    }
+
+    .gugon {
+      width: 100%;
+      position: absolute;
+      bottom: 0;
+      left: 0;
+    }
+
+    .shanxia {
+      width: 100%;
+      position: absolute;
+      bottom: 0;
+      right: 0;
+    }
+
+    .shanshang {
+      width: 100%;
+      position: absolute;
+      bottom: 30%;
+    }
+
+    .cloud {
+      width: 45%;
+      position: absolute;
+      right: -20rpx;
+      top: 15%;
+      // transform: scale(64);
+    }
+  }
+
+  .bottle-coverage {
+    width: 100%;
+    height: calc(100vh - 150rpx);
+    position: absolute;
+    top: 0;
+    left: 0;
+    overflow: hidden;
+
+    .parclose-box {
+      width: 100%;
+      height: 100%;
+      position: absolute;
+      top: 0;
+      left: 0;
+      display: none;
+      z-index: -1;
+      overflow: hidden;
+    }
+
+    .bottle-name {
+      width: 10%;
+      position: absolute;
+      top: 15%;
+      right: 15%;
+      overflow: hidden;
+      z-index: 100;
+    }
+
+    .bottle-name-an {
+      animation: bottle-name-animal .5s;
+    }
+
+    @keyframes bottle-name-animal {
+      0% {
+        display: none;
+        transform: scale(3);
+      }
+
+      100% {
+        display: block;
+        transform: scale(1);
+      }
+    }
+
+    .bottle-name-view {
+      width: 7.5%;
+      height: 23%;
+      position: absolute;
+      top: 15%;
+      right: 16%;
+      z-index: 99;
+      animation-name: fadenum;
+      animation-duration: 2s;
+      animation-iteration-count: infinite;
+      animation-direction: alternate;
+    }
+
+    @keyframes fadenum {
+      from {
+        box-shadow: 0 0 10px 10px rgba(255, 255, 255, 0.856);
+      }
+
+      to {
+        box-shadow: 0 0 5px 5px rgba(255, 255, 255, 0.733);
+      }
+    }
+
+    .name-change-an {
+      animation: name-change-animal 1s;
+    }
+
+    @keyframes name-change-animal {
+      0% {
+        display: none;
+        transform: scale(1.5);
+      }
+
+      100% {
+
+        transform: scale(1);
+      }
+    }
+
+    .disc-box {
+      width: 65%;
+      height: 55%;
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      text-align: center;
+      color: #ffffff;
+      font-family: 'SOURCEHANSERIFCN-BOLD';
+
+      image {
+        width: 100%;
+        height: 100%;
+      }
+
+      .bottle-box {
+        transform: scale(1.04);
+      }
+
+      .bottle-box-an {
+        animation: bottle-box-animal 1s;
+      }
+
+      @keyframes bottle-box-animal {
+        0% {
+          display: none;
+          transform: scale(0.6);
+        }
+
+        50% {
+          display: block;
+          transform: scale(1);
+        }
+
+        100% {
+          display: block;
+          transform: scale(1.04);
+        }
+      }
+
+      .bottleItem-change-an {
+        animation: bottleItem-box-animal 1s forwards;
+      }
+
+      @keyframes bottleItem-box-animal {
+        0% {
+          transform: scale(1);
+        }
+
+        100% {
+          transform: scale(1.04);
+        }
+      }
+
+      .disc-boxx {
+        animation: disc-boxx-animal 1s;
+      }
+
+      @keyframes disc-boxx-animal {
+        0% {
+          margin-top: 100%;
+        }
+
+        100% {
+          margin-bottom: 0;
+        }
+      }
+
+
+
+    }
+
+    .bottle-change-an {
+      animation: bottle-change-animal 1s;
+    }
+
+    @keyframes bottle-change-animal {
+      0% {
+        top: 50%;
+      }
+
+      50% {
+        top: -40%;
+      }
+
+      100% {
+        top: 50%;
+      }
+    }
+  }
+}
+
+.music-box {
+  position: absolute;
+  bottom: 3%;
+  right: 3%;
+  width: 80rpx;
+  height: 80rpx;
+
+  image {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>

+ 106 - 0
小程序/jingtailan/src/pages/mine/content/index copy.vue

@@ -0,0 +1,106 @@
+<script setup lang='ts'>
+import { MineApi } from '@/api/api/mine';
+import { onShow, onReachBottom } from '@dcloudio/uni-app';
+
+import { ref } from 'vue';
+const PageListInfo = ref({
+  pageNum: 1,
+  pageSize: 10,
+  searchKey: '',
+})
+
+const greatList = ref([] as any)
+const totle = ref(0)
+
+
+onShow(async (options) => {
+  const res: any = await MineApi.getContentList(PageListInfo)
+  if (res.data.code === 0) {
+    greatList.value = res.data.data.records;
+  } else {
+    uni.showToast({
+      title: res.data.msg,
+      icon: 'none'
+    })
+    setTimeout(() => {
+      uni.navigateBack();
+    }, 500)
+  }
+})
+
+// 滑动到底部 分页加载更多
+onReachBottom(async () => {
+  if (greatList.value.length > totle.value || greatList.value.length === totle.value) {
+    uni.showToast({
+      title: '没有更多了',
+      icon: 'none'
+    })
+  } else {
+    PageListInfo.value.pageNum += 1;
+    const res: any = await MineApi.getContentList(PageListInfo.value);
+    greatList.value = [...greatList.value, ...res.data.data.records]
+
+  }
+})
+
+// 点击进入详情
+const goTo = async (id: Number, type: String) => {
+  const data = {
+    moduleId: id,
+    moduleType: type
+  }
+  switch (type) {
+    case 'master':
+      skip(`../../explore/great/detail/index?id=${id}`);
+      break;
+    case 'craft':
+      skip(`../../explore/craft/detail/index?id=${id}`)
+      break;
+    case 'block':
+      skip(`../../explore/gift/detail/index?id=${id}`)
+      break;
+  }
+}
+
+const skip = (path: String) => {
+  uni.navigateTo({
+    url: path
+  })
+}
+
+</script>
+  
+<template>
+  <view class="all">
+    <view style="text-align: center;" v-if="greatList.length === 0">
+      暂无收藏
+    </view>
+    <view v-else class="content-item" v-for="item in greatList" :key="item" @tap="goTo(item.moduleId, item.type)">
+      {{ item.name }}
+    </view>
+  </view>
+</template>
+  
+<style lang='scss' scoped>
+.all {
+  min-width: 100vw;
+  min-height: 100vh;
+  background: #F7F1E6;
+  // border-top: 1px solid rgba(0, 0, 0, 0.15);
+  padding-top: 5px;
+  box-shadow: 0px 0px 8px 0px rgba(209, 209, 209, 0.15);
+
+  .content-item {
+    height: 12vh;
+    background: #ffffff65;
+    box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.15);
+    margin-bottom: 10px;
+    padding-left: 6vw;
+    line-height: 10vh;
+    font-weight: bold;
+    font-size: 32rpx;
+    color: rgba(0,0,0,0.6);
+    line-height: 12vh;
+  }
+}
+</style>

+ 123 - 0
小程序/jingtailan/src/pages/mine/content/index.vue

@@ -0,0 +1,123 @@
+<script setup lang="ts">
+import { MineApi } from "@/api/api/mine";
+import { onLoad, onShow } from "@dcloudio/uni-app";
+import { ref } from "vue";
+
+const PageListInfo = ref({
+  pageNum: 1,
+  pageSize: 10,
+  searchKey: "",
+});
+
+const greatList = ref([] as any);
+// 获取内容收藏列表
+const getContentListfn = async () => {
+  const res: any = await MineApi.getContentList(PageListInfo);
+  if (res.data.code === 0) {
+    greatList.value = res.data.data.records;
+  } else {
+    uni.showToast({
+      title: res.data.msg,
+      icon: "none",
+    });
+    setTimeout(() => {
+      uni.navigateBack();
+    }, 500);
+  }
+};
+
+// 路由拦截
+const checkToken = async () => {
+  const ress: any = await MineApi.checkToken();
+  if (ress.data.data) {
+    getContentListfn();
+  } else {
+    console.log('输出content')
+    uni.showToast({
+      title: "身份过期,请重新登录",
+      icon: "none",
+    });
+    uni.removeStorage({
+      key: "JTL_token",
+    });
+    uni.removeStorage({
+      key: "JTL_userInfo",
+    });
+    setTimeout(() => {
+      uni.reLaunch({
+        url: "../../../mine/index",
+      });
+    }, 1000);
+  }
+};
+
+// 点击进入详情
+const skip = (path: String) => {
+  uni.navigateTo({
+    url: path,
+  });
+};
+const goTo = async (id: Number, type: String) => {
+  const data = {
+    moduleId: id,
+    moduleType: type,
+  };
+  switch (type) {
+    case "master":
+      skip(`../../explore/great/detail/index?id=${id}`);
+      break;
+    case "craft":
+      skip(`../../explore/craft/detail/index?id=${id}`);
+      break;
+    case "block":
+      skip(`../../explore/gift/detail/index?id=${id}`);
+      break;
+  }
+};
+onShow(() => {
+  checkToken();
+});
+</script>
+
+<template>
+  <div class="all">
+    <view class="all">
+      <view style="text-align: center" v-if="greatList.length === 0">
+        暂无收藏
+      </view>
+      <view
+        v-else
+        class="content-item"
+        v-for="item in greatList"
+        :key="item"
+        @click="goTo(item.moduleId, item.type)"
+      >
+        {{ item.name }}
+      </view>
+    </view>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.all {
+  min-width: 100vw;
+  min-height: 100vh;
+  background: #f7f1e6;
+  // border-top: 1px solid rgba(0, 0, 0, 0.15);
+  padding-top: 5px;
+  box-shadow: 0px 0px 8px 0px rgba(209, 209, 209, 0.15);
+
+  .content-item {
+    height: 12vh;
+    background: #ffffff65;
+    box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.15);
+    margin-bottom: 10px;
+    padding-left: 6vw;
+    line-height: 10vh;
+    font-weight: bold;
+    font-size: 32rpx;
+    color: rgba(0, 0, 0, 0.6);
+    line-height: 12vh;
+  }
+}
+</style>

+ 140 - 0
小程序/jingtailan/src/pages/mine/culturalRelic/index.vue

@@ -0,0 +1,140 @@
+<script setup lang="ts">
+import { baseIMGUrl } from "@/api/request";
+import { ref } from "vue";
+import { onShow, onReachBottom } from "@dcloudio/uni-app";
+
+import { MineApi } from "@/api/api/mine/index";
+
+const greatList = ref([] as any);
+
+const PageListInfo = ref({
+  pageNum: 1,
+  pageSize: 10,
+  searchKey: "",
+});
+const totle = ref(0);
+
+const goTo = async (id: Number) => {
+  const data = {
+    moduleId: id,
+    moduleType: "goods",
+  };
+  const res: any = await MineApi.collectDetail(data);
+  if (res.data.code === 0) {
+    uni.navigateTo({
+      url: `../../analyse/detail/culturalRelicDetail/index?id=${id}`,
+    });
+  } else {
+    uni.showToast({
+      title: "藏品信息出错",
+    });
+  }
+};
+
+onShow(async (options) => {
+  const res: any = await MineApi.getGoodstList(PageListInfo.value);
+  if (res.data.code === 0) {
+    greatList.value = res.data.data.records;
+  } else {
+    uni.showToast({
+      title: res.data.msg,
+      icon: "none",
+    });
+    setTimeout(() => {
+      uni.navigateBack();
+    }, 500);
+  }
+});
+
+// 滑动到底部 分页加载更多
+onReachBottom(async () => {
+  if (
+    greatList.value.length > totle.value ||
+    greatList.value.length === totle.value
+  ) {
+    uni.showToast({
+      title: "没有更多了",
+      icon: "none",
+    });
+  } else {
+    PageListInfo.value.pageNum += 1;
+    const res: any = await MineApi.getGoodstList(PageListInfo.value);
+    greatList.value = [...greatList.value, ...res.data.data.records];
+  }
+});
+</script>
+
+<template>
+  <view class="all">
+    <view style="width: 100%; text-align: center" v-if="greatList.length === 0">
+      暂无收藏
+    </view>
+    <view v-else class="list">
+      <view
+        class="list-item"
+        v-for="item in greatList"
+        :key="item.id"
+        @tap="goTo(item.moduleId)"
+      >
+        <image :src="baseIMGUrl + item.thumb" mode="widthFix" />
+        <view class="list-name">{{ item.name }}</view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.all {
+  min-width: 100vw;
+  min-height: 100vh;
+  background: #f7f1e6;
+  padding-top: 10px;
+
+  .list {
+    margin: auto;
+    width: 90%;
+    /* 声明一个容器 */
+    display: grid;
+    grid-template-columns: repeat(2, 50%);
+    /* 声明行间距和列间距 */
+    grid-column-gap: 10px;
+    grid-row-gap: 5px;
+    margin-top: 10px;
+
+    &-item {
+      width: 90%;
+      position: relative;
+      height: 40vw;
+      background: linear-gradient( 180deg, rgba(47,40,40,0.6) 0%, #FFFFFF 100%);
+      border-radius: 5px;
+      text-align: center;
+      box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.4);
+
+      image {
+        width: 50%;
+        max-height: 40vw;
+        margin: 10px auto;
+        // height: 100%;
+      }
+
+      .list-name {
+        width: 100%;
+        position: absolute;
+        bottom: 0;
+        line-height: 30px;
+        text-align: center;
+        background: rgba(0, 0, 0, 0.65);
+        color: #ffffff;
+        border-radius: 0 0 4px 4px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        font-size: 28rpx;
+      }
+    }
+
+    /* 分别表示两行的高度 */
+    // grid-template-rows: 40px 40px 40px;
+  }
+}
+</style>

+ 822 - 0
小程序/jingtailan/src/pages/mine/index.vue

@@ -0,0 +1,822 @@
+<script setup lang="ts">
+import * as baseInfo from "@/api/record";
+import { baseIMGUrl } from "@/api/request";
+import { ref } from "vue";
+import TabBarTopHome from "@/components/TabBarTopHome.vue";
+
+import { LogonApi } from "@/api/api/login/index";
+import { MineApi } from "@/api/api/mine/index";
+import { onLoad, onShow } from "@dcloudio/uni-app";
+import TabBar from "@/components/TabBar.vue";
+
+const userInfo = ref({} as any);
+const noLogin = ref(true);
+
+const isMessage = ref(false);
+const messageText = ref("");
+const defaultHeadUrl = ref(
+  "https://houseoss.4dkankan.com/project/bjfljtl/img/bottomInco/defaultHead.png"
+);
+
+const top = uni.getMenuButtonBoundingClientRect().top;
+const height = uni.getMenuButtonBoundingClientRect().height;
+
+// 提交留言信息
+const submitMessage = async () => {
+  if (messageText.value.length < 5 || messageText.value.length > 200) {
+    uni.showToast({
+      title: "请输入5-200字!",
+      icon: "none",
+    });
+  } else {
+    const res: any = await MineApi.submitMeg(
+      messageText.value,
+      userInfo.value.nickName
+    );
+    if (res.data.code === 0) {
+      isMessage.value = false;
+      uni.showToast({
+        title: "留言成功",
+      });
+    }
+  }
+};
+
+const others = ref([] as any);
+
+// const others = [
+//   {
+//     name: "大众点评",
+//     icon: "https://hbimg.b0.upaiyun.com/2736424c8c107adaf0917de571b2dfb48b76555514d3d-gUTXtZ_fw658",
+//     appid: "wx734c1ad7b3562129",
+//     path: "packages/trip/mpvue-pages/pages/poi/poi?poiId=FnKeGux84asrPKr6&shopuuid=FnKeGux84asrPKr6&mode=subpackage&from=list",
+//   },
+//   {
+//     name: "携程",
+//     icon: "https://down.51rc.com/imagefolder/Logo/L11040000/11037518_b20190326102751.gif",
+//     appid: "wx0e6ed4f51db9d078",
+//     path: "pages/gs/sight/newDetail?sightId=1487166&fcpGUID=fcp_navigateTo_5&pubRouteBegin=1688348640703",
+//   },
+// ];
+
+const contentTotleNum = ref(0);
+const antiqueTotleNum = ref(0);
+
+// 获取文物收藏totle数
+const antiqueTotle = async () => {
+  const res: any = await MineApi.getGoodstList(PageListInfo.value);
+  if (res.data.code === 0) {
+    antiqueTotleNum.value = res.data.data.total;
+  } else {
+    uni.showToast({
+      title: res.data.msg,
+      icon: "none",
+    });
+  }
+};
+
+// 获取内容收藏totle数
+const contentTotle = async () => {
+  const res: any = await MineApi.getContentList(PageListInfo);
+  if (res.data.code === 0) {
+    contentTotleNum.value = res.data.data.total;
+  } else {
+    uni.showToast({
+      title: res.data.msg,
+      icon: "none",
+    });
+  }
+};
+
+const goTo = async (path: String) => {
+  const ress: any = await MineApi.checkToken();
+  if (ress.data.data) {
+    uni.navigateTo({
+      url: path,
+    });
+  } else {
+    console.log("输出mineNow");
+
+    uni.showToast({
+      title: "身份过期,请重新登录",
+      icon: "none",
+    });
+    uni.removeStorage({
+      key: "JTL_token",
+    });
+    uni.removeStorage({
+      key: "JTL_userInfo",
+    });
+    setTimeout(() => {
+      uni.reLaunch({
+        url: "/pages/mine/index",
+      });
+    }, 1000);
+  }
+};
+
+const isShowCode = ref(false);
+const codePath = ref("");
+const goToMini = (app: String, path: String) => {
+  // 抖音和小红书,直接打开图片让用户保存图片
+
+  console.log(app, path);
+  if (app == "other") {
+    // codePath.value = path
+    // isShowCode.value = true
+    // uni.showToast({
+    //   title: '保存图片到相册,并打开软件扫一扫',
+    // });
+    uni.previewImage({
+      current: 0,
+      urls: [path],
+      showmenu: true,
+    });
+  } else {
+    uni.navigateToMiniProgram({
+      appId: app,
+      path: path,
+    });
+  }
+};
+// 打开微信授权确认框
+const openUserProfile = () => {
+  return new Promise((resolve, reject) => {
+    uni.getUserProfile({
+      lang: "zh_CN",
+      desc: "获取你的昵称、头像、地区及性别",
+      success: (res) => {
+        resolve(res);
+      },
+      // 失败回调
+      fail: (err) => {
+        reject(err);
+      },
+    });
+  });
+};
+
+// 获得weixin Code
+const getWxCode = () => {
+  return new Promise((resolve, reject) => {
+    uni.login({
+      success(res) {
+        //这里就是code,可以打印看下
+        resolve(res.code);
+      },
+      fail(err) {
+        reject(err);
+      },
+    });
+  });
+};
+
+// 用户名和用户头像
+const userNickName = ref("");
+const userHeadUrl = ref("");
+const userInfoData = ref({} as any);
+
+// 完善信息——头像昵称填写(需要用户手动填入微信信息,微信小程序目前已经不允许API调用的方式获取用户信息)
+const preInfo = () => {
+  // console.log('完善信息')
+  uni.navigateTo({
+    url: "perfectInfo/index",
+  });
+};
+
+const getUserInfo = async () => {
+  const res: any = await MineApi.getUserInfo();
+  console.log();
+};
+
+// 授权触发事件
+const wxLogin = () => {
+  if (noLogin.value) {
+    let p1 = getWxCode();
+    let p2 = openUserProfile();
+    p1.then((code) => {
+      return code;
+    }).then((code) => {
+      return new Promise((resolve, reject) => {
+        p2.then(async (res: any) => {
+          // userInfoData.value = res.userInfo
+          // // 获得用户名和用户头像
+          userNickName.value = res.userInfo.nickName;
+          userHeadUrl.value = res.userInfo.avatarUrl;
+          resolve({
+            code,
+            iv: res.iv,
+            encryptedData: res.encryptedData,
+          });
+        }).catch((err) => {
+          reject(err);
+        });
+      }).then((res: any) => {
+        // 得到code 拉token
+        LogonApi.login(res.code).then((res: any) => {
+          if (res.data.code === 0) {
+            setTimeout(() => {
+              // 更新用户信息
+              MineApi.updateUser({
+                avatarUrl: userInfoData.value.avatarUrl,
+                city: userInfoData.value.city,
+                country: userInfoData.value.country,
+                gender: userInfoData.value.gender ? "女" : "男",
+                nickName: userInfoData.value.nickName,
+                phone: "",
+                province: userInfoData.value.province,
+              });
+            }, 1000);
+            // 改为登录状态
+            noLogin.value = false;
+            // 存放token
+            uni.setStorageSync("JTL_token", res.data.data.token);
+            // 存放登录用户信息
+            userInfo.value = res.data.data.wxUser;
+            uni.setStorageSync("JTL_userInfo", res.data.data.wxUser);
+
+            antiqueTotle();
+            contentTotle();
+            // 判断头像和用户名是否为空,前往头像手动上传页面
+            if (
+              userInfo.value.nickName == "" ||
+              userInfo.value.avatarUrl == ""
+            ) {
+              setTimeout(() => {
+                uni.showToast({
+                  title: "授权成功,请完善个人信息",
+                });
+              }, 300);
+              preInfo();
+            } else {
+              setTimeout(() => {
+                uni.showToast({
+                  title: "授权成功",
+                });
+              }, 300);
+            }
+          }
+        });
+      });
+    });
+  } else {
+    // 如果当前为登录状态的那么就是修改/完善个人信息
+    preInfo();
+  }
+};
+
+// 检查登录缓存
+const checkToken = async () => {
+  const ress: any = await MineApi.checkToken();
+  if (ress.data.data) {
+    noLogin.value = false;
+    const res: any = await MineApi.getUserInfo();
+    userInfo.value = res.data.data;
+    if (userInfo.value.avatarUrl === "") {
+      userInfo.value.avatarUrl = defaultHeadUrl.value;
+    }
+    antiqueTotle();
+    contentTotle();
+  }
+};
+
+const PageListInfo = ref({
+  pageNum: 1,
+  pageSize: 10,
+  searchKey: "",
+});
+
+// 景泰蓝艺术博物馆经纬数据
+const locatioData = {
+  longitude: 116.413699,
+  latitude: 39.864144,
+};
+
+// 点击位置  景泰蓝博物馆位置地图
+const openMap = () => {
+  uni.openLocation({
+    latitude: locatioData.latitude,
+    longitude: locatioData.longitude,
+  });
+};
+
+// 获取三方平台
+const getTripartiteList = async () => {
+  const res: any = await MineApi.tripartiteList();
+  if (res.data.code == 0) {
+    others.value = res.data.data;
+  }
+};
+
+onLoad(async (option) => {
+  // 自动跳转后自动清除定时器
+  const key = uni.getStorageSync("FIRST_KEY");
+  if (key) {
+    uni.removeStorage({
+      key: "FIRST_KEY",
+    });
+  }
+  checkToken();
+  getTripartiteList();
+});
+const page = ref("");
+onShow(async () => {
+  page.value = "/pages/mine/index";
+  const pages = getCurrentPages();
+  let currentPage = pages[pages.length - 1];
+
+  console.log("触发了", currentPage.route);
+  // 检查是否登录
+  const ress: any = await MineApi.checkToken();
+  if (ress.data.data) {
+    const res: any = await MineApi.getUserInfo();
+    userInfo.value = res.data.data;
+    antiqueTotle();
+    contentTotle();
+  }
+});
+</script>
+
+<template>
+  <view class="all">
+    <TabBarTopHome title="我的" />
+
+    <view
+      style="
+        padding-left: 10px;
+        padding-right: 10px;
+        max-height: 100vh;
+        overflow: hidden;
+      "
+    >
+      <view class="head" @tap="wxLogin">
+        <image
+          @error="
+            () => {
+              userInfo.avatarUrl = '';
+            }
+          "
+          :src="
+            noLogin
+              ? defaultHeadUrl
+              : userInfo.avatarUrl != '' || userInfo.avatarUrl.includes('https')
+              ? userInfo.avatarUrl
+              : defaultHeadUrl
+          "
+          mode="scaleToFill"
+        />
+        <view class="username"
+          >{{
+            noLogin
+              ? "请点击登录"
+              : userInfo.nickName != ""
+              ? userInfo.nickName
+              : "点击完善信息"
+          }}
+        </view>
+      </view>
+      <view class="content">
+        <view class="content-item" @tap="goTo('culturalRelic/index')">
+          <view class="content-item-left"
+            ><span>文物收藏</span>
+            <view v-if="!noLogin">{{ antiqueTotleNum }}</view>
+          </view>
+          <image
+            v-if="!noLogin"
+            :src="baseInfo.baseIMGUrl + '/bottomInco/right.png'"
+            mode="scaleToFill"
+          />
+        </view>
+        <view class="content-item" @tap="goTo('content/index')">
+          <view class="content-item-left"
+            ><span>内容收藏</span>
+            <view v-if="!noLogin">{{ contentTotleNum }}</view>
+          </view>
+          <image
+            v-if="!noLogin"
+            :src="baseInfo.baseIMGUrl + '/bottomInco/right.png'"
+            mode="scaleToFill"
+          />
+        </view>
+        <view
+          class="content-item"
+          @tap="
+            () => {
+              isMessage = true;
+            }
+          "
+        >
+          <view>我要留言</view>
+          <view class="content-item-right">
+            <view> 填写留言 </view>
+            <image
+              :src="baseInfo.baseIMGUrl + '/bottomInco/right.png'"
+              mode="scaleToFill"
+            />
+          </view>
+        </view>
+        <view class="content-item content-last" style="">
+          <view class="last1">三方平台评论</view>
+          <view class="last2"
+            ><view class="others" v-for="item in others" :key="item.name">
+              <image
+                @tap="
+                  goToMini(item.appId, item.name === '京东' ? '' : item.patch)
+                "
+                :src="baseIMGUrl + item.icon"
+                mode="scaleToFill"
+              /> </view
+          ></view>
+        </view>
+        <view class="position-box">
+          <image
+            :src="baseInfo.baseIMGUrl + '/data/C1Visit/home/4.png'"
+            mode="widthFix"
+            @tap="openMap"
+          />
+          <view class="info-box">
+            <view>中国景泰蓝艺术博物馆</view>
+            <view>中国北京市东城区安乐林路10号</view>
+            <view>开放时间:09:00-16:30 电话:010-67211677</view>
+          </view>
+        </view>
+      </view>
+
+      <!-- 登录界面
+    <view class="login-box" v-if="noLogin">
+      <view class="center">
+        <view class="head">
+          <image :src="userInfo.head" mode="scaleToFill" />
+        </view>
+        <view class="form-box">
+          <view class="input-box">
+            <input placeholder="请输入账号" type="text" v-model="userInfo.username">
+          </view>
+          <view class="input-box">
+            <input placeholder="请输入密码" type="password" v-model="userInfo.password">
+          </view>
+
+          <view class="login-btn">
+            登 录
+          </view>
+          <view class="others">
+            <view>新建账号</view>
+            <view>忘记密码</view>
+          </view>
+        </view>
+      </view>
+    </view> -->
+
+      <!-- 留言弹框 -->
+      <view
+        class="message-box"
+        v-if="isMessage"
+        :style="{ height: `calc(100% + ${top + height}px)` }"
+      >
+        <view class="pop-box">
+          <textarea
+            name="message"
+            id="message"
+            v-model="messageText"
+            cols="30"
+            rows="10"
+            placeholder="请输入留言内容,5-200个字"
+            minlength="5"
+            maxlength="200"
+          ></textarea>
+          <view class="btns">
+            <view
+              class="btn-item"
+              @tap="
+                () => {
+                  isMessage = false;
+                  messageText = '';
+                }
+              "
+              >取消</view
+            >
+            <view class="btn-item" @tap="submitMessage">确定</view>
+          </view>
+        </view>
+      </view>
+
+      <!-- 二维码图片 -->
+      <!-- <view class="code-box" v-if="isShowCode"  @click="isShowCode = false" >
+        <image id="code-image" :src="codePath" mode="widthFix"></image>
+        <view>长按保存图片在相册,打开软件扫一扫</view>
+      </view> -->
+    </view>
+  </view>
+  <TabBar :page="page" />
+</template>
+
+<style lang="scss" scoped>
+::-webkit-scrollbar {
+  display: none !important;
+}
+
+.all {
+  min-width: 100vw;
+  height: calc(100vh - 150rpx);
+  background: #f7f1e6;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  box-sizing: border-box;
+  padding-top: 9vh;
+
+  .head {
+    height: 17vh;
+    margin: auto;
+    display: flex;
+    flex-direction: column;
+    justify-content: top;
+
+    .username {
+      color: rgba(0, 0, 0, 0.7);
+      padding-top: 20px;
+    }
+
+    image {
+      height: 10vh;
+      width: 10vh;
+      border-radius: 50px;
+      margin: auto;
+    }
+
+    view {
+      margin: auto;
+      font-weight: bold;
+      text-align: center;
+      margin-top: -10%;
+    }
+  }
+
+  .content {
+    width: 100%;
+    height: calc(100vh - 200rpx);
+    border-radius: 20px 20px 0 0;
+    box-shadow: 0px -3px 15px 0px rgba(0, 0, 0, 0.3);
+    padding: 15px 30px;
+    box-sizing: border-box;
+    background-size: cover;
+    background-image: url("https://houseoss.4dkankan.com/project/bjfljtl/img/data/E1Mine/bg.png");
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+
+    &-item {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      height: 7.5vh;
+      border-bottom: 1px solid rgba(107, 107, 107, 0.192);
+
+      image {
+        width: 20px;
+        height: 20px;
+      }
+
+      &-left {
+        display: flex;
+        justify-content: left;
+        align-items: center;
+
+        view {
+          margin-left: 5vw;
+          height: 20px;
+          width: 20px;
+          border-radius: 50px;
+          background-color: #e07c67;
+          text-align: center;
+          line-height: 20px;
+          color: white;
+          font-size: 26rpx;
+        }
+      }
+
+      &-right {
+        display: flex;
+        justify-content: right;
+
+        view {
+          margin-right: 5px;
+          color: rgba(54, 54, 54, 0.705);
+        }
+      }
+    }
+
+    .position-box {
+      // box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.4);
+      flex: 1;
+      margin-left: -30px;
+      margin-right: -30px;
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      // position: absolute;
+      width: calc(100vw - 20px);
+      margin-bottom: 210rpx;
+      // bottom: 150rpx;
+
+      .info-box {
+        width: 100%;
+        background: #ffffff80;
+        margin-top: -24rpx;
+        padding: 20px 10px 5%;
+        box-sizing: border-box;
+        font-size: 10px;
+        line-height: 16px;
+        color: #000000b9;
+      }
+
+      image {
+        width: 100%;
+      }
+    }
+
+    &-last {
+      margin-top: 2vh;
+      border-bottom: none;
+      justify-content: space-between;
+      align-items: self-start;
+      height: auto;
+      .last1 {
+        width: 25%;
+      }
+      .last2 {
+        width: 74%;
+        display: flex;
+        flex-wrap: wrap;
+        image {
+          margin-bottom: 5px;
+        }
+      }
+
+      .others {
+        image {
+          width: 5vh;
+          height: 5vh;
+          border-radius: 5px;
+          margin-left: 5px;
+        }
+      }
+    }
+  }
+
+  .login-box {
+    position: absolute;
+    width: 100vw;
+    height: 100vh;
+    backdrop-filter: blur(30px);
+    display: flex;
+    justify-content: center;
+    flex-direction: column;
+
+    .center {
+      width: 70%;
+      // background: gold;
+      height: 70%;
+      margin: auto;
+
+      .head {
+        width: 100%;
+        height: auto;
+        display: flex;
+        justify-content: center;
+
+        image {
+          height: 10vh;
+          width: 10vh;
+          border-radius: 50px;
+        }
+      }
+
+      .form-box {
+        width: 100%;
+        margin-top: 20px;
+
+        .input-box {
+          width: 100%;
+          height: 7vh;
+          margin-top: 10px;
+          background: #e07b675e;
+          border-radius: 5px;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          // padding: 0 10px;
+          box-sizing: border-box;
+
+          input {
+            width: 90%;
+            margin: auto;
+            color: #00000093;
+          }
+        }
+
+        .login-btn {
+          width: 100%;
+          height: 8vh;
+          border-radius: 7px;
+          box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.5);
+          background: #e07c67;
+          color: white;
+          font-size: 18px;
+          line-height: 8vh;
+          text-align: center;
+          margin-top: 20px;
+        }
+
+        .others {
+          width: 100%;
+          display: flex;
+          justify-content: space-around;
+          margin-top: 30px;
+
+          view {
+            font-size: 14px;
+            color: #00000056;
+          }
+        }
+      }
+    }
+  }
+
+  .message-box {
+    position: absolute;
+    width: 100vw;
+    top: 0;
+    margin-left: -10px;
+    // margin-top: 80px;
+    background: #00000056;
+    display: flex;
+    justify-content: center;
+    flex-direction: column;
+
+    .pop-box {
+      width: 75%;
+      height: 50%;
+      background: #ffffff;
+      border-radius: 10px;
+      padding: 20px;
+      margin: auto;
+      box-sizing: border-box;
+
+      textarea {
+        width: 100%;
+        height: 80%;
+        background: rgba(240, 239, 239, 0.61);
+        border: 1px rgba(233, 233, 233, 0.623) solid;
+        border-radius: 10px;
+        padding: 10px;
+        box-sizing: border-box;
+        font-size: 14px;
+      }
+
+      .btns {
+        width: 100%;
+        height: 15%;
+        display: flex;
+        justify-content: space-between;
+        margin-top: 20px;
+
+        .btn-item {
+          width: 45%;
+          height: 100%;
+          background: #dda59a;
+          border-radius: 5px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          color: white;
+        }
+      }
+    }
+  }
+
+  .code-box {
+    width: 100%;
+    height: 100%;
+    position: fixed;
+    top: 0;
+    left: 0;
+    background: #00000056;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    z-index: 1;
+
+    image {
+      width: 80%;
+      object-fit: contain;
+    }
+
+    view {
+      color: white;
+      margin-top: 10px;
+    }
+  }
+}
+</style>

+ 596 - 0
小程序/jingtailan/src/pages/mine/index2.vue

@@ -0,0 +1,596 @@
+<script setup lang='ts'>
+import * as baseInfo from '@/api/record';
+import { baseIMGUrl } from '@/api/request'
+import { ref } from 'vue';
+
+import { LogonApi } from '@/api/api/login/index';
+import { MineApi } from '@/api/api/mine/index';
+import { onLoad, onShow } from '@dcloudio/uni-app';
+
+import TabBarTop from '@/components/TabBarTop.vue'
+
+
+const userInfo = ref({} as any)
+const noLogin = ref(true)
+
+const isMessage = ref(false)
+const messageText = ref('')
+const defaultHeadUrl = ref('https://4d-tjw.oss-cn-shenzhen.aliyuncs.com/project/bjfljtl/img/bottomInco/defaultHead.png')
+const botomBGURL = ref(`url(${baseIMGUrl}/img/data/E1Mine/bg.png)`)
+
+const top = uni.getMenuButtonBoundingClientRect().top;
+const height = uni.getMenuButtonBoundingClientRect().height;
+
+// 提交留言信息
+const submitMessage = async () => {
+  if (messageText.value.length < 5 || messageText.value.length > 200) {
+    uni.showToast({
+      title: '请输入5-200字!',
+      icon: 'none'
+    })
+  } else {
+    const res: any = await MineApi.submitMeg(messageText.value, userInfo.value.nickName)
+    if (res.data.code === 0) {
+      isMessage.value = false;
+      uni.showToast({
+        title: '留言成功'
+      })
+
+    }
+  }
+}
+
+const others = [
+  {
+    name: '大众点评',
+    icon: 'https://hbimg.b0.upaiyun.com/2736424c8c107adaf0917de571b2dfb48b76555514d3d-gUTXtZ_fw658',
+    appid: 'wx734c1ad7b3562129',
+    path: 'packages/trip/mpvue-pages/pages/poi/poi?poiId=FnKeGux84asrPKr6&shopuuid=FnKeGux84asrPKr6&mode=subpackage&from=list'
+  },
+  {
+    name: '携程',
+    icon: 'https://down.51rc.com/imagefolder/Logo/L11040000/11037518_b20190326102751.gif',
+    appid: 'wx0e6ed4f51db9d078',
+    path: 'pages/gs/sight/newDetail?sightId=1487166&fcpGUID=fcp_navigateTo_5&pubRouteBegin=1688348640703'
+  }
+]
+
+const contentTotleNum = ref(0)
+const antiqueTotleNum = ref(0)
+
+// 获取文物收藏totle数
+const antiqueTotle = async () => {
+  const res: any = await MineApi.getGoodstList(PageListInfo.value)
+  if (res.data.code === 0) {
+    antiqueTotleNum.value = res.data.data.total
+  } else {
+    uni.showToast({
+      title: res.data.msg,
+      icon: 'none'
+    })
+  }
+}
+
+// 获取内容收藏totle数
+const contentTotle = async () => {
+  const res: any = await MineApi.getContentList(PageListInfo)
+  if (res.data.code === 0) {
+    contentTotleNum.value = res.data.data.total;
+  } else {
+    uni.showToast({
+      title: res.data.msg,
+      icon: 'none'
+    })
+  }
+}
+
+
+const goTo = async (path: String) => {
+  const ress: any = await MineApi.checkToken();
+  if (ress.data.data) {
+    uni.navigateTo({
+      url: path
+    })
+  } else {
+    console.log('输出mine')
+
+    uni.showToast({
+      title: '身份过期,请重新登录',
+      icon: 'none'
+    })
+    uni.removeStorage({
+      key: 'JTL_token'
+    })
+    uni.removeStorage({
+      key: 'JTL_userInfo'
+    })
+    setTimeout(() => {
+      uni.reLaunch({
+        url: '/pages/mine/index'
+      })
+    }, 1000)
+  }
+
+}
+const goToMini = (app: String, path: String) => {
+  console.log(path)
+  uni.navigateToMiniProgram({
+    appId: app,
+    path: path
+  })
+}
+// 打开微信授权确认框
+const openUserProfile = () => {
+  return new Promise((resolve, reject) => {
+    uni.getUserProfile({
+      lang: 'zh_CN',
+      desc: '获取你的昵称、头像、地区及性别',
+      success: (res) => {
+        resolve(res)
+      },
+      // 失败回调
+      fail: (err) => {
+        reject(err)
+      }
+    })
+  })
+}
+
+// 获得weixin Code
+const getWxCode = () => {
+  return new Promise((resolve, reject) => {
+    uni.login({
+      success(res) {
+        //这里就是code,可以打印看下
+        resolve(res.code)
+      },
+      fail(err) {
+        reject(err)
+      }
+    })
+  })
+
+}
+
+// 用户名和用户头像
+const userNickName = ref('')
+const userHeadUrl = ref('')
+const userInfoData = ref({} as any)
+
+// 授权触发事件
+const wxLogin = () => {
+  if (noLogin.value) {
+    console.log('打开')
+    let p1 = getWxCode();
+    let p2 = openUserProfile();
+    p1.then(code => {
+      return code
+    }).then(code => {
+      return new Promise((resolve, reject) => {
+        p2.then(async (res: any) => {
+          userInfoData.value = res.userInfo
+          // 获得用户名和用户头像
+          userNickName.value = res.userInfo.nickName
+          userHeadUrl.value = res.userInfo.avatarUrl
+          console.log(res)
+          resolve({
+            code,
+            iv: res.iv,
+            encryptedData: res.encryptedData
+          })
+        }).catch(err => {
+          reject(err)
+        })
+      }).then((res: any) => {
+        // 得到code 拉token
+        LogonApi.login(res.code).then((res: any) => {
+          if (res.data.code === 0) {
+            setTimeout(() => {
+              // 更新用户信息
+              MineApi.updateUser({
+                avatarUrl: userInfoData.value.avatarUrl,
+                city: userInfoData.value.city,
+                country: userInfoData.value.country,
+                gender: userInfoData.value.gender ? '女' : '男',
+                nickName: userInfoData.value.nickName,
+                phone: "",
+                province: userInfoData.value.province
+              })
+            }, 1000)
+            // 改为登录状态
+            noLogin.value = false;
+            // 存放token
+            uni.setStorageSync('JTL_token', res.data.data.token);
+            // 存放登录用户信息
+            const dataInfo = res.data.data.wxUser;
+            dataInfo.avatarUrl = userHeadUrl.value;
+            dataInfo.nickName = userNickName.value;
+            uni.setStorageSync('JTL_userInfo', res.data.data.wxUser)
+            checkToken();
+            setTimeout(() => {
+              uni.showToast({
+                title: '授权成功'
+              })
+            }, 300)
+            antiqueTotle();
+            contentTotle();
+          }
+
+        })
+      })
+    })
+  } else {
+    return
+  }
+}
+
+
+// 检查登录缓存
+const checkToken = () => {
+  let token = uni.getStorageSync("JTL_token");
+  let userInfoStorage = uni.getStorageSync("JTL_userInfo");
+  if (userInfoStorage && token) {
+    noLogin.value = false
+    userInfo.value = userInfoStorage;
+    // 默认头像
+    if (userInfoStorage.avatarUrl === '') {
+      userInfo.value.avatarUrl = defaultHeadUrl.value;
+    }
+    // 获取个数
+    antiqueTotle();
+    contentTotle();
+  }
+}
+
+const PageListInfo = ref({
+  pageNum: 1,
+  pageSize: 10,
+  searchKey: '',
+})
+
+
+
+onLoad((option) => {
+  // 自动跳转后自动清除定时器
+  const key = uni.getStorageSync('FIRST_KEY')
+  if (key) {
+    uni.removeStorage({
+      key: 'FIRST_KEY'
+    })
+  }
+  // 判断是否登录
+  // checkToken();
+})
+
+onShow(() => {
+  console.log('触发了')
+})
+</script>
+  
+<template>
+  <view class="all">
+    <!-- <TabBarTop title="我的" color="rgba(0,0,0,0.6)" /> -->
+    <view style="padding-left: 10px; padding-right: 10px; max-height: 100vh; overflow: hidden;">
+      <view class="head" @tap="wxLogin">
+        <image :src="noLogin ? defaultHeadUrl : userInfo.avatarUrl" mode="scaleToFill" />
+        <view class="username">{{ !noLogin ? userInfo.nickName : '请点击登录' }}
+        </view>
+      </view>
+      <view class="content">
+        <view class="content-item" @tap="goTo('culturalRelic/index')">
+          <view class="content-item-left"><span>文物收藏</span>
+            <view v-if="!noLogin">{{ antiqueTotleNum }}</view>
+          </view>
+          <image v-if="!noLogin" :src="baseInfo.baseIMGUrl + '/bottomInco/right.png'" mode="scaleToFill" />
+        </view>
+        <view class="content-item" @tap="goTo('content/index')">
+          <view class="content-item-left"><span>内容收藏</span>
+            <view v-if="!noLogin">{{ contentTotleNum }}</view>
+          </view>
+          <image v-if="!noLogin" :src="baseInfo.baseIMGUrl + '/bottomInco/right.png'" mode="scaleToFill" />
+        </view>
+        <!-- TODO:构想ui -->
+        <view class="content-item" @tap="() => { isMessage = true }">
+          <view>我要留言</view>
+          <view class="content-item-right">
+            <view>
+              填写留言
+            </view>
+            <image :src="baseInfo.baseIMGUrl + '/bottomInco/right.png'" mode="scaleToFill" />
+          </view>
+        </view>
+        <view class="content-item content-last">
+          <view>三方平台评论</view>
+          <view class="others" v-for="item in others" :key="item.name">
+            <image @tap="goToMini(item.appid, item.path)" :src="item.icon" mode="scaleToFill" />
+          </view>
+        </view>
+      </view>
+
+      <!-- 登录界面
+    <view class="login-box" v-if="noLogin">
+      <view class="center">
+        <view class="head">
+          <image :src="userInfo.head" mode="scaleToFill" />
+        </view>
+        <view class="form-box">
+          <view class="input-box">
+            <input placeholder="请输入账号" type="text" v-model="userInfo.username">
+          </view>
+          <view class="input-box">
+            <input placeholder="请输入密码" type="password" v-model="userInfo.password">
+          </view>
+
+          <view class="login-btn">
+            登 录
+          </view>
+          <view class="others">
+            <view>新建账号</view>
+            <view>忘记密码</view>
+          </view>
+        </view>
+      </view>
+    </view> -->
+
+      <!-- 留言弹框 -->
+      <view class="message-box" v-if="isMessage" :style="{ height: `calc(100% + ${top + height}px)` }">
+        <view class="pop-box">
+          <textarea name="message" id="message" v-model="messageText" cols="30" rows="10" placeholder="请输入留言内容,5-200个字"
+            minlength="5" maxlength="200"></textarea>
+          <view class="btns">
+            <view class="btn-item" @tap="() => { isMessage = false; messageText = '' }">取消</view>
+            <view class="btn-item" @tap="submitMessage">确定</view>
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+  
+<style lang='scss' scoped>
+::-webkit-scrollbar {
+  display: none !important;
+}
+
+.all {
+  min-width: 100vw;
+  max-height: 100vh;
+  background: #F7F1E6;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  box-sizing: border-box;
+
+
+  .head {
+    height: 20vh;
+    margin: auto;
+    display: flex;
+    flex-direction: column;
+    justify-content: top;
+
+    .username {
+      color: rgba(0, 0, 0, 0.7);
+      padding-top: 20px;
+    }
+
+    image {
+      height: 10vh;
+      width: 10vh;
+      border-radius: 50px;
+      margin: auto;
+    }
+
+    view {
+      margin: auto;
+      font-weight: bold;
+      text-align: center;
+      margin-top: -10%;
+    }
+  }
+
+  .content {
+    width: 100%;
+    height: 100vh;
+    border-radius: 20px 20px 0 0;
+    box-shadow: 0px -3px 15px 0px rgba(0, 0, 0, 0.3);
+    padding: 30px;
+    box-sizing: border-box;
+    background-size: cover;
+    background-image: url('https://houseoss.4dkankan.com/project/bjfljtl/img/data/E1Mine/bg.png');
+
+
+    &-item {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      height: 10vh;
+      border-bottom: 1px solid rgba(107, 107, 107, 0.192);
+
+      image {
+        width: 20px;
+        height: 20px;
+      }
+
+      &-left {
+        display: flex;
+        justify-content: left;
+        align-items: center;
+
+        view {
+          margin-left: 5vw;
+          height: 20px;
+          width: 20px;
+          border-radius: 50px;
+          background-color: #E07C67;
+          text-align: center;
+          line-height: 20px;
+          color: white;
+          font-size: 26rpx;
+        }
+      }
+
+      &-right {
+        display: flex;
+        justify-content: right;
+
+        view {
+          margin-right: 5px;
+          color: rgba(54, 54, 54, 0.705);
+        }
+      }
+
+    }
+
+    &-last {
+      border-bottom: none;
+      justify-content: left;
+
+      .others {
+        image {
+          width: 5vh;
+          height: 5vh;
+          border-radius: 5px;
+          margin-left: 20px;
+        }
+      }
+    }
+
+  }
+
+  .login-box {
+    position: absolute;
+    width: 100vw;
+    height: 100vh;
+    backdrop-filter: blur(30px);
+    display: flex;
+    justify-content: center;
+    flex-direction: column;
+
+    .center {
+      width: 70%;
+      // background: gold;
+      height: 70%;
+      margin: auto;
+
+      .head {
+        width: 100%;
+        height: auto;
+        display: flex;
+        justify-content: center;
+
+        image {
+          height: 10vh;
+          width: 10vh;
+          border-radius: 50px;
+        }
+      }
+
+      .form-box {
+        width: 100%;
+        margin-top: 20px;
+
+        .input-box {
+          width: 100%;
+          height: 7vh;
+          margin-top: 10px;
+          background: #e07b675e;
+          border-radius: 5px;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          // padding: 0 10px;
+          box-sizing: border-box;
+
+          input {
+            width: 90%;
+            margin: auto;
+            color: #00000093;
+          }
+        }
+
+        .login-btn {
+          width: 100%;
+          height: 8vh;
+          border-radius: 7px;
+          box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.5);
+          background: #E07C67;
+          color: white;
+          font-size: 18px;
+          line-height: 8vh;
+          text-align: center;
+          margin-top: 20px;
+        }
+
+        .others {
+          width: 100%;
+          display: flex;
+          justify-content: space-around;
+          margin-top: 30px;
+
+          view {
+            font-size: 14px;
+            color: #00000056;
+          }
+        }
+
+      }
+
+
+    }
+
+  }
+
+  .message-box {
+    position: absolute;
+    width: 100vw;
+    top: 0;
+    margin-left: -10px;
+    // margin-top: 80px;
+    background: #00000056;
+    display: flex;
+    justify-content: center;
+    flex-direction: column;
+
+    .pop-box {
+      width: 75%;
+      height: 50%;
+      background: #ffffff;
+      border-radius: 10px;
+      padding: 20px;
+      margin: auto;
+      box-sizing: border-box;
+
+      textarea {
+        width: 100%;
+        height: 80%;
+        background: rgba(240, 239, 239, 0.61);
+        border: 1px rgba(233, 233, 233, 0.623) solid;
+        border-radius: 10px;
+        padding: 10px;
+        box-sizing: border-box;
+        font-size: 14px;
+      }
+
+      .btns {
+        width: 100%;
+        height: 15%;
+        display: flex;
+        justify-content: space-between;
+        margin-top: 20px;
+
+        .btn-item {
+          width: 45%;
+          height: 100%;
+          background: #dda59a;
+          border-radius: 5px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          color: white;
+        }
+      }
+    }
+  }
+}
+</style>

+ 182 - 0
小程序/jingtailan/src/pages/mine/perfectInfo/index.vue

@@ -0,0 +1,182 @@
+<script setup lang="ts">
+import { ref } from "vue";
+import { baseUrl, baseIMGUrl } from "@/api/request";
+import { MineApi } from "@/api/api/mine";
+import { onLoad } from "@dcloudio/uni-app";
+
+const avatarUrl = ref(
+  "https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0"
+);
+const nickName = ref("");
+const userAvatarUrl = ref("");
+const userNickNamr = ref("");
+
+const onChooseAvatar = (e: any) => {
+  avatarUrl.value = e.detail.avatarUrl;
+};
+const inputChange = (value: any) => {
+  nickName.value = value.detail.value;
+};
+const getUserInfo = async () => {
+  const res: any = await MineApi.getUserInfo();
+  if (res.data.code === 0) {
+    console.log(res.data.data.avatarUrl.indexOf("http"));
+    avatarUrl.value =
+      res.data.data.avatarUrl.indexOf("http") === "-1"
+        ? baseIMGUrl + res.data.data.avatarUrl
+        : res.data.data.avatarUrl;
+    userAvatarUrl.value =
+      res.data.data.avatarUrl.indexOf("http") === "-1"
+        ? baseIMGUrl + res.data.data.avatarUrl
+        : res.data.data.avatarUrl;
+    nickName.value = res.data.data.nickName;
+    userNickNamr.value = res.data.data.nickName;
+    console.log(nickName.value);
+  }
+};
+
+// 不改变头像的所有情况
+const userUpdate = () => {
+  // setTimeout(() => {
+  //   console.log(avatarUrl.value, nickName.value, userAvatarUrl.value);
+  // });
+  MineApi.updateUser({
+    avatarUrl: userAvatarUrl.value,
+    nickName: nickName.value,
+  }).then((resss: any) => {
+    if (resss.data.code === 0) {
+      uni.showToast({
+        title: "修改成功",
+      });
+      setTimeout(async () => {
+        uni.navigateBack();
+      }, 200);
+    } else {
+      uni.showToast({
+        title: resss.data.msg,
+      });
+    }
+  });
+};
+
+// 确定上传头像
+const uploadHead = () => {
+  let token = uni.getStorageSync("JTL_token");
+  // 改变了头像
+  if (avatarUrl.value != userAvatarUrl.value) {
+    uni.uploadFile({
+      url: baseUrl + "/cms/goods/upload",
+      fileType: "image",
+      filePath: avatarUrl.value,
+      name: "file",
+      formData: {
+        type: "img",
+      },
+      header: {
+        // 根据实际接口设计 key 取 token 或者 authorization
+        token: token,
+        "Content-Type": "application/json",
+      },
+      success: (res) => {
+        const ress = JSON.parse(res.data);
+        MineApi.updateUser({
+          avatarUrl: baseIMGUrl + ress.data.filePath,
+          nickName: nickName.value,
+        }).then((resss: any) => {
+          if (resss.data.code === 0) {
+            uni.showToast({
+              title: "修改成功",
+            });
+            setTimeout(async () => {
+              uni.navigateBack();
+            }, 200);
+          } else {
+            uni.showToast({
+              title: resss.data.msg,
+            });
+          }
+        });
+      },
+      fail: (error) => {
+        uni.showToast({
+          title: "设置失败,请重试!",
+        });
+      },
+    });
+  } else {
+    userUpdate();
+  }
+};
+
+onLoad(() => {
+  getUserInfo();
+});
+</script>
+
+<template>
+  <view class="all">
+    <button
+      class="avatar-wrapper"
+      open-type="chooseAvatar"
+      @chooseavatar="onChooseAvatar"
+    >
+      <image class="avatar" @error="() => {
+        avatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
+      }" :src="avatarUrl"></image>
+    </button>
+    <div class="nickName-box">
+      <label>昵称</label
+      ><input
+        type="nickname"
+        class="weui-input"
+        placeholder="请输入昵称"
+        @change="inputChange"
+        :value="nickName"
+      />
+    </div>
+
+    <button class="submit-box" @tap="uploadHead">提交</button>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.all {
+  width: 100vw;
+  height: 100vh;
+  background: #f7f1e6;
+
+  button {
+    width: 20vw;
+    height: 20vw;
+    padding: 0;
+
+    image {
+      width: 100%;
+      height: 100%;
+    }
+  }
+
+  .nickName-box {
+    margin-top: 20px;
+    padding: 20px;
+    display: flex;
+    border-top: 1px solid rgba(221, 221, 221, 0.562);
+    border-bottom: 1px solid rgba(221, 221, 221, 0.562);
+
+    label {
+      // color: gray;
+      margin-right: 40px;
+    }
+  }
+
+  .submit-box {
+    width: 90%;
+    height: 50px;
+    background: #e07c67;
+    color: white;
+    font-size: 36rpx;
+    line-height: 50px;
+    margin-top: 20px;
+  }
+}
+</style>

+ 47 - 0
小程序/jingtailan/src/pages/visit/exhibition/index.vue

@@ -0,0 +1,47 @@
+<script setup lang="ts">
+import { onLoad } from "@dcloudio/uni-app";
+import commonn from "@/static/data/common";
+import { onUnmounted, ref } from "vue";
+const path = ref("");
+const musicStaRe = ref(false)
+
+const playAudio = (id: string) => {
+
+  musicStaRe.value = commonn.musicSta
+  if (musicStaRe.value) {
+    console.log(musicStaRe.value)
+    // 先暂停背景音频
+    commonn.innerAudioContext.pause()
+    commonn.musicSta = false
+  }
+  setTimeout(() => {
+    commonn.introAudioContext.src = `https://houseoss.4dkankan.com/project/bjfljtl/audio/scene/${id == 'KJ-IKOTxwolNJ' ? '' : 'other'}.mp3`
+    console.log(commonn.introAudioContext.src)
+    commonn.introAudioContext.currentTime = 0
+    commonn.introAudioContext.play()
+  },5000)
+}
+onLoad((option) => {
+  console.log(option!.id);
+  path.value = `https://houseoss.4dkankan.com/project/bjfljtl/scene/index.html?m=${option!.id}`
+  // path.value = `https://www.4dmodel.com/SuperTwo/index.html?m=TEST`
+  playAudio(option!.id)
+
+});
+
+onUnmounted(() => {
+  if (musicStaRe.value) {
+    commonn.innerAudioContext.play()
+    commonn.musicSta = true
+  }
+  commonn.introAudioContext.pause()
+})
+</script>
+
+<template>
+  <div class="">
+    <web-view :src="path" />
+  </div>
+</template>
+
+<style lang="less" scoped></style>

文件差异内容过多而无法显示
+ 1751 - 0
小程序/jingtailan/src/pages/visit/guide/index copy 2.vue


+ 47 - 0
小程序/jingtailan/src/pages/visit/guide/index copy.vue

@@ -0,0 +1,47 @@
+<script setup lang='ts'>
+import commonn from "@/static/data/common";
+import { onMounted, onUnmounted, ref } from "vue";
+
+declare global {
+  interface Window {
+    // 停止简介音频
+    musicStop: (v: boolean) => void
+  }
+}
+
+const musicStaRe = ref(false)
+
+const playAudio = () => {
+  musicStaRe.value = commonn.musicSta
+  if (musicStaRe.value) {
+    console.log(musicStaRe.value)
+    // 先暂停背景音频
+    commonn.innerAudioContext.pause()
+    commonn.musicSta = false
+  }
+  // commonn.introAudioContext.src = 'https://houseoss.4dkankan.com/project/bjfljtl/audio/data/C1Visit/企业简介.mp3'
+  // commonn.introAudioContext.play()
+}
+
+const messageData = (e:any) => {
+  console.log(JSON.stringify(e.detail))
+}
+
+onMounted(() => {
+  playAudio()
+})
+
+onUnmounted(() => {
+  if (musicStaRe.value) {
+    commonn.innerAudioContext.play()
+    commonn.musicSta = true
+  }
+  commonn.introAudioContext.pause()
+})
+</script>
+  
+<template>
+  <web-view @message="messageData" :src="`https://houseoss.4dkankan.com/project/bjfljtl/guildsvg/svg.html?t=${new Date().getTime()}`" :fullscreen="false" />
+</template>
+  
+<style lang='scss' scoped></style>

+ 47 - 0
小程序/jingtailan/src/pages/visit/guide/index.vue

@@ -0,0 +1,47 @@
+<script setup lang='ts'>
+import commonn from "@/static/data/common";
+import { onMounted, onUnmounted, ref } from "vue";
+
+declare global {
+  interface Window {
+    // 停止简介音频
+    musicStop: (v: boolean) => void
+  }
+}
+
+const musicStaRe = ref(false)
+
+const playAudio = () => {
+  musicStaRe.value = commonn.musicSta
+  if (musicStaRe.value) {
+    console.log(musicStaRe.value)
+    // 先暂停背景音频
+    commonn.innerAudioContext.pause()
+    commonn.musicSta = false
+  }
+  // commonn.introAudioContext.src = 'https://houseoss.4dkankan.com/project/bjfljtl/audio/data/C1Visit/企业简介.mp3'
+  // commonn.introAudioContext.play()
+}
+
+const messageData = (e:any) => {
+  console.log(JSON.stringify(e.detail))
+}
+
+onMounted(() => {
+  playAudio()
+})
+
+onUnmounted(() => {
+  if (musicStaRe.value) {
+    commonn.innerAudioContext.play()
+    commonn.musicSta = true
+  }
+  commonn.introAudioContext.pause()
+})
+</script>
+  
+<template>
+  <web-view @message="messageData" :src="`https://houseoss.4dkankan.com/project/bjfljtl/guildsvg/svg.html?t=${new Date().getTime()}`" :fullscreen="false" />
+</template>
+  
+<style lang='scss' scoped></style>

+ 394 - 0
小程序/jingtailan/src/pages/visit/history/index.vue

@@ -0,0 +1,394 @@
+<script setup lang="ts">
+import * as baseInfo from "@/api/record";
+import { baseIMGUrl } from "@/api/request";
+import { onLoad, onReachBottom } from "@dcloudio/uni-app";
+import { ref } from "vue";
+import TabBarTop from "@/components/TabBarTop.vue";
+import { VisitApi } from "@/api/api/visit";
+
+const curIndex = ref(0);
+const historys = ref([] as any);
+
+const changeIndex = async (newIndex: number) => {
+  curIndex.value = newIndex;
+  // 非公司简介
+  if (newIndex != 0 && !newHistorys.value[newIndex].detail) {
+    console.log(newHistorys.value[newIndex]);
+    const res: any = await VisitApi.getLogsList(newHistorys.value[newIndex].id);
+    if (res.data.code == 0) {
+      // 存进newHistorys中
+      Reflect.set(newHistorys.value[newIndex], "detail", res.data.data);
+    }
+  }
+  console.log(newHistorys.value);
+};
+
+const top = uni.getMenuButtonBoundingClientRect().top;
+const height = uni.getMenuButtonBoundingClientRect().height;
+
+// 页面滑动到底部,跳转到下一个
+// onReachBottom(async () => {
+//   console.log("ppp");
+//   if (!newHistorys.value[curIndex.value + 1].detail) {
+//     const res: any = await VisitApi.getLogsList(
+//       newHistorys.value[curIndex.value + 1].id
+//     );
+//     if (res.data.code == 0) {
+//       // 存进newHistorys中
+//       Reflect.set(
+//         newHistorys.value[curIndex.value + 1],
+//         "detail",
+//         res.data.data
+//       );
+//     }
+//   }
+//   setTimeout(() => {
+//     curIndex.value = curIndex.value + 1;
+//     uni.pageScrollTo({ scrollTop: 0, duration: 300 });
+//   }, 500);
+// });
+
+onLoad(async () => {
+  const data = await getData();
+  getDataFromAPI();
+  historys.value = data;
+});
+
+const newHistorys = ref([] as any);
+
+// 获得公司简介,加入到json结构中
+const getCompanyDetail = async () => {
+  const resProfile: any = await VisitApi.getCompanyProfile();
+  if (resProfile.data.code == 0) {
+    newHistorys.value.push({
+      name: "公司简介",
+      detail: [
+        {
+          content: resProfile.data.data.entity.content,
+          image: resProfile.data.data.file,
+          name: resProfile.data.data.entity.name,
+          video: resProfile.data.data.entity.video,
+          videoName: resProfile.data.data.entity.videoName,
+          type: resProfile.data.data.entity.type,
+        },
+      ],
+    });
+    console.log(newHistorys.value);
+  }
+};
+
+// 获取年代专题
+const getChronology = async () => {
+  const res: any = await VisitApi.getChronology();
+  if (res.data.code == 0) {
+    res.data.data.forEach((item: any) => {
+      newHistorys.value.push({
+        ...item,
+      });
+    });
+  }
+};
+
+const getDataFromAPI = () => {
+  getCompanyDetail();
+  setTimeout(() => {
+    getChronology();
+  }, 50);
+};
+
+// 阿拉伯数字转换成中文数字
+const fontChange = (dateStr: string) => {
+  var dict = {
+    "0": "零",
+    "1": "一",
+    "2": "二",
+    "3": "三",
+    "4": "四",
+    "5": "五",
+    "6": "六",
+    "7": "七",
+    "8": "八",
+    "9": "九",
+    "10": "十",
+    "11": "十一",
+    "12": "十二",
+    "13": "十三",
+    "14": "十四",
+    "15": "十五",
+    "16": "十六",
+    "17": "十七",
+    "18": "十八",
+    "19": "十九",
+    "20": "二十",
+    "21": "二十一",
+    "22": "二十二",
+    "23": "二十三",
+    "24": "二十四",
+    "25": "二十五",
+    "26": "二十六",
+    "27": "二十七",
+    "28": "二十八",
+    "29": "二十九",
+    "30": "三十",
+    "31": "三十一",
+  };
+  var date = dateStr.split("-"),
+    yy = date[0],
+    mm = date[1],
+    dd = date[2];
+
+  console.log(yy, mm, dd);
+
+  var yearStr = dict[yy[0]] + dict[yy[1]] + dict[yy[2]] + dict[yy[3]] + "年",
+    monthStr = mm ? dict["" + Number(mm)] + "月" : "",
+    dayStr = dd ? dict["" + Number(dd)] + "月" : "";
+
+  return yearStr + monthStr + dayStr;
+};
+
+// json文件中拿数据
+const getData = () => {
+  return new Promise((resolve, reject) => {
+    uni.request({
+      url: "https://houseoss.4dkankan.com/project/bjfljtl/history.json",
+      data: {},
+      header: {
+        Accept: "application/json",
+        "Content-Type": "application/json",
+        "X-Requested-With": "XMLHttpRequest",
+      },
+      method: "GET",
+      sslVerify: true,
+      success: ({ data, statusCode, header }) => {
+        resolve(data);
+      },
+      fail: (err) => {
+        console.log(err);
+        uni.showToast({
+          title: "数据获取失败" + JSON.stringify(err),
+          icon: "none",
+          duration: 10000,
+        });
+        reject(err);
+      },
+    });
+  });
+};
+
+// 图片单张预览
+const previewImg = (previewImgUrl: String) => {
+  let imgsArray = [];
+  //根据api拼接
+  imgsArray[0] = baseIMGUrl + previewImgUrl;
+  uni.previewImage({
+    current: 0,
+    urls: imgsArray,
+    showmenu: false
+  });
+};
+</script>
+
+<template>
+  <view class="all" :style="{ paddingTop: top + height + 10 + 'px' }">
+    <TabBarTop
+      title="企业回顾"
+      :isBack="true"
+      backColor="black"
+      color="rgba(0,0,0,0.6)"
+      :site="'left'"
+    />
+    <view class="options-box">
+      <view
+        @tap="changeIndex(index)"
+        class="options-item"
+        :style="{
+          background:
+            index === curIndex ? '#E07C67' : 'rgba(224, 124, 103, 0.46',
+          boxShadow:
+            index === curIndex
+              ? '0px 2px 4px 0px rgba(0,0,0,0.8)'
+              : '0px 2px 4px 0px rgba(0,0,0,0.3)',
+          color:
+            index === curIndex ? 'rgba(255,255,255,0.8)' : 'rgba(0, 0, 0, 0.8)',
+        }"
+        v-for="(item, index) in newHistorys"
+        :key="index"
+        >{{ item.name }}</view
+      >
+    </view>
+    <view class="history-box" v-if="newHistorys.length !== 0">
+      <view v-if="curIndex === 0" class="history-box-info">
+        <view class="title">
+          {{ newHistorys[curIndex].name }}
+        </view>
+        <view
+          class="box-item"
+          v-for="(item, index) in newHistorys[curIndex].detail"
+          :key="index"
+        >
+          <view class="box-item-text">
+            {{ item.content }}
+          </view>
+          <view v-if="item.image.length != 0">
+            <image
+              :src="baseIMGUrl + img.filePath"
+              mode="widthFix"
+              v-for="(img, index) in item.image"
+              :key="index"
+              @tap="previewImg(img.filePath)"
+            />
+          </view>
+        </view>
+      </view>
+      <view v-else class="history-box-chronicles">
+        <view v-if="newHistorys[curIndex].detail.length === 0">暂无历史</view>
+        <view
+          v-for="(item, index) in newHistorys[curIndex].detail"
+          :key="index"
+        >
+          <view class="top">
+            <view class="top-point"></view>
+            <view class="top-text">{{ fontChange(item.date) }}</view>
+          </view>
+          <view class="content">
+            <view class="content-text">{{ item.content }}</view>
+            <image
+              v-if="item.image !== ''"
+              :src="baseIMGUrl + item.thumb"
+              mode="widthFix"
+              @tap="previewImg(item.thumb)"
+            />
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.all {
+  width: 100vw;
+  background-color: #f7f1e6;
+  background-image: url("https://houseoss.4dkankan.com/project/bjfljtl/img/data/C1Visit/history/bg.png");
+  background-size: cover;
+
+  ::-webkit-scrollbar {
+    display: none !important;
+  }
+
+  .options-box {
+    height: 40px;
+    white-space: nowrap;
+    overflow-x: auto;
+    // overflow-y: hidden;
+
+    // ::-webkit-scrollbar {
+    //   display: none !important;
+    // }
+
+    .options-item {
+      margin-left: 10px;
+      display: inline-block;
+      width: 85px;
+      height: 30px;
+      float: none;
+      font-size: 26rpx;
+      line-height: 30px;
+      text-align: center;
+      background-color: rgba(224, 124, 103, 0.46);
+      border-radius: 5px;
+      box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.3);
+      color: rgba(0, 0, 0, 0.8);
+      font-weight: bold;
+    }
+  }
+
+  .history-box {
+    width: 100%;
+    min-height: calc(100vh - 50px);
+    margin-top: 20px;
+    border-radius: 30px 30px 0 0;
+    box-shadow: 0px -4px 4px 0px rgba(0, 0, 0, 0.4);
+    box-sizing: border-box;
+    padding: 40px 40px 20px 40px;
+    background-color: #f7f1e6;
+
+    &-info {
+      .title {
+        width: 100%;
+        text-align: center;
+        font-size: 20px;
+        font-weight: bold;
+        color: #cc4b10;
+        line-height: 23px;
+      }
+
+      .box-item {
+        margin-top: 20px;
+
+        &-text {
+          font-size: 14px;
+          line-height: 20px;
+          margin-bottom: 10px;
+          color: #000000e0;
+          white-space: pre-wrap;
+        }
+
+        image {
+          width: 100%;
+        }
+      }
+    }
+
+    &-chronicles {
+      .top {
+        min-width: 100%;
+        display: flex;
+        justify-content: left;
+        align-content: center;
+        flex-wrap: nowrap;
+        position: relative;
+
+        &-point {
+          width: 10px;
+          height: 10px;
+          border-radius: 50px;
+          background: #d9d9d9;
+          border: 1px solid rgba(0, 0, 0, 0.4);
+          position: absolute;
+
+          left: -5px;
+          top: 6px;
+        }
+
+        &-text {
+          font-size: 20px;
+          font-weight: bold;
+          color: #cc4b10;
+          margin-left: 20px;
+        }
+      }
+
+      .content {
+        border-left: 1px #0000004b solid;
+        padding: 10px 0px 20px 20px;
+        box-sizing: border-box;
+
+        &-text {
+          font-size: 10px;
+          font-family: "KaiTi-Regular";
+          color: #000000a8;
+          line-height: 20px;
+          white-space: pre-wrap;
+          margin-bottom: 10px;
+          // whiteSpace: 'pre-wrap'
+        }
+
+        image {
+          width: 100%;
+        }
+      }
+    }
+  }
+}
+</style>

+ 243 - 0
小程序/jingtailan/src/pages/visit/index.vue

@@ -0,0 +1,243 @@
+<script setup lang="ts">
+import * as baseInfo from "@/api/record";
+import { onLoad, onShow } from "@dcloudio/uni-app";
+import { ref } from "vue";
+import TabBar from "@/components/TabBar.vue";
+import TabBarTopHome from "@/components/TabBarTopHome.vue";
+
+
+
+const BGList = [
+  {
+    image: baseInfo.baseIMGUrl + "/data/C1Visit/home/1.png",
+    path: "guide/index",
+  },
+  { image: baseInfo.baseIMGUrl + "/data/C1Visit/home/2.png", path: "" },
+  {
+    image: baseInfo.baseIMGUrl + "/data/C1Visit/home/3.png",
+    path: "history/index",
+  },
+];
+
+const exhibitions = [
+  {
+    name: "中国景泰蓝艺术博物馆",
+    image: baseInfo.baseIMGUrl + "/data/C1Visit/home/exhibition1.png",
+    link: "KJ-IKOTxwolNJ",
+  },
+  {
+    name: "京珐艺苑精品销售厅1",
+    image: baseInfo.baseIMGUrl + "/data/C1Visit/home/exhibition2.png",
+    link: "KJ-V5dvJZlK8y",
+  },
+  {
+    name: "京珐艺苑精品销售厅2",
+    image: baseInfo.baseIMGUrl + "/data/C1Visit/home/exhibition3.png",
+    link: "KJ-ia3JD7zdtr",
+  },
+];
+
+const goTo = (path: String) => {
+  if (path === "") {
+    uni.showToast({
+      title: "敬请期待",
+      icon: "none",
+    });
+    return;
+  }
+  uni.navigateTo({
+    url: path,
+  });
+};
+
+const goExhibition = (pathId: string) => {
+  uni.navigateTo({
+    url: `./exhibition/index?id=${pathId}`,
+  });
+};
+
+onLoad(() => {
+  // 自动跳转后自动清除定时器
+  const key = uni.getStorageSync("FIRST_KEY");
+  if (key) {
+    uni.removeStorage({
+      key: "FIRST_KEY",
+    });
+  }
+});
+const page = ref('')
+onShow(() => {
+  page.value = '/pages/visit/index'
+})
+</script>
+
+<template>
+  <view class="all">
+    <TabBarTopHome title="游览" />
+    <view class="content-box">
+      <!-- <TabBarTop title="游览" color="rgba(0,0,0,0.6)" /> -->
+      <div class="image-top" :style="{
+        boxShadow: '0px 2px 4px 0px rgba(0, 0, 0, 0.4)',
+        backgroundImage: `url(${BGList[0].image})`,
+      }" @tap="goTo(BGList[0].path)">
+        <!-- <img src="https://houseoss.4dkankan.com/project/bjfljtl/img/data/C1Visit/home/11.png" alt=""> -->
+        <view class="title">游线导览入口</view>
+      </div>
+
+      <div class="image-center">
+        <div class="exhibition-item" v-for="item in exhibitions" :key="item.name"
+          :style="{ backgroundImage: `url(${item.image})` }" @tap="goExhibition(item.link)">
+          <view class="title">{{ item.name }}</view>
+        </div>
+      </div>
+
+      <div class="image-top" :style="{
+        boxShadow: '0px 2px 4px 0px rgba(0, 0, 0, 0.4)',
+        backgroundImage: `url(${BGList[2].image})`,
+      }" @tap="goTo(BGList[2].path)">
+        <view class="title">企业回顾</view>
+      </div>
+    </view>
+    <TabBar :page="page" />
+  </view>
+</template>
+
+<style lang="scss" scoped>
+::-webkit-scrollbar {
+  display: none !important;
+}
+
+.all {
+  width: 100vw;
+  height: calc(100vh - 150rpx);
+  padding-bottom: 20px;
+  box-sizing: border-box;
+  background: #f7f1e6;
+  padding-top: 12vh;
+
+  .content-box {
+    padding: 0 10px;
+    width: 100vw;
+    height: 100%;
+    box-sizing: border-box;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+  }
+}
+
+.image-top {
+  width: 100%;
+  height: 31%;
+  margin-bottom: 20rpx;
+  box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.4);
+  border-radius: 8px;
+  background-size: cover;
+  position: relative;
+
+  .title {
+    width: 50%;
+    height: 30%;
+    margin-bottom: 0;
+    position: absolute;
+    background-image: linear-gradient(to right, rgba(0, 0, 0, 0.616), rgba(0, 0, 0, 0), );
+    top: 50%;
+    transform: translateY(-20%);
+    animation-name: fadenum;
+    animation-duration: 1.5s;
+    animation-iteration-count: infinite;
+    animation-direction: alternate;
+    color: white;
+    font-size: 1.3em;
+    font-weight: bold;
+    letter-spacing: 2px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    // text-shadow:  2px 2px 5px rgba(212, 16, 16, 0.5);
+  }
+
+  // @keyframes fadenum {
+  //   from {
+  //     text-shadow:  2px 2px 10px rgba(255, 255, 255, 0.774);
+  //   }
+
+  //   to {
+  //     text-shadow:  2px 2px 10px rgba(255, 255, 255, 0.527);
+  //   }
+  // }
+
+  @keyframes fadenum {
+    from {
+      box-shadow: 0 0 10px 10px rgba(255, 255, 255, 0.856);
+    }
+
+    to {
+      box-shadow: 0 0 5px 5px rgba(255, 255, 255, 0.733);
+    }
+  }
+
+
+
+  // image {
+  //   width: 45%;
+  //   height: 30%;
+  //   margin-bottom: 0;
+  //   position: absolute;
+  //   top: 50%;
+  //   transform: translateY(-20%);
+  //   animation-name: fadenum;
+  //   animation-duration: 2s;
+  //   animation-iteration-count: infinite;
+  //   animation-direction: alternate;
+  // }
+
+
+
+}
+
+.image-center {
+  width: 100%;
+  height: 31%;
+  border-radius: 8px;
+  display: flex;
+  justify-content: space-between;
+
+  .exhibition-item {
+    width: 33.5%;
+    height: 100%;
+    position: relative;
+    background-size: 100% 100%;
+    overflow-x: hidden;
+    white-space: nowrap;
+
+    .title {
+      width: 100%;
+      padding: 5px;
+      box-sizing: border-box;
+      font-size: 0.7rem;
+      color: #ffffff;
+      position: absolute;
+      top: 83%;
+      display: inline-block;
+      animation: 5s wordsLoop-1e99bd5b linear infinite normal;
+    }
+
+    @keyframes wordsLoop-1e99bd5b {
+      0% {
+        transform: translateX(100%);
+      }
+
+      100% {
+        transform: translateX(-100%);
+      }
+    }
+  }
+}
+
+image {
+  width: 100%;
+  height: 31%;
+  margin-bottom: 16rpx;
+}
+</style>

+ 6 - 0
小程序/jingtailan/src/shime-uni.d.ts

@@ -0,0 +1,6 @@
+export {}
+
+declare module "vue" {
+  type Hooks = App.AppInstance & Page.PageInstance;
+  interface ComponentCustomOptions extends Hooks {}
+}

+ 10 - 0
小程序/jingtailan/src/static/data/common.ts

@@ -0,0 +1,10 @@
+// 背景音频
+const innerAudioContext = uni.createInnerAudioContext();
+// 介绍音频
+const introAudioContext = uni.createInnerAudioContext();
+const musicSta = false;
+export default {
+  innerAudioContext,
+  musicSta,
+  introAudioContext,
+};

二进制
小程序/jingtailan/src/static/img/bottomInco/back1.png


二进制
小程序/jingtailan/src/static/img/bottomInco/back2.png


文件差异内容过多而无法显示
+ 1 - 0
小程序/jingtailan/src/static/img/bottomInco/gride.svg


二进制
小程序/jingtailan/src/static/img/bottomInco/inco1.png


二进制
小程序/jingtailan/src/static/img/bottomInco/inco1Ac.png


二进制
小程序/jingtailan/src/static/img/bottomInco/inco2.png


二进制
小程序/jingtailan/src/static/img/bottomInco/inco2Ac.png


二进制
小程序/jingtailan/src/static/img/bottomInco/inco3.png


二进制
小程序/jingtailan/src/static/img/bottomInco/inco3Ac.png


二进制
小程序/jingtailan/src/static/img/bottomInco/inco4.png


二进制
小程序/jingtailan/src/static/img/bottomInco/inco4Ac.png


二进制
小程序/jingtailan/src/static/img/bottomInco/inco5.png


二进制
小程序/jingtailan/src/static/img/bottomInco/inco5Ac.png


二进制
小程序/jingtailan/src/static/img/bottomInco/music.png


二进制
小程序/jingtailan/src/static/img/bottomInco/musicAc.png


二进制
小程序/jingtailan/src/static/img/bottomInco/right.png


二进制
小程序/jingtailan/src/static/img/bottomInco/title-logo.png


+ 4 - 0
小程序/jingtailan/src/types/declaration.d.ts

@@ -0,0 +1,4 @@
+declare module "*.scss";
+declare module "*.png";
+declare module "*.jpg";
+declare module "*.gif";

+ 2 - 0
小程序/jingtailan/src/types/index.d.ts

@@ -0,0 +1,2 @@
+
+

+ 1 - 0
小程序/jingtailan/src/types/store/Mine.d.ts

@@ -0,0 +1 @@
+

+ 76 - 0
小程序/jingtailan/src/uni.scss

@@ -0,0 +1,76 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+
+/* 颜色变量 */
+
+/* 行为相关颜色 */
+$uni-color-primary: #007aff;
+$uni-color-success: #4cd964;
+$uni-color-warning: #f0ad4e;
+$uni-color-error: #dd524d;
+
+/* 文字基本颜色 */
+$uni-text-color: #333; // 基本色
+$uni-text-color-inverse: #fff; // 反色
+$uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息
+$uni-text-color-placeholder: #808080;
+$uni-text-color-disable: #c0c0c0;
+
+/* 背景颜色 */
+$uni-bg-color: #fff;
+$uni-bg-color-grey: #f8f8f8;
+$uni-bg-color-hover: #f1f1f1; // 点击状态颜色
+$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色
+
+/* 边框颜色 */
+$uni-border-color: #c8c7cc;
+
+/* 尺寸变量 */
+
+/* 文字尺寸 */
+$uni-font-size-sm: 12px;
+$uni-font-size-base: 14px;
+$uni-font-size-lg: 16px;
+
+/* 图片尺寸 */
+$uni-img-size-sm: 20px;
+$uni-img-size-base: 26px;
+$uni-img-size-lg: 40px;
+
+/* Border Radius */
+$uni-border-radius-sm: 2px;
+$uni-border-radius-base: 3px;
+$uni-border-radius-lg: 6px;
+$uni-border-radius-circle: 50%;
+
+/* 水平间距 */
+$uni-spacing-row-sm: 5px;
+$uni-spacing-row-base: 10px;
+$uni-spacing-row-lg: 15px;
+
+/* 垂直间距 */
+$uni-spacing-col-sm: 4px;
+$uni-spacing-col-base: 8px;
+$uni-spacing-col-lg: 12px;
+
+/* 透明度 */
+$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
+
+/* 文章场景相关 */
+$uni-color-title: #2c405a; // 文章标题颜色
+$uni-font-size-title: 20px;
+$uni-color-subtitle: #555; // 二级标题颜色
+$uni-font-size-subtitle: 18px;
+$uni-color-paragraph: #3f536e; // 文章段落颜色
+$uni-font-size-paragraph: 15px;

+ 90 - 0
小程序/jingtailan/src/util/index.ts

@@ -0,0 +1,90 @@
+import { LogonApi } from "@/api/api/login";
+
+// 检查userInfo缓存
+export function checkLoginStatus() {
+  let userInfo =  uni.getStorageSync("JTL_userInfo");
+  if (userInfo) {
+    let nowTime = Date.now();
+    let data = JSON.parse(userInfo);
+    // 超过了6个小时
+    if (nowTime - data.time >= 1000 * 60 * 60 * 6) {
+      return false;
+    } else {
+      return true;
+    }
+  } else {
+    return false;
+  }
+}
+
+
+// 授权登录
+// 打开微信授权确认框
+export function openUserProfile() {
+  return new Promise((resolve, reject) => {
+    uni.getUserProfile({
+      lang: 'zh_CN',
+      desc: '获取你的昵称、头像、地区及性别',
+      success: (res) => {
+        resolve(res)
+      },
+      // 失败回调
+      fail: (err) => {
+        reject(err)
+      }
+    })
+  })
+}
+
+// 获得weixin Code
+export function getWxCode() {
+  return new Promise((resolve, reject) => {
+    uni.login({
+      success(res) {
+        //这里就是code,可以打印看下
+        resolve(res.code)
+      },
+      fail(err) {
+        reject(err)
+      }
+    })
+  })
+
+}
+
+// 授权触发事件
+export function wxLogin () {
+  let p1 = getWxCode();
+  let p2 = openUserProfile();
+  p1.then(code => {
+    return code
+  }).then(code => {
+    return new Promise((resolve, reject) => {
+      p2.then((res: any) => {
+        resolve({
+          code,
+          iv: res.iv,
+          encryptedData: res.encryptedData
+        })
+      }).catch(err => {
+        reject(err)
+      })
+    }).then((res: any) => {
+      // 得到code 拉token
+      LogonApi.login(res.code).then((res: any) => {
+        if (res.data.code === 0) {
+          // 存放token
+          uni.setStorageSync('JTL_token', res.data.data.token);
+          // 存放登录用户信息
+          uni.setStorageSync('JTL_userInfo', res.data.data.wxUser)
+          setTimeout(() => {
+            uni.showToast({
+              title: '授权成功'
+            })
+          }, 300)
+        }
+      })
+    })
+  })
+}
+

+ 0 - 0
小程序/jingtailan/tsconfig.json


部分文件因为文件数量过多而无法显示