杨磊
2 天以前 87d2fac9c381de99f75ce6c6c39b7d638b980d7e
1111
20个文件已删除
17个文件已添加
11个文件已修改
3970 ■■■■■ 已修改文件
package-lock.json 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/book-cover.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/bookStore/feblei.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/default-book-img.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/default_avatar.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/delete.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/header/dialogLeftImg.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/index/bookListBg.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/login/boxBg.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/login/pageBg.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/login/weChartIcon.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/packDown.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/packUp.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/pageHeader/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/personalCenter/choose.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/personalCenter/examine.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/personalCenter/noPass.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/personalCenter/pass.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/teaching/arrow.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/teaching/electronicBooks.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/teaching/paperCopies.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/teaching/sample.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/teaching/teacher.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/config.js 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/middleGround/api/identity.js 141 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/middleGround/tool.js 113 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/toolClass.js 200 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/main.css 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/MapContainer.vue 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sliderImg/component/verify.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sliderImg/img/refresh.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sliderImg/img/right.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sliderImg/img/update@3.5x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sliderImg/sliderImg.css 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sliderImg/sliderImg.js 262 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/headerPage.vue 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/login.vue 832 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/plugin/axios/index.ts 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/counter.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/index.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/modules/user.js 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/aboutUs/index.vue 378 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/bookStore/detail.vue 593 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/bookStore/index.vue 383 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/educationalPublishing/index.vue 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/home/index.vue 327 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -8,6 +8,7 @@
      "name": "xiehe",
      "version": "0.0.0",
      "dependencies": {
        "@amap/amap-jsapi-loader": "^1.0.1",
        "axios": "^1.11.0",
        "element-plus": "^2.10.7",
        "less": "^4.4.0",
@@ -15,6 +16,7 @@
        "pinia": "^3.0.3",
        "spark-md5": "^3.0.2",
        "vue": "^3.5.18",
        "vue-baidu-map-3x": "^1.0.40",
        "vue-router": "^4.5.1"
      },
      "devDependencies": {
@@ -26,6 +28,12 @@
      "engines": {
        "node": "^20.19.0 || >=22.12.0"
      }
    },
    "node_modules/@amap/amap-jsapi-loader": {
      "version": "1.0.1",
      "resolved": "https://registry.npmmirror.com/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz",
      "integrity": "sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw==",
      "license": "MIT"
    },
    "node_modules/@ampproject/remapping": {
      "version": "2.3.0",
@@ -1620,6 +1628,12 @@
        }
      }
    },
    "node_modules/@yangjianfei/bmaplib.lushu": {
      "version": "1.0.0",
      "resolved": "https://registry.npmmirror.com/@yangjianfei/bmaplib.lushu/-/bmaplib.lushu-1.0.0.tgz",
      "integrity": "sha512-qZVijbgUgNs6tsP1muS67x0XzE5fJ3kFireouDvXO3bUYVV6XbpjZXksQTsggihLMIEvC1DO9GS9vVF8CnEeqQ==",
      "license": "MIT"
    },
    "node_modules/ansis": {
      "version": "4.1.0",
      "resolved": "https://registry.npmmirror.com/ansis/-/ansis-4.1.0.tgz",
@@ -1659,6 +1673,39 @@
      "funding": {
        "url": "https://github.com/sponsors/antfu"
      }
    },
    "node_modules/bmaplib.curveline": {
      "version": "1.0.0",
      "resolved": "https://registry.npmmirror.com/bmaplib.curveline/-/bmaplib.curveline-1.0.0.tgz",
      "integrity": "sha512-9wcFMVhiYxNPqpvsLDAADn3qDhNzXp2mA6VyHSHg2XOAgSooC7ZiujdFhy0sp+0QYjTfJ/MjmLuNoUg2HHxH4Q==",
      "license": "MIT"
    },
    "node_modules/bmaplib.distancetool": {
      "version": "1.0.2",
      "resolved": "https://registry.npmmirror.com/bmaplib.distancetool/-/bmaplib.distancetool-1.0.2.tgz",
      "integrity": "sha512-EvxMnQRH6xM036zx5OLPyTg5tMCTbFBuGTTHOtExLy2/T0X6v5Va0YE7c3IPm/a/Eo5V/ynYpOLOLZbRY8ccyA==",
      "license": "MIT"
    },
    "node_modules/bmaplib.heatmap": {
      "version": "1.0.4",
      "resolved": "https://registry.npmmirror.com/bmaplib.heatmap/-/bmaplib.heatmap-1.0.4.tgz",
      "integrity": "sha512-rmhqUARBpUSJ9jXzUI2j7dIOqnc38bqubkx/8a349U2qtw/ulLUwyzRD535OrA8G7w5cz4aPKm6/rNvUAarg/Q==",
      "license": "MIT"
    },
    "node_modules/bmaplib.markerclusterer": {
      "version": "1.0.13",
      "resolved": "https://registry.npmmirror.com/bmaplib.markerclusterer/-/bmaplib.markerclusterer-1.0.13.tgz",
      "integrity": "sha512-VrLyWSiuDEVNi0yUfwOhFQ6z1oEEHS4w36GNu3iASu6p52QIx9uAXMUkuSCHReNR0bj2Cp9SA1dSx5RpojXajQ==",
      "license": "MIT",
      "dependencies": {
        "bmaplib.texticonoverlay": "^1.0.2"
      }
    },
    "node_modules/bmaplib.texticonoverlay": {
      "version": "1.0.2",
      "resolved": "https://registry.npmmirror.com/bmaplib.texticonoverlay/-/bmaplib.texticonoverlay-1.0.2.tgz",
      "integrity": "sha512-4ZTWr4ZP3B6qEWput5Tut16CfZgII38YwM3bpyb4gFTQyORlKYryFp9WHWrwZZaHlOyYDAXG9SX0hka43jTADg==",
      "license": "MIT"
    },
    "node_modules/browserslist": {
      "version": "4.25.2",
@@ -3085,6 +3132,12 @@
        "node": ">=16"
      }
    },
    "node_modules/tiny-emitter": {
      "version": "2.1.0",
      "resolved": "https://registry.npmmirror.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
      "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
      "license": "MIT"
    },
    "node_modules/tinyglobby": {
      "version": "0.2.14",
      "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.14.tgz",
@@ -3392,6 +3445,25 @@
        }
      }
    },
    "node_modules/vue-baidu-map-3x": {
      "version": "1.0.40",
      "resolved": "https://registry.npmmirror.com/vue-baidu-map-3x/-/vue-baidu-map-3x-1.0.40.tgz",
      "integrity": "sha512-Rq3g1KNsNztkuX3SJIuCpy6HE3xHVX8ySgqS2xC3jut/hvVr5kFBS0Nu7uYppk3xYVz69S1JFxU8WUI0Xftpyg==",
      "license": "MIT",
      "dependencies": {
        "@yangjianfei/bmaplib.lushu": "^1.0.0",
        "bmaplib.curveline": "^1.0.0",
        "bmaplib.distancetool": "^1.0.2",
        "bmaplib.heatmap": "^1.0.4",
        "bmaplib.markerclusterer": "^1.0.13",
        "tiny-emitter": "^2.1.0",
        "vue": "^3.2.25",
        "vue-router": "^4.0.14"
      },
      "peerDependencies": {
        "vue": "^3.2.25"
      }
    },
    "node_modules/vue-router": {
      "version": "4.5.1",
      "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.1.tgz",
@@ -3461,6 +3533,11 @@
    }
  },
  "dependencies": {
    "@amap/amap-jsapi-loader": {
      "version": "1.0.1",
      "resolved": "https://registry.npmmirror.com/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz",
      "integrity": "sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw=="
    },
    "@ampproject/remapping": {
      "version": "2.3.0",
      "resolved": "https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.3.0.tgz",
@@ -4460,6 +4537,11 @@
        }
      }
    },
    "@yangjianfei/bmaplib.lushu": {
      "version": "1.0.0",
      "resolved": "https://registry.npmmirror.com/@yangjianfei/bmaplib.lushu/-/bmaplib.lushu-1.0.0.tgz",
      "integrity": "sha512-qZVijbgUgNs6tsP1muS67x0XzE5fJ3kFireouDvXO3bUYVV6XbpjZXksQTsggihLMIEvC1DO9GS9vVF8CnEeqQ=="
    },
    "ansis": {
      "version": "4.1.0",
      "resolved": "https://registry.npmmirror.com/ansis/-/ansis-4.1.0.tgz",
@@ -4490,6 +4572,34 @@
      "version": "2.5.0",
      "resolved": "https://registry.npmmirror.com/birpc/-/birpc-2.5.0.tgz",
      "integrity": "sha512-VSWO/W6nNQdyP520F1mhf+Lc2f8pjGQOtoHHm7Ze8Go1kX7akpVIrtTa0fn+HB0QJEDVacl6aO08YE0PgXfdnQ=="
    },
    "bmaplib.curveline": {
      "version": "1.0.0",
      "resolved": "https://registry.npmmirror.com/bmaplib.curveline/-/bmaplib.curveline-1.0.0.tgz",
      "integrity": "sha512-9wcFMVhiYxNPqpvsLDAADn3qDhNzXp2mA6VyHSHg2XOAgSooC7ZiujdFhy0sp+0QYjTfJ/MjmLuNoUg2HHxH4Q=="
    },
    "bmaplib.distancetool": {
      "version": "1.0.2",
      "resolved": "https://registry.npmmirror.com/bmaplib.distancetool/-/bmaplib.distancetool-1.0.2.tgz",
      "integrity": "sha512-EvxMnQRH6xM036zx5OLPyTg5tMCTbFBuGTTHOtExLy2/T0X6v5Va0YE7c3IPm/a/Eo5V/ynYpOLOLZbRY8ccyA=="
    },
    "bmaplib.heatmap": {
      "version": "1.0.4",
      "resolved": "https://registry.npmmirror.com/bmaplib.heatmap/-/bmaplib.heatmap-1.0.4.tgz",
      "integrity": "sha512-rmhqUARBpUSJ9jXzUI2j7dIOqnc38bqubkx/8a349U2qtw/ulLUwyzRD535OrA8G7w5cz4aPKm6/rNvUAarg/Q=="
    },
    "bmaplib.markerclusterer": {
      "version": "1.0.13",
      "resolved": "https://registry.npmmirror.com/bmaplib.markerclusterer/-/bmaplib.markerclusterer-1.0.13.tgz",
      "integrity": "sha512-VrLyWSiuDEVNi0yUfwOhFQ6z1oEEHS4w36GNu3iASu6p52QIx9uAXMUkuSCHReNR0bj2Cp9SA1dSx5RpojXajQ==",
      "requires": {
        "bmaplib.texticonoverlay": "^1.0.2"
      }
    },
    "bmaplib.texticonoverlay": {
      "version": "1.0.2",
      "resolved": "https://registry.npmmirror.com/bmaplib.texticonoverlay/-/bmaplib.texticonoverlay-1.0.2.tgz",
      "integrity": "sha512-4ZTWr4ZP3B6qEWput5Tut16CfZgII38YwM3bpyb4gFTQyORlKYryFp9WHWrwZZaHlOyYDAXG9SX0hka43jTADg=="
    },
    "browserslist": {
      "version": "4.25.2",
@@ -5396,6 +5506,11 @@
        "copy-anything": "^3.0.2"
      }
    },
    "tiny-emitter": {
      "version": "2.1.0",
      "resolved": "https://registry.npmmirror.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
      "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
    },
    "tinyglobby": {
      "version": "0.2.14",
      "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.14.tgz",
@@ -5562,6 +5677,21 @@
        "@vue/shared": "3.5.18"
      }
    },
    "vue-baidu-map-3x": {
      "version": "1.0.40",
      "resolved": "https://registry.npmmirror.com/vue-baidu-map-3x/-/vue-baidu-map-3x-1.0.40.tgz",
      "integrity": "sha512-Rq3g1KNsNztkuX3SJIuCpy6HE3xHVX8ySgqS2xC3jut/hvVr5kFBS0Nu7uYppk3xYVz69S1JFxU8WUI0Xftpyg==",
      "requires": {
        "@yangjianfei/bmaplib.lushu": "^1.0.0",
        "bmaplib.curveline": "^1.0.0",
        "bmaplib.distancetool": "^1.0.2",
        "bmaplib.heatmap": "^1.0.4",
        "bmaplib.markerclusterer": "^1.0.13",
        "tiny-emitter": "^2.1.0",
        "vue": "^3.2.25",
        "vue-router": "^4.0.14"
      }
    },
    "vue-router": {
      "version": "4.5.1",
      "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.1.tgz",
package.json
@@ -13,6 +13,7 @@
    "format": "prettier --write src/"
  },
  "dependencies": {
    "@amap/amap-jsapi-loader": "^1.0.1",
    "axios": "^1.11.0",
    "element-plus": "^2.10.7",
    "less": "^4.4.0",
@@ -20,6 +21,7 @@
    "pinia": "^3.0.3",
    "spark-md5": "^3.0.2",
    "vue": "^3.5.18",
    "vue-baidu-map-3x": "^1.0.40",
    "vue-router": "^4.5.1"
  },
  "devDependencies": {
src/assets/images/book-cover.png
src/assets/images/bookStore/feblei.png
src/assets/images/default-book-img.png
Binary files differ
src/assets/images/default_avatar.png
Binary files differ
src/assets/images/delete.png
Binary files differ
src/assets/images/header/dialogLeftImg.png
src/assets/images/index/bookListBg.png
Binary files differ
src/assets/images/login/boxBg.png
Binary files differ
src/assets/images/login/pageBg.png
Binary files differ
src/assets/images/login/weChartIcon.png
Binary files differ
src/assets/images/packDown.png
Binary files differ
src/assets/images/packUp.png
Binary files differ
src/assets/images/pageHeader/logo.png
Binary files differ
src/assets/images/personalCenter/choose.png
Binary files differ
src/assets/images/personalCenter/examine.png
Binary files differ
src/assets/images/personalCenter/noPass.png
Binary files differ
src/assets/images/personalCenter/pass.png
Binary files differ
src/assets/images/teaching/arrow.png
Binary files differ
src/assets/images/teaching/electronicBooks.png
Binary files differ
src/assets/images/teaching/paperCopies.png
Binary files differ
src/assets/images/teaching/sample.png
Binary files differ
src/assets/images/teaching/teacher.png
Binary files differ
src/assets/js/config.js
@@ -1,4 +1,5 @@
export const requestCtx = 'http://182.92.203.7:5001' // 请求地址
// export const requestCtx = 'http://182.92.203.7:5001' // 请求地址
export const requestCtx = 'http://39.96.166.67' // 请求地址
// export const appId = 1051;
// export const requestCtx = 'http://172.31.31.145' // 请求地址
@@ -6,9 +7,9 @@
export const appId = 1
export const requestTimeOut = 300000 // 请求超时时间
export const tokenKey = 'jilin-token'
export const userInfoKey = 'jilin-userInfo' // 用户信息key
export const appRefCode = 'jilinWebsite'
export const tokenKey = 'jsek-token'
export const userInfoKey = 'jsek-isUserInfo' // 用户信息key
export const appRefCode = 'PUMC'
export const goodsStore = `defaultGoodsStore${appId}` // 默认商品库(书城)
export const publicStore = `defaultPublicStore${appId}` // 默认资源开放仓储
export const publicRepository = `defaultPublicRepository${appId}` // 默认资源开放库
@@ -66,7 +67,7 @@
  appid: 'wx2b9d4a6308fd03d6',
  scope: 'snsapi_login',
  logInRedirectURL: encodeURIComponent(requestCtx + '/website'),
  authenRedirectURL:encodeURIComponent(requestCtx + '/website/#/userInfo')
  authenRedirectURL: encodeURIComponent(requestCtx + '/website/#/userInfo'),
}
const config = {
@@ -79,6 +80,6 @@
  reg_tel,
  appId,
  refCode,
  wxLogin
  wxLogin,
}
export default config
src/assets/js/middleGround/api/identity.js
@@ -1,181 +1,194 @@
import request from "@/plugin/axios/index.ts";
import request from '@/plugin/axios/index.ts'
const identityApi = {
  // 获取图形验证码
  getImgCode() {
    return request({
      url: "/identity/NewCaptcha",
      method: "post",
    });
      url: '/identity/NewCaptcha',
      method: 'post',
    })
  },
  // 验证图形验证码
  verificationImgCode(data) {
    return request({
      url: "/identity/ValidCaptcha",
      method: "post",
      url: '/identity/ValidCaptcha',
      method: 'post',
      data,
    });
    })
  },
  // 获取短信验证码
  getPhoneCode(data) {
    return request({
      url: "/identity/NewSms",
      method: "post",
      url: '/identity/NewSms',
      method: 'post',
      data,
    });
    })
  },
  // 验证短信验证码
  verificationPhoneCode(data) {
    return request({
      url: "/identity/api/ApiValidMobilePhone",
      method: "post",
      url: '/identity/api/ApiValidMobilePhone',
      method: 'post',
      data,
    });
    })
  },
  getSlideCaptchaImage(options) {
    return request('/identity/GetSlideCaptchaImage', {
      method: 'POST',
      data: options || {},
    })
  },
  // 验证滑动验证码
  validSlideCaptcha(options) {
    return request('/identity/ValidSlideCaptcha', {
      method: 'POST',
      data: options || {},
    })
  },
  // 通过手机号注册用户
  registerAppUserWithPhone(data) {
    return request({
      url: "/identity/api/RegisterAppUserWithPhone",
      method: "post",
      url: '/identity/api/RegisterAppUserWithPhone',
      method: 'post',
      data,
    });
    })
  },
  // 账号密码登录
  loginByPassword(data) {
    return request({
      url: "/identity/api/LoginByPassword",
      method: "post",
      url: '/identity/api/LoginByPassword',
      method: 'post',
      data,
    });
    })
  },
  // 短信验证码登录
  loginByMobilePhone(data) {
    return request({
      url: "/identity/api/LoginByMobilePhone",
      method: "post",
      url: '/identity/api/LoginByMobilePhone',
      method: 'post',
      data,
    });
    })
  },
  // 设置用户key
  setUserKey(data) {
    return request({
      url: "/identity/api/ApiAppUserSetKey",
      method: "post",
      url: '/identity/api/ApiAppUserSetKey',
      method: 'post',
      data,
    });
    })
  },
  // 获取用户key
  getUserKey(data) {
    return request({
      url: "/identity/api/ApiGetAppUserKey",
      method: "post",
      url: '/identity/api/ApiGetAppUserKey',
      method: 'post',
      data,
    });
    })
  },
  // 删除用户key
  delUserKey(data) {
    return request({
      url: "/identity/api/ApiDelAppUserKey",
      method: "post",
      url: '/identity/api/ApiDelAppUserKey',
      method: 'post',
      data,
    });
    })
  },
  // 获取去当前用户信息
  getCurrentAppUser() {
    return request({
      url: "/identity/api/GetCurrentAppUser",
      method: "post",
    });
      url: '/identity/api/GetCurrentAppUser',
      method: 'post',
    })
  },
  // 添加用户信息
  setAppUserInfo(data) {
    return request({
      url: "/identity/api/SetAppUserInfoRequest",
      method: "post",
      url: '/identity/api/SetAppUserInfoRequest',
      method: 'post',
      data,
    });
    })
  },
  // 用户更换绑定手机号,如没有绑定手机则自动创建
  userSetPhoneNumber(data) {
    return request({
      url: "/identity/api/ApiUserSetPhoneNumber",
      method: "post",
      url: '/identity/api/ApiUserSetPhoneNumber',
      method: 'post',
      data,
    });
    })
  },
  // 检测用户是否绑定微信
  checkBuildingWeChat(data) {
    return request({
      url: "/identity/api/ApiCheckBuildingWeChat",
      method: "post",
      url: '/identity/api/ApiCheckBuildingWeChat',
      method: 'post',
      data,
    });
    })
  },
  // 通过手机号重置密码
  changePasswordByMobilePhone(data) {
    return request({
      url: "/identity/api/ChangePasswordByMobilePhone",
      method: "post",
      url: '/identity/api/ChangePasswordByMobilePhone',
      method: 'post',
      data,
    });
    })
  },
  // 微信开放平台扫码登录
  loginByWeChatOpenCode(data) {
    return request({
      url: "/identity/api/LoginByWeChatOpenCode",
      method: "post",
      url: '/identity/api/LoginByWeChatOpenCode',
      method: 'post',
      data,
    });
    })
  },
  // 用户绑定微信号
  bindingWeChat(data) {
    return request({
      url: "/identity/api/ApiBindingWeChat",
      method: "post",
      url: '/identity/api/ApiBindingWeChat',
      method: 'post',
      data,
    });
    })
  },
  // 设置登录的用户名和密码,用户名和密码至少6位
  setLoginNameAndPassword(data) {
    return request({
      url: "/identity/api/ApiUserSetLoginNameAndPassword",
      method: "post",
      url: '/identity/api/ApiUserSetLoginNameAndPassword',
      method: 'post',
      data,
    });
    })
  },
  // 获取邮箱验证码
  getEmailCode(data) {
    return request({
      url: "/identity/api/SendVerifyEMail",
      method: "post",
      url: '/identity/api/SendVerifyEMail',
      method: 'post',
      data,
    });
    })
  },
  // 用户绑定邮箱
  bindingEmail(data) {
    return request({
      url: "/identity/api/ApiBindEMail",
      method: "post",
      url: '/identity/api/ApiBindEMail',
      method: 'post',
      data,
    });
    })
  },
};
}
export default identityApi;
export default identityApi
src/assets/js/middleGround/tool.js
@@ -1,7 +1,7 @@
import { requestCtx, appId } from '@/assets/js/config.js'
// import defaultImg from '@/assets/images/default-book-img.png'
// import defaultBookFair from '@/assets/images/default-bookFair.png'
// import bookCover from '@/assets/images/book-cover.png'
import bookCover from '@/assets/images/book-cover.png'
// import defaultPub from '@/assets/images/math/default-pub.png'
// import defaultAudio from '@/assets/images/math/default-audio.png'
import moment from 'moment'
@@ -13,7 +13,7 @@
  storeInfo,
  repositoryInfo,
  coverSize,
  handelEBooK
  handelEBooK,
}) {
  const dataList = []
  for (let i = 0; i < datas.length; i++) {
@@ -78,7 +78,7 @@
      subProductCount: parseInt(item.datas.SubProductCount),
      ..._fields,
      datas: item.datas,
      subDatas
      subDatas,
    }
    // 统一处理价格
@@ -88,7 +88,7 @@
        let saleMethod = []
        try {
          saleMethod = obj.cmsDatas[0].datas.find(
            (item) => item.datas.RefCode == 'tourism_accompanyingResources'
            (item) => item.datas.RefCode == 'tourism_accompanyingResources',
          ).datas.SaleMethod
          saleMethod = JSON.parse(saleMethod)
        } catch (error) {
@@ -154,22 +154,22 @@
  itemFields,
  handelEBooK,
}) {
  item.fileMap = {};
  let itemFieldsData = [];
  item.fileMap = {}
  let itemFieldsData = []
  for (const key in itemFields) {
    itemFieldsData.push(key);
    itemFieldsData.push(key)
  }
  let fieldsData = [];
  let fieldsData = []
  for (const key in fields) {
    fieldsData.push(key);
    fieldsData.push(key)
  }
  for (let i = 0; i < fieldsData.length; i++) {
    const field = fieldsData[i];
    item.datas[field] = JSON.parse(item.datas[field]);
    const datas = item.datas[field];
    const field = fieldsData[i]
    item.datas[field] = JSON.parse(item.datas[field])
    const datas = item.datas[field]
    if (datas.length > 0) {
      if (datas[0].Value) {
        item[field] = datas[0].Value;
        item[field] = datas[0].Value
        if (datas[0].Data.FileLinkList && datas[0].Data.FileLinkList.length) {
          item.fileMap = {
            ...item.fileMap,
@@ -178,13 +178,13 @@
                return {
                  ...item.File,
                  ...item,
                };
              })
                }
              }),
            ),
          };
          }
        }
      } else if (datas[0].Data) {
        item[field] = datas[0].Data.Value;
        item[field] = datas[0].Data.Value
        if (datas[0].Data.FileLinkList && datas[0].Data.FileLinkList.length) {
          item.fileMap = {
            ...item.fileMap,
@@ -193,84 +193,77 @@
                return {
                  ...item.File,
                  ...item,
                };
              })
                }
              }),
            ),
          };
          }
        }
      }
    }
  }
  // 处理cms资源
  const subDatas = item.subDatas;
  const linkItemsMap = {};
  const subDatas = item.subDatas
  const linkItemsMap = {}
  if (subDatas) {
    for (const sdata of subDatas) {
      const tag = sdata.queryTag;
      const tag = sdata.queryTag
      for (const subItem of sdata.datas) {
        convertCmsItemBase(subItem, coverSize, handelEBooK);
        subItem.fileMap = {};
        convertCmsItemBase(subItem, coverSize, handelEBooK)
        subItem.fileMap = {}
        for (let i = 0; i < itemFieldsData.length; i++) {
          const itemField = itemFieldsData[i];
          const itemField = itemFieldsData[i]
          try {
            subItem.datas[itemField] = JSON.parse(subItem.datas[itemField]);
            subItem.datas[itemField] = JSON.parse(subItem.datas[itemField])
          } catch (error) {
            subItem.datas[itemField] = [];
            subItem.datas[itemField] = []
          }
          const itemDatas = subItem.datas[itemField];
          const itemDatas = subItem.datas[itemField]
          if (itemDatas.length > 0) {
            if (itemDatas[0].Value) {
              subItem[itemField] = itemDatas[0].Value;
              subItem[itemField] = itemDatas[0].Value
              if (itemDatas[0].FileList && itemDatas[0].FileList.length) {
                subItem.fileMap = {
                  ...subItem.fileMap,
                  ...handleLinkFileInfo(itemDatas[0].FileList),
                };
                }
              }
            } else if (itemDatas[0].Data) {
              subItem[itemField] = itemDatas[0].Data.Value;
              if (
                itemDatas[0].Data.FileList &&
                itemDatas[0].Data.FileList.length
              ) {
              subItem[itemField] = itemDatas[0].Data.Value
              if (itemDatas[0].Data.FileList && itemDatas[0].Data.FileList.length) {
                subItem.fileMap = {
                  ...subItem.fileMap,
                  ...handleLinkFileInfo(itemDatas[0].Data.FileList),
                };
                }
              }
            } else if (itemDatas[0].CmsItemData) {
              subItem[itemField] = itemDatas[0].CmsItemData.Value;
              if (
                itemDatas[0].CmsItemData.FileList &&
                itemDatas[0].CmsItemData.FileList.length
              ) {
              subItem[itemField] = itemDatas[0].CmsItemData.Value
              if (itemDatas[0].CmsItemData.FileList && itemDatas[0].CmsItemData.FileList.length) {
                subItem.fileMap = {
                  ...subItem.fileMap,
                  ...handleLinkFileInfo(itemDatas[0].CmsItemData.FileList),
                };
                }
              }
            }
          }
        }
        if (subItem.productLinkInfo && subItem.productLinkInfo.length) {
          let itemProductLinkInfo = subItem.productLinkInfo.find(citem => citem.Name == item.datas.Name)
          let itemProductLinkInfo = subItem.productLinkInfo.find(
            (citem) => citem.Name == item.datas.Name,
          )
          subItem.productLinkPath =
            itemProductLinkInfo.LinkPath +
            "\\" +
            itemProductLinkInfo.CmsItemId;
            itemProductLinkInfo.LinkPath + '\\' + itemProductLinkInfo.CmsItemId
        }
        if (subItem.linkInfo && subItem.linkInfo.length)
          subItem.linkPath =
            subItem.linkInfo[0].LinkPath + "\\" + subItem.linkInfo[0].CmsItemId;
          subItem.linkPath = subItem.linkInfo[0].LinkPath + '\\' + subItem.linkInfo[0].CmsItemId
      }
      linkItemsMap[tag] = sdata.datas;
      linkItemsMap[tag] = sdata.datas
    }
  }
  convertCmsItemBase(item, coverSize, handelEBooK);
  item.idPath = path + "\\" + item.id;
  item.subItems = linkItemsMap;
  return item;
  convertCmsItemBase(item, coverSize, handelEBooK)
  item.idPath = path + '\\' + item.id
  item.subItems = linkItemsMap
  return item
}
const handleLinkFileInfo = (linkList) => {
@@ -287,7 +280,7 @@
      size: linkItem.Size,
      // metaData: JSON.parse(linkItem.MetaData ?? "{}"),
      order: linkItem.Order,
      protectType: linkItem.ProtectType
      protectType: linkItem.ProtectType,
    }
  }
  return linkFileMap
@@ -309,9 +302,9 @@
  item.linkStoreId = parseInt(item.datas.LinkStore)
  item.linkRepoId = item.datas.LinkRepository
  item.childrenCount = parseInt(item.datas.ChildrenCount ?? '0')
  ;(item.childrenFolderCount = parseInt(item.datas.ChildrenFolderCount ?? '0')),
  ;((item.childrenFolderCount = parseInt(item.datas.ChildrenFolderCount ?? '0')),
    (item.childrenChannelCount = parseInt(item.datas.ChildrenChannelCount ?? '0')),
    (item.linkId = parseInt(item.datas.LinkId))
    (item.linkId = parseInt(item.datas.LinkId)))
  item.linkOrg = JSON.parse(item.datas.LinkOrg ?? '[]')[0]
  item.linkDepartment = JSON.parse(item.datas.LinkDepartment ?? '[]')[0]
  item.linkInfo = JSON.parse(item.datas.LinkInfo ?? '[]')
@@ -328,7 +321,7 @@
    if (handelEBooK) {
      // 获取随书资源的销售方式
      let saleMethod = item.cmsDatas[0].datas.find(
        (item) => item.refCode == 'tourism_accompanyingResources'
        (item) => item.refCode == 'tourism_accompanyingResources',
      ).saleMethod
      if (saleMethod && saleMethod.length > 0) {
        Object.keys(saleMethod[0]).map((key) => {
@@ -412,9 +405,9 @@
    src = requestCtx + `/file/GetPreViewImage?md5=${md5}`
  } else {
    if(storeInfo == `defaultGoodsStore${appId}`){
      return bookCover;
      return bookCover
    }else{
      return ""
      return ''
    }
  }
  if (width && src) src += `&width=${width}`
src/assets/js/toolClass.js
@@ -1,12 +1,7 @@
import SparkMD5 from 'spark-md5'
import {
  getPublicImage
} from '@/assets/js/middleGround/tool.js'
import { getPublicImage } from '@/assets/js/middleGround/tool.js'
import config from './config'
import moment from "moment";
import moment from 'moment'
var tool = {
  secondToTime(second) {
@@ -74,9 +69,8 @@
      .replace(/\.[\d]{3}Z/, '')
    var time = new Date(newDate)
    return time.getTime()
  },
  }
}
//处理表单提交数据
export function worksData(res) {
@@ -101,8 +95,8 @@
      nrr.push({
        linkProtectType: e.linkProtectType,
        linkType: e.linkType,
        md5: e.md5
      })
        md5: e.md5,
      }),
    )
  }
  res.forEach((item) => {
@@ -111,7 +105,7 @@
      order: 0,
      typeFieldId: item.typeField.id,
      sequenceNum: item.config ? JSON.parse(item.config).uuid : '',
      newDataAndFileLinkListRequest: []
      newDataAndFileLinkListRequest: [],
    }
    for (let k in value) {
      if (item.typeField.refCode === k) {
@@ -165,7 +159,7 @@
        id: updateOldData.id,
        typeFieldId: citem.typeField.id,
        sequenceNum: citem.sequenceNum,
        setDataAndFileLinkListRequest: []
        setDataAndFileLinkListRequest: [],
      }
      for (let k in value) {
        if (citem.typeField.refCode === k) {
@@ -174,9 +168,11 @@
            obj.setDataAndFileLinkListRequest = linkList
          } else if (typeof value[k] == 'object' && k == 'region') {
            obj.strValue = value[k]?.join('/')
            obj.setDataAndFileLinkListRequest = [{
              area: value[k]
            }]
            obj.setDataAndFileLinkListRequest = [
              {
                area: value[k],
              },
            ]
          } else {
            obj.strValue = value[k].toString()
          }
@@ -191,7 +187,7 @@
        order: 0,
        typeFieldId: citem.typeField.id,
        sequenceNum: citem.sequenceNum,
        setDataAndFileLinkListRequest: []
        setDataAndFileLinkListRequest: [],
      }
      for (let k in value) {
        if (citem.typeField.refCode === k) {
@@ -210,7 +206,7 @@
  })
  return {
    updateData: arr,
    newData: newArr
    newData: newArr,
  }
}
@@ -298,10 +294,7 @@
// 获取文件
export function getPublicFile(md5, isToken) {
  const {
    tokenKey,
    requestCtx
  } = config
  const { tokenKey, requestCtx } = config
  let src = null
  let token = localStorage.getItem(tokenKey)
  if (md5) {
@@ -316,33 +309,28 @@
  return src
}
export const handleCmsItemListRequestData = (datas, fields, path, storeId, repositoryId) => {
  const dataList = [];
  const dataList = []
  for (let i = 0; i < datas.length; i++) {
    const item = datas[i];
    const _fields = {};
    const _datas = [];
    const item = datas[i]
    const _fields = {}
    const _datas = []
    if (fields != null) {
      for (let fieldKey in fields) {
        // 兼容筛选条件的字段值获取,因为后台筛选和取值只能传一个,都会返回值
        fieldKey = fieldKey.replace(/[!=<>*]/g, '');
        fieldKey = fieldKey.replace(/[!=<>*]/g, '')
        if (item.datas[fieldKey]) {
          let values = [];
          let values = []
          if (typeof item.datas[fieldKey] == 'string') {
            values = JSON.parse(item.datas[fieldKey]);
            values = JSON.parse(item.datas[fieldKey])
          } else {
            values = item.datas[fieldKey];
            values = item.datas[fieldKey]
          }
          if (values ?.length > 0) {
            // 用字段名处理返回的字段值
            if (values[0].Value) {
              _fields[fieldKey] = values[0].Value;
              values[0].sequenceNum = values[0].SequenceNum;
              _fields[fieldKey] = values[0].Value
              values[0].sequenceNum = values[0].SequenceNum
            }
            // 兼容处理数据返回的key是CmsItemData
            // if (values[0].CmsItemData) {
@@ -350,24 +338,24 @@
            //   values[0].sequenceNum = values[0].CmsItemData.SequenceNum;
            // }
            item.datas[fieldKey] = values[0];
            item.datas[fieldKey] = values[0]
            if (values ?.length > 1) {
              const isFile = values.find((citem) => citem.FileList ?.length > 0);
              const dataItems = deduplicateArray(values, 'FieldId');
              const isFile = values.find((citem) => citem.FileList?.length > 0)
              const dataItems = deduplicateArray(values, 'FieldId')
              if (!isFile) {
                _datas.push(dataItems[0]);
                _datas.push(dataItems[0])
              } else {
                const customFile = {
                  customFileList: values,
                  name: fieldKey,
                  md5: _fields[fieldKey],
                  FieldId: values[0].FieldId,
                  SequenceNum: values[0].SequenceNum
                };
                _datas.push(customFile);
                  SequenceNum: values[0].SequenceNum,
                }
                _datas.push(customFile)
              }
            } else {
              _datas.push(values[0]);
              _datas.push(values[0])
            }
          }
        }
@@ -375,14 +363,14 @@
    }
    if (item.datas.LogQuery) {
      item.datas.LogQuery = JSON.parse(item.datas.LogQuery);
      item.datas.LogQuery = JSON.parse(item.datas.LogQuery)
    }
    const subDatas = {};
    const subDatas = {}
    if (item.subDatas) {
      for (let subData of item.subDatas) {
        const tag = subData.queryTag.replace('Query', '');
        subDatas[tag] = subData.datas;
        const tag = subData.queryTag.replace('Query', '')
        subDatas[tag] = subData.datas
      }
    }
    dataList.push({
@@ -418,43 +406,44 @@
      ..._fields,
      datas: item.datas,
      fieldList: _datas,
      subDatas
    });
      subDatas,
    })
  }
  return dataList;
};
  return dataList
}
// type结构处理
export const handleTypeList = (list) => {
  for (let i = 0; i < list.length; i++) {
    const type = list[i];
    const type = list[i]
    try {
      type.cfg = JSON.parse(type.config);
      type.cfg = JSON.parse(type.config)
    } catch (error) {
      type.cfg = null;
      type.cfg = null
    }
    const fieldRefcodeMap = {};
    const tableHeaderFieldList = [];
    const isSearchFieldList = [];
    const isAdvSearchFieldList = [];
    const isFilterFieldList = [];
    const fieldRefcodeMap = {}
    const tableHeaderFieldList = []
    const isSearchFieldList = []
    const isAdvSearchFieldList = []
    const isFilterFieldList = []
    console.log(type, 'type')
    handleType({
      typeFieldList: type.typeLinkList,
      typeFieldList: type.cmsTypeLinks,
      fieldRefcodeMap,
      tableHeaderFieldList,
      isSearchFieldList,
      isAdvSearchFieldList,
      isFilterFieldList
    });
    type.fieldRefcodeMap = fieldRefcodeMap;
    type.tableHeaderFieldList = tableHeaderFieldList;
    type.isSearchFieldList = isSearchFieldList;
    type.isAdvSearchFieldList = isAdvSearchFieldList;
    type.isFilterFieldList = isFilterFieldList;
      isFilterFieldList,
    })
    type.fieldRefcodeMap = fieldRefcodeMap
    type.tableHeaderFieldList = tableHeaderFieldList
    type.isSearchFieldList = isSearchFieldList
    type.isAdvSearchFieldList = isAdvSearchFieldList
    type.isFilterFieldList = isFilterFieldList
  }
  return list;
};
  return list
}
const handleType = ({
  typeFieldList,
@@ -462,34 +451,34 @@
  tableHeaderFieldList,
  isSearchFieldList,
  isAdvSearchFieldList,
  isFilterFieldList
  isFilterFieldList,
}) => {
  for (let i = 0; i < typeFieldList.length; i++) {
    const item = typeFieldList[i];
    const item = typeFieldList[i]
    try {
      item.cfg = JSON.parse(item.config);
      item.cfg = JSON.parse(item.config)
    } catch (error) {
      item.cfg = null;
      item.cfg = null
    }
    if (item.typeField) {
      try {
        item.typeField.cfg = JSON.parse(item.typeField.config);
        item.typeField.cfg = JSON.parse(item.typeField.config)
      } catch (error) {
        item.typeField.cfg = null;
        item.typeField.cfg = null
      }
      fieldRefcodeMap[item.typeField.refCode] = item;
      fieldRefcodeMap[item.typeField.refCode] = item
    }
    if (item.cfg && item.cfg.isColHeader) {
      tableHeaderFieldList.push(item);
      tableHeaderFieldList.push(item)
    }
    if (item.cfg && item.cfg.isSearch) {
      isSearchFieldList.push(item);
      isSearchFieldList.push(item)
    }
    if (item.cfg && item.cfg.isAdvSearch) {
      isAdvSearchFieldList.push(item);
      isAdvSearchFieldList.push(item)
    }
    if (item.cfg && item.cfg.isFilter) {
      isFilterFieldList.push(item);
      isFilterFieldList.push(item)
    }
    if (item.children && item.children.length) {
      handleType({
@@ -498,59 +487,54 @@
        tableHeaderFieldList,
        isSearchFieldList,
        isAdvSearchFieldList,
        isFilterFieldList
      });
        isFilterFieldList,
      })
    }
  }
};
}
//处理树形结构
const handleTreeData = (datas, parent, noTriggerSelect = false) => {
  let parentData = {};
  let parentData = {}
  if (parent) {
    parentData = { ...parent, parent: null };
    parentData = { ...parent, parent: null }
  } else {
    parentData = null;
    parentData = null
  }
  const list = [];
  const list = []
  for (let i = 0; i < datas.length; i++) {
    const data = datas[i];
    const data = datas[i]
    const obj = {
      label: data.name,
      key: parentData ? parentData.key + "_" + i : i + "",
      namePath: parentData ? parentData.namePath + "\\" + data.name : data.name,
      key: parentData ? parentData.key + '_' + i : i + '',
      namePath: parentData ? parentData.namePath + '\\' + data.name : data.name,
      icon: data.icon,
      data: data,
      parent: parentData,
      leaf: false,
      children: [],
    };
    if (data["children"] && data["children"].length) {
      obj.leaf = false;
    }
    if (data['children'] && data['children'].length) {
      obj.leaf = false
      obj.children = handleTreeData(
        data["children"],
        data['children'],
        {
          ...data,
          key: obj.key,
          namePath: obj.namePath,
        },
        i == 0 ? false : true // 如果有子数据处理,只有第一条数据需要展开和回调
      );
        i == 0 ? false : true, // 如果有子数据处理,只有第一条数据需要展开和回调
      )
    } else {
      obj.leaf =
        !data["childrenChannelCount"] || data["childrenChannelCount"] == 0;
      obj.leaf = !data['childrenChannelCount'] || data['childrenChannelCount'] == 0
    }
    list.push(obj);
    list.push(obj)
  }
  console.log(list, "list");
  return list;
};
  console.log(list, 'list')
  return list
}
//获取资源
export default {
  ...tool,
src/assets/main.css
@@ -163,7 +163,8 @@
} */
.el-input-group__append, .el-input-group__prepend { 
  vertical-align: initial !important;
  /* vertical-align: initial !important; */
  /* align-items: stretch !important; */
}
.el-checkbox__inner{
  border: 1px solid #000 !important;
src/components/MapContainer.vue
New file
@@ -0,0 +1,90 @@
<template>
  <div class="map-container">
    <!-- 地图容器 -->
    <div id="map-container" ref="mapContainer"></div>
  </div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import AMapLoader from '@amap/amap-jsapi-loader'
// 配置安全密钥(推荐)
window._AMapSecurityConfig = {
  securityJsCode: '4c6cee842f5412a45a781aeaa76e12cc', // 高德控制台获取
}
const mapContainer = ref(null)
const mapInstance = ref(null)
const marker = ref(null)
// 示例地点数据
const location = ref({
  name: '天安门广场',
  address: '北京市东城区长安街',
  position: [116.413823, 39.912052],
})
// 初始化地图
onMounted(() => {
  AMapLoader.load({
    key: '4c6cee842f5412a45a781aeaa76e12cc', // 替换为你的Key
    version: '2.0', // SDK版本
    plugins: ['AMap.Marker', 'AMap.ToolBar', 'AMap.Scale'], // 所需插件
  })
    .then((AMap) => {
      // 创建地图实例
      mapInstance.value = new AMap.Map(mapContainer.value, {
        viewMode: '2D', // 默认使用2D模式
        zoom: 15, // 初始缩放级别
        center: location.value.position, // 初始中心点
      })
      // 添加控件
      mapInstance.value.addControl(new AMap.ToolBar())
      mapInstance.value.addControl(new AMap.Scale())
      // 添加标记点
      marker.value = new AMap.Marker({
        position: location.value.position,
        title: location.value.name,
      })
      mapInstance.value.add(marker.value)
      // 点击标记点显示信息
      marker.value.on('click', () => {
        alert(`您点击了:${location.value.name}`)
      })
    })
    .catch((error) => {
      console.error('地图加载失败:', error)
    })
})
</script>
<style scoped>
.map-container {
  position: relative;
  width: 100%;
  height: 500px;
}
#map-container {
  width: 100%;
  height: 100%;
  border-radius: 8px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.location-card {
  position: absolute;
  bottom: 20px;
  left: 20px;
  background: white;
  padding: 15px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  z-index: 10;
  max-width: 300px;
}
</style>
src/components/sliderImg/component/verify.vue
New file
@@ -0,0 +1,69 @@
<template>
  <div class="container">
    <div id="captcha" style="position: relative"></div>
  </div>
</template>
<script>
export default {
  name: "verify",
  props: {
    msg: String,
    MG: Object,
  },
  data() {
    return {
      code: "",
    };
  },
  mounted() {
    this.getImg();
  },
  methods: {
    getImg() {
      var that = this;
      this.MG.identity.getSlideCaptchaImage().then((res) => {
        try {
          if (res) {
            /* eslint-disable */ // 参数1:当前画布父级元素 参数2:滑动成功函数,返回滑动距离,接口参数前缀,当前盒子内子元素及方法  参数3:滑动失败函数返回滑动距离,接口参数前缀  参数4:通过接口获取到的图片以及宽高比  参数5:当前页面的this
            jigsaw.init(
              document.getElementById("captcha"),
              function (left, prefix, objCustom) {
                const data = {
                  captcha: prefix + left,
                };
                that.MG.identity.validSlideCaptcha(data).then((res) => {
                  if (res && res.result == "验证成功") {
                    that.code = res.code;
                    console.log(res, "this.code");
                    document.getElementById("msg").innerHTML = res.result;
                    objCustom.addClass(
                      objCustom.sliderContainer,
                      "sliderContainer_success"
                    );
                    that.$emit("loginImgVerify", res.code);
                  } else {
                    document.getElementById("msg").innerHTML =
                      res.result + ",点击右上角刷新再试一次";
                    objCustom.addClass(
                      objCustom.sliderContainer,
                      "sliderContainer_fail"
                    );
                  }
                });
              },
              function (left, prefix) {
                console.log(left, prefix, "fail");
              },
              res, // 图片参数
              that
            );
          }
        } catch (error) {
          console.log(error);
        }
      });
    },
  },
};
</script>
src/components/sliderImg/img/refresh.png
src/components/sliderImg/img/right.jpg
src/components/sliderImg/img/update@3.5x.png
src/components/sliderImg/sliderImg.css
New file
@@ -0,0 +1,167 @@
.container {
  max-width: 400px;
  width: auto;
  margin: auto;
  overflow: hidden;
}
input {
  display: block;
  width: 290px;
  line-height: 40px;
  padding: 10px;
  box-sizing: border-box;
  outline: none;
  border: 1px solid #c8cccf;
  border-radius: 4px;
  color: #6a6f77;
}
#msg {
  position: absolute;
  bottom: 60px;
  left: 0;
  width: 100%;
  background-color: rgba(0, 0, 0, 0.3);
  line-height: 40px;
  font-size: 14px;
  color: #fff;
  text-align: center;
  z-index: 999;
}
.msgError {
  color: #ff4c05 !important;
}
.msgSuccess {
  color: #52ccba !important;
}
/* a:link,
a:visited,
a:hover,
a:active {
  margin-left: 100px;
  color: #0366d6;
} */
.block {
  position: absolute;
  left: 0;
  top: 0;
}
.sliderContainer {
  position: relative;
  text-align: center;
  width: 400px;
  height: 40px;
  line-height: 40px;
  margin-top: 15px;
  background: #f7f9fa;
  color: #45494c;
  border: 1px solid #e4e7eb;
}
.sliderContainer_active .slider {
  height: 38px;
  top: -1px;
  border: 1px solid #1991fa;
}
.sliderContainer_active .sliderMask {
  height: 38px;
  border-width: 1px;
}
.sliderContainer_success .slider {
  height: 38px;
  top: -1px;
  border: 1px solid #52ccba;
  background-color: #52ccba !important;
}
.sliderContainer_success .sliderMask {
  height: 38px;
  border: 1px solid #52ccba;
  background-color: #d2f4ef;
}
.sliderContainer_success .sliderIcon {
  background-position: 0 -40px !important;
}
.sliderContainer_fail .slider {
  height: 38px;
  top: -1px;
  border: 1px solid #f57a7a;
  background-color: #f57a7a !important;
}
.sliderContainer_fail .sliderMask {
  height: 38px;
  border: 1px solid #f57a7a;
  background-color: #fce1e1;
}
.sliderContainer_fail .sliderIcon {
  background-position: 0 -83px !important;
}
.sliderContainer_active .sliderText,
.sliderContainer_success .sliderText,
.sliderContainer_fail .sliderText {
  display: none;
}
.sliderMask {
  position: absolute;
  left: 0;
  top: 0;
  height: 40px;
  border: 0 solid #1991fa;
  background: #d1e9fe;
}
.slider {
  position: absolute;
  top: 0;
  left: 0;
  width: 40px;
  height: 40px;
  background: #fff;
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.1);
  cursor: pointer;
  transition: background 0.2s linear;
}
.slider:hover {
  background: #1991fa;
}
.slider:hover .sliderIcon {
  background-position: 0 -40px;
}
.sliderIcon {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: url("./img/right.jpg");
  background-size: 100%;
  background-repeat: no-repeat;
  background-position: center;
}
.refreshIcon {
  position: absolute;
  right: 5px;
  top: 5px;
  width: 25px;
  height: 25px;
  cursor: pointer;
  background: url("./img//refresh.png");
  background-size: 100%;
  background-repeat: no-repeat;
  background-position: center;
  z-index: 1;
}
src/components/sliderImg/sliderImg.js
New file
@@ -0,0 +1,262 @@
(function (window) {
  let l = 50, // 滑块边长
    r = 0, // 滑块半径
    w = 300, // canvas宽度
    h = 150, // canvas高度
    PI = Math.PI;
  let L = l + r * 2; // 滑块实际边长
  function createCanvas(width, height) {
    const canvas = createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    return canvas;
  }
  function createImg(onload, info) {
    const img = createElement("img");
    img.crossOrigin = "Anonymous";
    img.onload = onload;
    img.onerror = () => {
      img.src = getRandomImg(info.backgroundImage);
    };
    img.src = getRandomImg(info.backgroundImage);
    return img;
  }
  function createImg2(onload, info) {
    const block = createElement("img");
    block.crossOrigin = "Anonymous";
    block.onload = onload;
    block.onerror = () => {
      block.src = getRandomImg(info.frontImage);
    };
    block.src = getRandomImg(info.frontImage);
    return block;
  }
  function createElement(tagName) {
    return document.createElement(tagName);
  }
  function addClass(tag, className) {
    tag.classList.add(className);
  }
  function removeClass(tag, className) {
    tag.classList.remove(className);
  }
  function getRandomImg(val) {
    return val;
  }
  function sum(x, y) {
    return x + y;
  }
  function square(x) {
    return x * x;
  }
  function clear(obj) {
    obj.canvasCtx.clearRect(0, 0, w, h);
    obj.blockCtx.clearRect(0, 0, w, h);
    obj.block.width = w;
    document.getElementById("msg").innerHTML = null;
    document.getElementById("captcha").innerHTML = null;
  }
  class jigsaw {
    constructor(el, success, fail, info, parent) {
      this.el = el;
      this.success = success;
      this.fail = fail;
      this.info = info;
      this.parent = parent;
    }
    init() {
      if (this.info) {
        const { backgroundHeight, backgroundWidth, frontHeight, frontWidth } =
          this.info;
        l = frontHeight;
        r = 0;
        w = backgroundWidth;
        h = backgroundHeight;
        L = frontWidth;
      }
      this.initDOM();
      this.initImg();
      this.bindEvents();
    }
    initDOM() {
      const canvas = createCanvas(w, h); // 画布
      const block = canvas.cloneNode(true); // 滑块
      const msg = createElement("div");
      const sliderContainer = createElement("div");
      const refreshIcon = createElement("div");
      const sliderMask = createElement("div");
      const slider = createElement("div");
      const sliderIcon = createElement("span");
      const text = createElement("span");
      block.className = "block";
      msg.id = "msg";
      sliderContainer.className = "sliderContainer";
      refreshIcon.className = "refreshIcon";
      sliderMask.className = "sliderMask";
      slider.className = "slider";
      sliderIcon.className = "sliderIcon";
      text.innerHTML = "向右滑动滑块填充拼图";
      text.className = "sliderText";
      const el = this.el;
      el.appendChild(canvas);
      el.appendChild(refreshIcon);
      el.appendChild(block);
      el.appendChild(msg);
      slider.appendChild(sliderIcon);
      sliderMask.appendChild(slider);
      sliderContainer.appendChild(sliderMask);
      sliderContainer.appendChild(text);
      el.appendChild(sliderContainer);
      Object.assign(this, {
        canvas,
        block,
        sliderContainer,
        refreshIcon,
        slider,
        sliderMask,
        sliderIcon,
        text,
        msg,
        canvasCtx: canvas.getContext("2d"),
        blockCtx: block.getContext("2d"),
        addClass,
        clear,
      });
    }
    initImg() {
      const block = createImg2(() => {
        this.blockCtx.drawImage(block, 0, 0, w, h);
      }, this.info);
      const img = createImg(() => {
        this.canvasCtx.drawImage(img, 0, 0, w, h);
      }, this.info);
      this.img = img;
    }
    clean() {
      this.canvasCtx.clearRect(0, 0, w, h);
      this.blockCtx.clearRect(0, 0, w, h);
      this.block.width = w;
    }
    bindEvents() {
      this.el.onselectstart = () => false;
      this.refreshIcon.onclick = () => {
        this.reset();
      };
      let originX,
        originY,
        trail = [],
        isMouseDown = false;
      var that = this;
      var handleDragStart = function (e) {
        originX = e.clientX || e.touches[0].clientX;
        originY = e.clientY || e.touches[0].clientY;
        // (originX = e.x), (originY = e.y);
        isMouseDown = true;
      };
      var handleDragMove = function (e) {
        if (!isMouseDown) return false;
        var eventX = e.clientX || e.touches[0].clientX;
        var eventY = e.clientY || e.touches[0].clientY;
        const moveX = eventX - originX;
        const moveY = eventY - originY;
        if (moveX < 0 || moveX + 38 >= w) return false;
        that.slider.style.left = moveX + "px";
        var blockLeft = ((w - 40 - 20) / (w - 40)) * moveX;
        that.block.style.left = blockLeft + "px";
        addClass(that.sliderContainer, "sliderContainer_active");
        that.sliderMask.style.width = moveX + "px";
        console.log(that.sliderMask.offsetLeft, 4545);
        trail.push(moveY);
      };
      var handleDragEnd = function (e) {
        if (!isMouseDown) return false;
        isMouseDown = false;
        var eventX = e.clientX || e.changedTouches[0].clientX;
        if (eventX == originX) return false;
        removeClass(that.sliderContainer, "sliderContainer_active");
        that.trail = trail;
        const { left } = that.verify();
        const { prefix } = that.info;
        if (left && prefix) {
          that.success(left, prefix, that);
        } else {
          addClass(that.sliderContainer, "sliderContainer_fail");
          that.fail && that.fail(left, prefix);
          setTimeout(() => {
            that.reset();
          }, 1000);
        }
      };
      this.slider.addEventListener("mousedown", handleDragStart);
      this.slider.addEventListener("touchstart", handleDragStart);
      document.addEventListener("mousemove", handleDragMove);
      document.addEventListener("touchmove", handleDragMove);
      document.addEventListener("mouseup", handleDragEnd);
      document.addEventListener("touchend", handleDragEnd);
      document.addEventListener("mousedown", function () {
        return false;
      });
      document.addEventListener("touchstart", function () {
        return false;
      });
      // this.slider.addEventListener("mousedown");
      // document.addEventListener("mousemove");
      // document.addEventListener("mouseup");
    }
    verify() {
      const arr = this.trail; // 拖动时y轴的移动距离
      const average = arr.reduce(sum) / arr.length; // 平均值
      const deviations = arr.map((x) => x - average); // 偏差数组
      const stddev = Math.sqrt(deviations.map(square).reduce(sum) / arr.length); // 标准差
      const left = parseInt(this.block.style.left);
      return {
        // spliced: Math.abs(left - this.x) < 10,
        // TuringTest: average !== stddev, // 只是简单的验证拖动轨迹,相等时一般为0,表示可能非人为操作
        left,
        // x: this.x,
      };
    }
    reset() {
      this.sliderContainer.className = "sliderContainer";
      this.slider.style.left = 0;
      this.block.style.left = 0;
      this.sliderMask.style.width = 0;
      clear(this);
      // this.initImg();
      this.parent.getImg();
      console.log(this.parent);
    }
  }
  window.jigsaw = {
    init: function (element, success, fail, info, callback) {
      new jigsaw(element, success, fail, info, callback).init();
    },
  };
})(window);
src/layout/components/headerPage.vue
@@ -27,31 +27,16 @@
            <a
              @click="
                () => {
                  $router.push({
                    path: '/register',
                  })
                  console.log(loginRef.value)
                  loginRef.logIn()
                }
              "
              >注册</a
            >
            |
            <a
              @click="
                () => {
                  $router.push({
                    path: '/login',
                    query: {
                      redirectPath: $route.fullPath,
                    },
                  })
                }
              "
              >登录</a
              >注册/登录</a
            >
          </div>
          <div v-else class="userInfoBox">
            <el-dropdown @command="handleCommand">
              <span style="cursor: pointer">欢迎您,{{ userInfo.name }}!</span>
              <span style="cursor: pointer">欢迎您,{{ userStore?.userInfo.name }}!</span>
              <el-dropdown-menu slot="dropdown">
                <el-dropdown-item icon="el-icon-user" command="gotoPersonalCenter"
                  >个人中心</el-dropdown-item
@@ -65,6 +50,7 @@
        </div>
      </div>
    </div>
    <login ref="loginRef"></login>
    <div class="contentBox navBox" v-show="!hideNav">
      <div
        :class="{
@@ -82,8 +68,15 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import login from './login.vue'
import { onMounted, ref } from 'vue'
import { Search } from '@element-plus/icons-vue'
import { useUserStore } from '@/stores'
import { useRouter } from 'vue-router'
const userStore = useUserStore()
const router = useRouter()
const loginRef = ref()
const props = defineProps({
  hideSerch: {
    type: Boolean,
@@ -116,9 +109,16 @@
  },
])
onMounted(() => {
  userInfo.value = userStore.userInfo
  console.log(userInfo.value, 'userInfo')
})
const gotoSearch = () => {}
const handleCommand = () => {}
const gotoPage = () => {}
const gotoPage = (item) => {
  router.push(item.path)
}
</script>
<style lang="less" scoped>
src/layout/components/login.vue
New file
@@ -0,0 +1,832 @@
<template>
  <el-dialog
    align-center
    append-to-body
    v-model="dialogFormVisible"
    @close="closeDialog"
    @open="openDialog"
    class="fansdialog"
  >
    <div style="display: flex; justify-content: space-around">
      <el-image :src="dialogLeftImg" class="leftImg" />
      <div class="logIn">
        <div class="signUpTitle" v-if="flag == 'logIn'">
          <ul>
            <li
              @click="signUpWay = 'authSignUp'"
              :style="{
                color: signUpWay == 'authSignUp' ? '#144941' : '#545C63',
              }"
            >
              手机号登录
            </li>
            <li>|</li>
            <li
              @click="wechatLoginOpen"
              :style="{ color: signUpWay == 'wechat' ? '#144941' : '#545C63' }"
            >
              微信登录
            </li>
          </ul>
        </div>
        <div v-else style="text-align: center; color: #144941">注册</div>
        <div
          class="singUpPhone"
          v-if="signUpWay === 'phone' || 'authSignUp'"
          :style="{ height: signUpWay == 'findPassword' ? '450px' : '400px' }"
        >
          <el-form
            :model="passFormData"
            v-if="signUpWay === 'phone' || 'authSignUp'"
            ref="passFormRef"
            @keyup.enter="signInSystem(passFormRef)"
          >
            <el-form-item
              v-if="signUpWay !== 'findPassword'"
              :rules="[
                { min: 11, max: 11, message: '请输入11位电话号码' },
                {
                  validator: (_, value, callback) => {
                    if (
                      !/^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/.test(
                        value,
                      )
                    ) {
                      callback('请输入11位电话号码')
                    } else {
                      callback()
                    }
                  },
                },
              ]"
              prop="telNumber"
            >
              <el-input v-model="passFormData.telNumber" placeholder="请输入手机号" size="large">
                <template #prepend>
                  <el-select
                    v-model="select"
                    placeholder="Select"
                    style="width: 110px"
                    class="selectPhone"
                  >
                    <el-option label="中国+86" value="86" />
                  </el-select>
                </template>
              </el-input>
            </el-form-item>
            <el-form-item>
              <el-button class="yanzhengBtn" @click="sliderImgDialogVisable = true">验证</el-button>
            </el-form-item>
            <el-form-item
              v-if="signUpWay === 'authSignUp'"
              class="codeWay"
              :rules="[
                { required: true, message: '请输入验证码' },
                { min: 4, max: 6, message: '请输入有效验证码' },
              ]"
              prop="telCode"
            >
              <el-input v-model="passFormData.telCode" placeholder="请输入验证码" size="large" />
              <el-button
                type="primary"
                class="codeBtn"
                :disabled="countDown != 0"
                @click="getCode(passFormRef)"
                >{{ countDown == 0 ? '获取验证码' : '验证码(' + countDown + 's)' }}</el-button
              >
            </el-form-item>
            <el-form-item
              v-if="flag === 'signUp'"
              :rules="[
                { required: true, message: '请输入密码' },
                { min: 8, max: 16, message: '密码在8到16位之间' },
                {
                  validator: (rule, value, callback) => {
                    if (!/\d/.test(value) || /^\d+$/.test(value)) {
                      callback('密码不能为纯数字或字母')
                    } else {
                      callback()
                    }
                  },
                },
              ]"
              prop="password"
              class="passwordInput"
            >
              <el-input
                type="password"
                show-password
                v-model="passFormData.password"
                placeholder="请输入密码"
                size="large"
                style="width: 304px"
              >
              </el-input>
            </el-form-item>
            <el-form-item
              v-if="flag === 'signUp'"
              :rules="[
                { required: true, message: '请输入确认密码' },
                { validator: validateLogInPassword },
              ]"
              prop="confirmPassword"
              class="passwordInput"
            >
              <el-input
                type="password"
                show-password
                v-model="passFormData.confirmPassword"
                placeholder="确认密码"
                size="large"
                style="width: 304px"
              />
            </el-form-item>
          </el-form>
          <el-button class="loginBtn" @click="loginBtn">登录</el-button>
        </div>
      </div>
    </div>
    <el-dialog
      v-model="sliderImgDialogVisable"
      align-center
      destroy-on-close="true"
      width="420"
      class="sliderImgDialog"
    >
      <verify :MG="MG" @loginImgVerify="loginImgVerify"></verify>
    </el-dialog>
  </el-dialog>
</template>
<script setup>
import { ref, inject, watchEffect, reactive, nextTick } from 'vue'
import dialogLeftImg from '@/assets/images/header/dialogLeftImg.png'
import verify from '@/components/sliderImg/component/verify.vue'
import '@/components/sliderImg/sliderImg.js'
import '@/components/sliderImg/sliderImg.css'
import { ElMessage } from 'element-plus'
import { useUserStore } from '@/stores'
import { useRouter } from 'vue-router'
const router = useRouter()
const userStore = useUserStore()
const MG = inject('MG')
const config = inject('config')
const dialogFormVisible = ref(false)
const sliderImgDialogVisable = ref(false)
const flag = ref('logIn') // 登录或注册
const signUpWay = ref('authSignUp') // 登录方式
const select = ref('中国+86')
const countDown = ref(0) // 倒计时时间
let timer = null // 倒计时实例
const passFormRef = ref()
const passFormData = ref({
  telNumber: '',
  password: '',
  telCode: '',
  password: '',
  confirmPassword: '',
})
const closeDialog = () => {
  countDown.value = 0
  clearInterval(timer)
  if (passFormRef.value) {
    passFormRef.value.resetFields()
  }
  dialogFormVisible.value = false
}
// 弹窗打开事件
const openDialog = () => {}
const loginImgVerify = (code) => {
  sliderImgDialogVisable.value = false
  MG.identity
    .getPhoneCode({
      phoneNumber: passFormData.value.telNumber,
      imageCaptcha: code,
      appRefCode: config.appRefCode,
    })
    .then((res) => {
      if (res == '验证码发送成功') {
        getSecond(60)
        ElMessage.success(res)
      } else {
        ElMessage.error(res)
      }
    })
}
watchEffect(() => {
  if (dialogFormVisible.value) {
  }
})
//登录
const loginBtn = () => {
  let query = {
    phoneNumber: passFormData.value.telNumber,
    phoneCaptcha: passFormData.value.telCode,
    appRefCode: config.appRefCode,
    platform: 'string',
  }
  MG.identity.loginByMobilePhone(query).then((res) => {
    console.log('res', res)
    userStore.setToken(res.data.accessToken)
    getUserInfo()
  })
}
const getUserInfo = () => {
  MG.identity.getCurrentAppUser().then((res) => {
    console.log('res', res)
    if (res) {
      let userInfo = res.infoList.find((item) => item.type == 'userInfo')
      let userTypeObj = res.infoList.find((item) => item.type == 'userType')
      const userData = {
        userName: userInfo && userInfo.data ? JSON.parse(userInfo.data).name : '',
        school: userInfo && userInfo.data ? JSON.parse(userInfo.data).school : '',
        city: userInfo && userInfo.data ? JSON.parse(userInfo.data).city : '',
        cityCode: userInfo && userInfo.data ? JSON.parse(userInfo.data).cityCode : '',
        address: userInfo && userInfo.data ? JSON.parse(userInfo.data).address : '',
        userType: userTypeObj && userTypeObj.data ? JSON.parse(userTypeObj.data).userType : '',
      }
      localStorage.setItem('jsek-isUserInfo', userData?.userType == '' ? '-1' : '1')
      let teacherRole = res.roleLinks.find((item) => item.role.refCode == 'teacher')
      let teacherInfos = res.infoList.find((item) => item.type == 'teacherInfo')
      let wechatInfo = res.infoList.find((item) => item.type == 'WeChat')
      let studentInfo = res.infoList.find((item) => item.type == 'Default')
      let phoneInfo = res.secretList.find((item) => item.type == 'MobilePhone')
      // let nameAndPassword = res.secretList.find((item) => item.type == 'LoginNameAndPassword')
      let emailInfo = res.secretList.find((item) => item.type == 'EMail')
      if (teacherRole && teacherInfos) {
        userStore.setUserInfo({
          ...userData,
          ...teacherInfos,
          phoneNumber: phoneInfo?.credential,
          Email: emailInfo ? emailInfo.credential : JSON.parse(teacherInfos.data).email,
          icon: wechatInfo?.icon,
          role: 'Teacher',
          roleId: teacherRole.role.id,
          userId: res.userId,
        })
      } else if (wechatInfo) {
        userStore.setUserInfo({
          ...userData,
          ...wechatInfo,
          phoneNumber: phoneInfo?.credential,
          Email: emailInfo?.credential,
          role: 'Student',
          userId: res.userId,
        })
      } else if (studentInfo) {
        userStore.setUserInfo({
          ...userData,
          ...studentInfo,
          icon: wechatInfo?.icon,
          phoneNumber: phoneInfo?.credential,
          Email: emailInfo?.credential,
          role: 'Student',
          userId: res.userId,
        })
      } else if (phoneInfo) {
        userStore.setUserInfo({
          ...userData,
          ...phoneInfo,
          name: phoneInfo?.credential,
          icon: phoneInfo?.icon,
          phoneNumber: phoneInfo?.credential,
          role: 'Student',
          userId: res.userId,
        })
      }
    }
    router.go(0)
  })
}
// 倒计时
const getSecond = (time) => {
  if (!timer) {
    countDown.value = time
    timer = setInterval(() => {
      countDown.value--
      if (countDown.value == 0) {
        clearInterval(timer)
        timer = null
      }
    }, 1000)
  }
}
// 登录和重置密码按钮按钮
const signInSystem = async (formEl) => {
  if (!formEl) return
  formEl.validate((valid) => {
    if (valid) {
      // if (signUpWay.value === 'phone') {
      //   // 账号密码登录
      //   passwordSignUp()
      // } else if (signUpWay.value == 'authSignUp') {
      //   // 验证码登录
      //   codeSignUp()
      // } else {
      //   // 重置密码
      //   changePassword()
      // }
    }
  })
}
const logIn = () => {
  dialogFormVisible.value = true
  flag.value = 'logIn'
}
// 打开注册弹窗
const signUp = () => {
  dialogFormVisible.value = true
  flag.value = 'signUp'
}
const wechatLoginOpen = () => {
  signUpWay.value = 'wechat'
}
defineExpose({
  logIn,
  signUp,
})
</script>
<style lang="less" scoped>
// 用户信息填写界面
.changeUser {
  .prompt-title {
    width: 80%;
    line-height: 24px;
    color: #000;
    span {
      display: inline-block;
    }
  }
}
.fansdialog {
  width: 806px;
  .leftImg {
    box-sizing: border-box;
    width: 403px;
  }
  .el-dialog__header {
    padding: 0;
  }
  .el-dialog__body {
    width: 806px;
    height: 575px;
    display: flex;
    padding: 0 !important;
  }
  .leftImg {
    .el-image__inner {
      width: 403px;
    }
  }
  .el-dialog__header {
    padding: 0;
  }
  .el-dialog__body {
    width: 806px;
    display: flex;
    padding: 0 !important;
  }
}
.agreementDialog {
  width: 760px;
  height: 600px;
  p span {
    line-height: 24px;
  }
  .el-dialog__header {
    font-size: 18px;
    color: #333;
  }
  .el-dialog__body {
    overflow: auto;
    height: 500px;
    width: 760px;
  }
  .el-dialog__footer {
    display: flex;
    justify-content: center;
  }
}
.wechatTipsDialog {
  .el-dialog__header {
    font-size: 18px;
  }
  .el-dialog__body {
    display: flex;
    align-items: center;
    p {
      margin-left: 10px;
      line-height: 24px;
    }
  }
}
.sliderImgDialog {
  .el-dialog__body {
    min-height: 320px;
  }
}
</style>
<style lang="less">
/** 登录注册弹窗 */
.logIn {
  width: 403px;
  height: 100%;
  padding-top: 48px;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  .signUpTitle {
    width: 100%;
    ul {
      display: flex;
      justify-content: center;
      width: 100%;
      li {
        height: 20px;
        display: flex;
        align-items: center;
        .el-image {
          margin-right: 5px;
          width: 20px;
        }
      }
      li:nth-child(2n + 1) {
        cursor: pointer;
        margin: 0 10px;
      }
      li:first-child {
        margin-left: 0;
        .el-image {
          width: 10px;
        }
      }
    }
  }
  /** 微信登录 */
  .signUpContent {
    display: flex;
    height: 400px;
    flex-wrap: wrap;
    flex-direction: column;
    justify-content: space-around;
    align-content: center;
    .el-image {
      width: 176px;
    }
    h2 {
      font-size: 20px;
      color: #000;
      font-weight: 700;
      text-align: center;
    }
    p {
      text-align: center;
      line-height: 26px;
    }
    .wechatCode {
      h2 {
        margin-bottom: 24px;
      }
    }
  }
  /** 密码登录 */
  .singUpPhone {
    height: 400px;
    display: flex;
    flex-direction: column;
    align-items: center;
    h2 {
      padding-top: 35px;
      font-size: 20px;
      color: #000;
      font-weight: 700;
      text-align: center;
    }
    .back {
      display: flex;
      align-items: center;
      cursor: pointer;
      margin: 10px 0px 0px 20px;
      align-self: flex-start;
      font-size: 12px;
      color: #333;
    }
    .el-form {
      margin-top: 26px;
    }
    .signInBtn {
      width: 304px;
      height: 41px;
      margin-bottom: 33px;
      border-radius: 3px;
      // opacity: 0.55;
      color: #fff;
      font-size: 14px;
    }
    .codeBtn {
      width: 101px;
      height: 41px;
      background-color: #019e58;
      // opacity: 0.55;
    }
    .yanzhengBtn {
      width: 100%;
      height: 41px;
      background-color: #019e58;
      color: #fff;
    }
    .loginBtn {
      width: 76%;
      height: 41px;
      background: linear-gradient(90deg, #019e58 0%, #144941 100%);
      color: #fff;
      margin-top: 50px;
    }
    .el-image {
      display: flex;
      flex-direction: column;
      justify-content: center;
    }
    .authSignUp {
      width: 305px;
      flex: 1;
      display: flex;
      justify-content: end;
      align-items: end;
      padding-bottom: 20px;
      span {
        cursor: pointer;
        color: #333;
        font-size: 12px;
      }
    }
    .codeWay {
      .el-input {
        width: 195px;
      }
      .el-button {
        width: 100px;
        padding: 0;
        margin: 0 0 0 10px;
      }
      .authCodeBox {
        width: 100px;
        height: 50px;
        margin-left: 10px;
        cursor: pointer;
        position: relative;
        span {
          position: absolute;
          top: 35px;
          height: 10px;
          margin-bottom: 20px;
          font-size: 10px;
          color: #1f971f;
        }
      }
    }
  }
  .claus {
    margin-bottom: 10px;
    color: #000;
    font-size: 12px;
    width: 100%;
    text-align: center;
    line-height: 26px;
  }
}
.policy {
  cursor: pointer;
  color: #ff6c00;
}
/** 注册表单 */
.signUp {
  width: 403px;
  justify-content: space-around;
  color: #333;
  font-size: 12px;
  span:first-child,
  span:last-child {
    cursor: pointer;
  }
  .logInTitle {
    width: 96%;
    font-size: 16px;
    margin: 20px 0 0 20px;
    font-weight: bold;
  }
  h4 {
    font-size: 16px;
    color: #ff6c00;
  }
  .logInBox {
    margin-top: 20px;
    padding: 0 40px;
    width: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    .el-form-item {
      .el-button {
        width: 100px;
        height: 41px;
        border-radius: 3px;
        color: #fff;
        font-size: 14px;
      }
    }
    .agreement {
      height: 40px;
      display: flex;
      align-items: center;
      margin: 30px 0 0 0;
      line-height: 32px;
      height: 32px;
      font-size: 12px;
      color: #000;
      .el-checkbox {
        margin-right: 10px;
      }
      .el-link {
        font-size: 12px;
      }
      p {
        height: 100%;
        display: flex;
        align-items: center;
      }
    }
    .hint {
      font-size: 11px;
      color: #545c63;
    }
    .codeWay {
      .el-input {
        width: 195px;
      }
      .el-button {
        width: 100px;
        padding: 0;
        margin: 0 0 0 10px;
      }
      .authCodeBox {
        width: 100px;
        height: 50px;
        margin-left: 10px;
        cursor: pointer;
        position: relative;
        span {
          position: absolute;
          top: 35px;
          left: 0;
          width: 100px;
          font-size: 10px;
          color: #1f971f;
        }
      }
    }
  }
  .logInBtn {
    width: 304px;
    height: 41px;
    margin-top: 10px;
    margin-bottom: 20px;
    border-radius: 3px;
    color: #fff;
    font-size: 14px;
  }
  /** 选择用户类型 */
  .changeUser {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    align-items: center;
    .el-form-item {
      &:last-child {
        margin-bottom: 0;
      }
      .el-button {
        height: 40px;
        margin-left: 10px;
      }
    }
    h2 {
      font-size: 20px;
      margin-top: 70px;
      color: #000;
      font-weight: bold;
    }
    .el-radio-group {
      display: flex;
      flex-direction: column;
      .el-radio-button {
        width: 166px;
      }
      /deep/ .el-radio-button__inner {
        width: 166px;
        height: 41px;
        line-height: 24px;
        border-radius: 4px;
        border: 0;
        border: 1px solid #dcdfe6;
      }
      .el-radio-button:nth-child(n + 1) {
        margin-bottom: 27px;
      }
    }
  }
}
.selectPhone {
  background: #fff;
}
// .el-select {
//   width: 100px;
//   height: 30px;
//   color: red;
//   border: none !important;
//   /deep/ .select-trigger {
//     height: 100%;
//     .el-input--suffix {
//       height: 100%;
//       background-color: #fff;
//     }
//   }
// }
</style>
src/plugin/axios/index.ts
@@ -1,69 +1,84 @@
import axios from "axios";
import myConfig from "@/assets/js/config.js";
import toolClass from "@/assets/js/toolClass.js";
import router from "@/router";
import axios from 'axios'
import myConfig from '@/assets/js/config.js'
import toolClass from '@/assets/js/toolClass.js'
import router from '@/router'
// 创建 axios 实例
const service = axios.create({
  baseURL: myConfig.requestCtx,
  timeout: myConfig.requestTimeOut, // 请求超时时间
});
})
// 请求拦截器
service.interceptors.request.use(
  (config) => {
    let token = localStorage.getItem(myConfig.tokenKey);
    if (token) config.headers["Authorization"] = `bearer ${token}`;
    return config;
    let token = localStorage.getItem(myConfig.tokenKey)
    console.log(token, 'token')
    if (token) config.headers['Authorization'] = `bearer ${token}`
    return config
  },
  (error) => {
    // 发送失败
    Promise.reject(error);
  }
);
    Promise.reject(error)
  },
)
// 响应拦截器
service.interceptors.response.use(
  (response) => {
    // dataAxios 是 axios 返回数据中的 data
    const dataAxios = response.data;
    if (typeof dataAxios.data === "boolean") {
      return dataAxios.data;
    const dataAxios = response.data
    if (typeof dataAxios.data === 'boolean') {
      return dataAxios.data
    }
    if (response.config.responseType == "blob") {
      return dataAxios;
    if (response.config.responseType == 'blob') {
      return dataAxios
    }
    const { success } = dataAxios;
    const { success } = dataAxios
    if (dataAxios.currentDate) {
      sessionStorage.currentDate = new Date(dataAxios.currentDate).getTime();
      sessionStorage.currentDate = new Date(dataAxios.currentDate).getTime()
    }
    // 根据 code 进行判断
    if (response.status == 200 && response.statusText == "OK") {
      return dataAxios.data ? dataAxios.data : dataAxios;
    if (success) {
      return dataAxios.data ? dataAxios.data : dataAxios
    } else {
      // 提示错误
    }
  },
  (error) => {
    if (
      (error.response && error.response.status == 401) ||
      error.code == "ERR_NETWORK"
    ) {
      console.log(router, "router");
    if ((error.response && error.response.status == 401) || error.code == 'ERR_NETWORK') {
      console.log(router, 'router')
      localStorage.removeItem(myConfig.tokenKey);
      localStorage.removeItem("jesk-userInfo");
      router.push({
        name: "login",
      });
      localStorage.removeItem(myConfig.tokenKey)
      localStorage.removeItem('jesk-userInfo')
      localStorage.removeItem('jsek-isUserInfo')
      localStorage.removeItem('alreadyElectronicBook')
      localStorage.removeItem('alreadyPaperBook')
      localStorage.removeItem('electronicBookList')
      localStorage.removeItem('paperBookList')
      sessionStorage.removeItem('cartNumber')
      const url = window.location.hash.slice(1)
      console.log(url, 'url')
      if (url.includes('showLogin=1')) {
        router.push(url)
      } else {
        // router.push(url)
        if (url.includes('?')) {
          console.log(url.includes('?'))
          router.push(url)
        } else {
          router.push(url + '?showLogin=1')
        }
      }
    } else {
      if (error.response && error.response.data && error.response.data.error) {
        console.error(error.response.data.error.msg);
        console.error(error.response.data.error.msg)
      } else {
        console.error("请求发生错误");
        console.error('请求发生错误')
      }
    }
    return Promise.reject(error);
  }
);
    return Promise.reject(error)
  },
)
export default service;
export default service
src/router/index.js
@@ -1,5 +1,8 @@
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import HomeView from '../views/home/index.vue'
import aboutUs from '../views/aboutUs/index.vue'
import bookStore from '../views/bookStore/index.vue'
import bookdetail from '../views/bookStore/detail.vue'
import PageLayout from '../layout/baseLayout.vue'
const router = createRouter({
  history: createWebHashHistory(import.meta.env.BASE_URL),
@@ -15,6 +18,21 @@
          name: 'home',
          component: HomeView,
        },
        {
          path: '/aboutUs',
          name: 'aboutUs',
          component: aboutUs,
        },
        {
          path: '/bookdetail',
          name: 'bookdetail',
          component: bookdetail,
        },
        {
          path: '/bookStore',
          name: 'bookStore',
          component: bookStore,
        },
      ],
    },
  ],
src/stores/counter.js
File was deleted
src/stores/index.js
New file
@@ -0,0 +1,9 @@
import { createPinia } from 'pinia'
// 创建pinia实例
const pinia = createPinia()
export default pinia
// export * from './modules/breadcrumb'
export * from './modules/user'
src/stores/modules/user.js
New file
@@ -0,0 +1,56 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useUserStore = defineStore('user', () => {
  const token = localStorage.getItem('jsek-token') ? ref(localStorage.getItem('jsek-token')) : ref()
  const userInfo = localStorage.getItem('jesk-userInfo')
    ? ref(JSON.parse(localStorage.getItem('jesk-userInfo')))
    : ref()
  const setToken = (value) => {
    token.value = value
    localStorage.setItem('jsek-token', value)
  }
  const setUserInfo = (value) => {
    userInfo.value = value
    localStorage.setItem('jesk-userInfo', JSON.stringify(value))
  }
  // 退出登录
  const delteUserInfo = () => {
    ;((token.vlaue = ''), (userInfo.value = { userName: '', userType: '' }))
    localStorage.removeItem('jsek-token')
    localStorage.removeItem('jesk-userInfo')
    localStorage.removeItem('jsek-isUserInfo')
  }
  // 购物车数量
  let cartNum = ref(1)
  // 更新右侧弹出框购物车的数量
  const updateRightPop = () => {
    cartNum.value += 1
  }
  // 购物车商品id
  const shoppingIds = ref([])
  const updateShoppingIds = (ids) => {
    shoppingIds.value = ids
  }
  // 已购买的商品id
  const buyIds = ref([])
  const updateBuyIds = (ids) => {
    buyIds.value = ids
  }
  return {
    token,
    setToken,
    userInfo,
    setUserInfo,
    delteUserInfo,
    cartNum,
    updateRightPop,
    shoppingIds,
    updateShoppingIds,
    buyIds,
    updateBuyIds,
  }
})
src/views/aboutUs/index.vue
New file
@@ -0,0 +1,378 @@
<template>
  <div class="homePage">
    <el-carousel :height="screenheight + 'px'">
      <el-carousel-item v-for="(item, index) in banner" :key="index">
        <div class="bannerBox imgBox">
          <img id="autoHeight" class="bannerImg" :src="item.icon" @click="bannerLink(item)" />
        </div>
      </el-carousel-item>
    </el-carousel>
    <div class="contentBox">
      <div class="crumbs">
        <el-breadcrumb separator-class="el-icon-arrow-right">
          <el-breadcrumb-item :to="{ name: 'home' }">首页</el-breadcrumb-item>
          <el-breadcrumb-item>关于我们</el-breadcrumb-item>
        </el-breadcrumb>
      </div>
      <div class="aboutUs">
        <div class="aboutTitle">
          <div class="titleBox1">
            <img class="autoImg" src="@/assets/images/xiehe/about/yinhao.png" alt="" />
          </div>
          <div class="titleText">Publisher Introduction</div>
        </div>
        <div class="textBox" v-html="publisherIntroduction"></div>
        <div class="statisticsBox">
          <div class="statisticsItem">
            <div class="statisticsNum">
              {{ publisherData.focusOnMedical }} <span class="circleBox">年</span>
            </div>
            <div class="statisticsTitle">专注医学出版</div>
          </div>
          <div class="statisticsItem">
            <div class="statisticsNum">{{ publisherData.topExpertDatabase }}+ 位</div>
            <div class="statisticsTitle">顶级专家库</div>
          </div>
          <div class="statisticsItem">
            <div class="statisticsNum">
              {{ publisherData.accumulatedTextbooks }}+ <span class="circleBox">本</span>
            </div>
            <div class="statisticsTitle">累计出版教材教辅</div>
          </div>
          <div class="statisticsItem">
            <div class="statisticsNum">
              {{ publisherData.academicJournals }} <span class="circleBox">本</span>
            </div>
            <div class="statisticsTitle">学术期刊</div>
          </div>
          <div class="statisticsItem">
            <div class="statisticsNum">
              {{ publisherData.dualCoreJournal }} <span class="circleBox">本</span>
            </div>
            <div class="statisticsTitle">双核心期刊</div>
          </div>
        </div>
      </div>
    </div>
    <div class="brandCultureBox">
      <div class="brandCultureTop">
        <div class="CultureBox">
          <div class="brandCultureTitle">
            <div>理念与品牌文化</div>
            <div class="enText">Philosophy & Brand Culture</div>
          </div>
          <div class="cultureList" v-loading="loading">
            <div class="cultureItem firstItem">
              <div class="cultureTitle" style="border-bottom: 1px solid rgba(255, 255, 255, 0.1)">
                <div class="leftIcon">
                  <img class="autoImg" src="@/assets/images/xiehe/about/zongzhi.png" alt="" />
                </div>
                <div class="titleTextInfo">
                  <div class="itemTitle" style="color: #fff">{{ ideaBrandCulture[0]?.name }}</div>
                  <div class="itemSubTitle" style="color: #fff">
                    {{ ideaBrandCulture[0]?.EnglishName }}
                  </div>
                </div>
              </div>
              <div
                class="itemText"
                style="color: #d5d5d5"
                v-html="ideaBrandCulture[0]?.content"
              ></div>
            </div>
            <div class="cultureItem">
              <div class="cultureTitle">
                <div class="leftIcon">
                  <img class="autoImg" src="@/assets/images/xiehe/about/beijing.png" alt="" />
                </div>
                <div class="titleTextInfo">
                  <div class="itemTitle">{{ ideaBrandCulture[1]?.name }}</div>
                  <div class="itemSubTitle">
                    {{ ideaBrandCulture[1]?.EnglishName }}
                  </div>
                </div>
              </div>
              <div class="itemText" v-html="ideaBrandCulture[1]?.content"></div>
            </div>
            <div class="cultureItem">
              <div class="cultureTitle">
                <div class="leftIcon">
                  <img class="autoImg" src="@/assets/images/xiehe/about/zizhi.png" alt="" />
                </div>
                <div class="titleTextInfo">
                  <div class="itemTitle">{{ ideaBrandCulture[2]?.name }}</div>
                  <div class="itemSubTitle">
                    {{ ideaBrandCulture[2]?.EnglishName }}
                  </div>
                </div>
              </div>
              <div class="itemText" v-html="ideaBrandCulture[2]?.content"></div>
            </div>
            <div class="cultureItem">
              <div class="cultureTitle">
                <div class="leftIcon">
                  <img class="autoImg" src="@/assets/images/xiehe/about/fazhan.png" alt="" />
                </div>
                <div class="titleTextInfo">
                  <div class="itemTitle">{{ ideaBrandCulture[3]?.name }}</div>
                  <div class="itemSubTitle">
                    {{ ideaBrandCulture[3]?.EnglishName }}
                  </div>
                </div>
              </div>
              <div class="itemText" v-html="ideaBrandCulture[3]?.content"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="page-container">
      <MapContainer />
    </div>
  </div>
</template>
<script setup>
import moment from 'moment'
import MapContainer from '@/components/MapContainer.vue'
import { ref, onBeforeMount, inject, reactive, onMounted } from 'vue'
let screenheight = ref(document.documentElement.clientHeight / 2)
const MG = inject('MG')
const config = inject('config')
const tool = inject('tool')
const banner = reactive([])
let publisherIntroduction = ref('')
let publisherData = ref('')
let ideaBrandCulture = ref([])
let loading = ref(false)
const getBanner = () => {
  MG.resource
    .getItem({
      path: 'banner\\homeBanner',
      fields: { link: [] },
      paging: { start: 0, size: 9 },
    })
    .then((res) => {
      banner.push(...res.datas)
      console.log(res.datas)
    })
}
const getPublisherIntroduction = () => {
  MG.resource
    .getItem({
      path: 'aboutUs\\publisherIntroduction',
      fields: { content: [] },
      paging: { start: 0, size: 9 },
    })
    .then((res) => {
      console.log(res.datas)
      publisherIntroduction.value = res.datas[0].content
    })
}
const getIdeaBrandCulture = () => {
  loading.value = true
  MG.resource
    .getItem({
      path: 'aboutUs\\ideaBrandCulture',
      fields: { content: [], EnglishName: [] },
      paging: { start: 0, size: 9 },
    })
    .then((res) => {
      console.log(res.datas, 'ideaBrandCulture')
      ideaBrandCulture.value = res.datas
      loading.value = false
    })
}
const getPublisherData = () => {
  MG.resource
    .getItem({
      path: 'aboutUs\\publisherData',
      fields: {
        academicJournals: [],
        accumulatedTextbooks: [],
        dualCoreJournal: [],
        focusOnMedical: [],
        topExpertDatabase: [],
      },
      paging: { start: 0, size: 1 },
    })
    .then((res) => {
      console.log(res.datas, 'publisherData')
      publisherData.value = res.datas[0]
    })
}
onMounted(() => {
  getBanner()
  getPublisherIntroduction()
  getPublisherData()
  getIdeaBrandCulture()
})
</script>
<style lang="less" scoped>
.homePage {
  min-width: 1220px;
  min-height: calc(100vh - 61.8%);
  background-color: #fff;
}
.contentBox {
  background-color: #fff;
  padding-bottom: 100px;
  margin-top: 35px;
  .aboutUs {
    width: 100%;
    font-size: 16px;
    border-top: 1px solid #ededed;
    margin-top: 40px;
    .aboutTitle {
      display: flex;
      width: 100%;
      padding-top: 30px;
      .titleBox1 {
        position: relative;
        width: 50px;
        height: 50px;
        margin-right: 20px;
      }
      .titleText {
        font-size: 48px;
        font-weight: 700;
        opacity: 0.05;
      }
    }
    .block {
      display: inline-block;
      width: 4px;
      height: 4px;
      margin-right: 10px;
      vertical-align: middle;
      background: #dadada;
    }
    .selected {
      background-color: #e7f9ef;
      .block {
        background-color: #008e3f;
      }
    }
    .title {
      padding: 0;
      font-weight: 700;
      text-align: center;
      background: #008e3f;
      color: #fff;
      line-height: 36px;
      border-bottom: 0;
    }
    div {
      cursor: pointer;
      // border-bottom: 1px dashed #ededed;
    }
    .colorText {
      color: #144941;
    }
    .textBox {
      line-height: 20px;
      margin-top: 30px;
      p {
        margin-top: 30px;
      }
    }
  }
  .statisticsBox {
    display: flex;
    justify-content: space-between;
    margin-top: 80px;
    text-align: center;
    .statisticsNum {
      font-size: 48px;
    }
    .statisticsTitle {
      margin-top: 10px;
    }
    .circleBox {
      width: 26px;
      height: 26px;
      display: inline-block;
      font-size: 20px;
      line-height: 26px;
      color: #fff;
      background-color: #144941;
      border-radius: 50%;
    }
  }
}
.brandCultureTop {
  background-image: url(@/assets/images/xiehe/about/wenhua_bg.png);
  width: 100%;
  height: 500px;
  padding-top: 55px;
}
.brandCultureTitle {
  font-size: 36px;
  color: #fff;
  font-weight: 700;
  text-align: center;
}
.cultureList {
  display: flex;
  justify-content: space-between;
  width: 100%;
  margin-top: 60px;
}
.cultureItem {
  width: 320px;
  height: 320px;
  background-color: #fff;
  margin-left: 30px;
  padding: 20px;
  box-sizing: border-box;
}
.firstItem {
  background-color: #144941;
  color: #fff;
  width: 320px;
  height: 320px;
  text-align: center;
  margin-left: 0px;
}
.CultureBox {
  width: 1200px;
  margin: 0 auto;
}
.leftIcon {
  width: 58px;
  height: 58px;
  position: relative;
}
.cultureTitle {
  display: flex;
  border-bottom: 1px solid #dedede;
  padding-bottom: 16px;
}
.titleTextInfo {
  margin-left: 20px;
  text-align: left;
}
.itemTitle {
  font-size: 18px;
  font-weight: 700;
  line-height: 36px;
  color: #333;
}
.itemSubTitle {
  color: #000;
  opacity: 0.5;
}
.itemText {
  font-size: 16px;
  line-height: 28px;
  color: #000;
  padding-top: 20px;
}
</style>
src/views/bookStore/detail.vue
New file
@@ -0,0 +1,593 @@
<template>
  <div class="homePage">
    <div class="infoBox">
      <div class="contentBox">
        <div class="crumbs">
          <el-breadcrumb separator-class="el-icon-arrow-right">
            <el-breadcrumb-item :to="{ name: 'bookStore' }">数字教材</el-breadcrumb-item>
            <el-breadcrumb-item>详情</el-breadcrumb-item>
          </el-breadcrumb>
        </div>
        <div class="infoTag" v-if="bookInfo.projectTitle">
          <el-tooltip
            class="item"
            effect="dark"
            :content="bookInfo.projectTitle"
            placement="top-start"
          >
            <div class="tagText">
              {{ bookInfo.projectTitle }}
            </div>
          </el-tooltip>
        </div>
        <div class="bookDetail">
          <div class="bookImg">
            <img class="autoImg" :src="bookInfo.icon" alt="" />
          </div>
          <span class="iconfont icon-tubiaozhizuo"></span>
          <div class="detailBox">
            <div class="bookTitle">
              <div class="bookName" :title="bookInfo.name">
                {{ bookInfo.name }}
              </div>
              <div class="bookTag" :title="bookInfo.seriesName">
                {{ bookInfo.seriesName }}
              </div>
              <div class="collectBox">
                <img
                  @click="collectBook"
                  v-if="bookInfo.isFavourite"
                  class="buyIcon"
                  src="@/assets/images/bookStore/shoucang.svg"
                  style="margin-right: 10px"
                />
                <span
                  @click="collectBook"
                  v-else
                  class="iconfont icon-shoucang"
                  style="margin-right: 10px"
                >
                </span>
                <div class="collectText" @click="collectBook" v-if="bookInfo.isFavourite">
                  已收藏
                </div>
                <div class="collectText" @click="collectBook" v-else>收藏</div>
              </div>
            </div>
            <div class="authorBox">
              <div class="titleBox1">
                <div>作者:</div>
                <div>出版时间:</div>
              </div>
              <div class="valueBox">
                <div>
                  {{ bookInfo.author ? bookInfo.author : '-' }}
                </div>
                <div>
                  {{
                    bookInfo.publicationDate
                      ? moment(bookInfo.publicationDate).format('YYYY-MM-DD')
                      : '-'
                  }}
                </div>
              </div>
              <div class="titleBox1" style="margin-left: 30px">
                <div>ISBN:</div>
                <div>版次:</div>
              </div>
              <div class="valueBox">
                <div>
                  {{ bookInfo.isbn ? bookInfo.isbn : '-' }}
                </div>
                <div>
                  {{ bookInfo.pubNumber ? bookInfo.pubNumber : '-' }}
                </div>
              </div>
            </div>
            <div class="authorBox" style="box-sizing: border-box">
              <div class="titleBox1">
                <div>一级分类:</div>
                <div>二级分类:</div>
              </div>
              <div class="valueBox">
                <div>全国高等职业教育预防医学专业规划教材</div>
                <div>高等职业教育</div>
              </div>
            </div>
            <div class="purchaseBox">
              <div class="priceBox">
                <span v-if="bookInfo.price && bookInfo.price > 0">
                  <span>定价:</span><span>¥</span> <span>{{ bookInfo.price || '-' }}</span
                  ><span v-if="bookInfo.VirtualPrice">原价:¥{{ bookInfo.VirtualPrice }}</span>
                </span>
                <span class="price" v-else>
                  <span class="freePrice">免费</span>
                </span>
              </div>
              <div
                class="buyInfo"
                v-if="
                  (currentRoute !== 'teachingServices' && bookInfo.paperBookDD) ||
                  bookInfo.paperBookJD ||
                  bookInfo.paperBookTmall
                "
              >
                纸质书其他购买渠道:
                <span @click="toJDLink" v-if="bookInfo.paperBookJD">
                  <img class="buyIcon" src="@/assets/images/bookStore/京东icon-01.svg" />京东</span
                >
                <span @click="toDDLink" v-if="bookInfo.paperBookDD"
                  ><img class="buyIcon" src="@/assets/images/bookStore/当当网.svg" />当当</span
                >
                <span @click="toTmLink" v-if="bookInfo.paperBookTmall"
                  ><img
                    class="buyIcon"
                    src="@/assets/images/bookStore/tianmaologo2.svg"
                  />天猫</span
                >
              </div>
            </div>
            <div class="btnBox">
              <el-button
                v-if="
                  currentRoute !== 'teachingServices' &&
                  !bookInfo.alreadyBuy &&
                  bookInfo.isSell &&
                  bookInfo.isSell == '1'
                "
                type="primary"
                :disabled="bookInfo.alreadyBuy"
                @click="gotoOrder"
                >电子书购买</el-button
              >
              <el-button
                v-if="bookInfo.pdfFreeFile && !bookInfo.alreadyBuy"
                type="primary"
                plain
                style="min-width: 98px"
                @click="previewBook"
                >试读</el-button
              >
              <el-button
                v-else-if="bookInfo.pdfFile && bookInfo.alreadyBuy"
                type="primary"
                plain
                style="min-width: 98px"
                @click="previewBook"
                >立即阅读</el-button
              >
              <el-button
                v-if="currentRoute == 'teachingServices' && !bookInfo.alreadyBuy"
                plain
                @click="addEbook"
                >电子样书</el-button
              >
              <el-button v-if="currentRoute == 'teachingServices'" plain @click="addPaperBook"
                >纸质样书</el-button
              >
            </div>
          </div>
        </div>
        <el-dialog title="联系编辑" :visible.sync="contactVisible" width="30%" :lock-scroll="false">
          <div class="contactBox" v-if="bookInfo.editor">
            <div class="contacItem">
              <i class="iconfont icon-renwu-ren contacIcon"></i>
              {{ bookInfo.editor.name }}
            </div>
            <div class="contacItem">
              <i class="iconfont icon-QQ contacIcon"></i>
              {{ bookInfo.editor.qq }}
            </div>
            <div class="contacItem">
              <i class="iconfont icon-tongxunlu contacIcon"></i>
              {{ bookInfo.editor.phone }}
            </div>
            <div class="contacItem">
              <i class="iconfont icon-dianhua contacIcon"></i>
              {{ bookInfo.editor.telephone }}
            </div>
          </div>
          <el-empty v-else description="暂无数据" class="empty" :image-size="100"></el-empty>
        </el-dialog>
        <el-dialog title="信息反馈" :visible.sync="dialogVisible" width="50%" :lock-scroll="false">
          <div class="infoDialog">
            <el-input
              type="textarea"
              :rows="8"
              placeholder="详细描述您所遇到的问题,有助于快速给您反馈!"
              v-model="textarea"
            >
            </el-input>
            <div class="subBtn">
              <el-button type="primary" @click="sendDiscuss">提交</el-button>
            </div>
            <div class="infoList">
              <div class="infoItem" v-for="(item, index) in commentList" :key="index">
                <div class="infoImg">
                  <img v-if="item.icon" class="autoImg" :src="item.icon" alt="" />
                  <i v-else class="el-icon-user-solid"></i>
                </div>
                <div class="infoContent">
                  <div class="infoTitle">
                    <div class="userNameBox">{{ item.content.name }}</div>
                    <div class="userNameBox">
                      {{ moment(item.createDate).format('YYYY-MM-DD') }}
                    </div>
                  </div>
                  <div class="infoText">
                    {{ item.content.content }}
                  </div>
                </div>
              </div>
            </div>
          </div>
        </el-dialog>
      </div>
    </div>
    <div class="detailContent contentBox">
      <div class="resourceBox">
        <div class="tabsBox">
          <el-tabs v-model="editableTabsValue" type="card" class="demo-tabs">
            <el-tab-pane
              v-for="item in editableTabs"
              :key="item.name"
              :label="item.title"
              :name="item.name"
            >
              {{ item.content }}
            </el-tab-pane>
          </el-tabs>
        </div>
        <div v-if="editableTabsValue == '1'" class="textbookInfo">
          <div class="textbookInfoItem">
            <div class="titleBorderBox">图书简介</div>
            <div class="textbookContent"></div>
          </div>
          <div class="textbookInfoItem">
            <div class="titleBorderBox">作者简介</div>
            <div class="authorInfo"></div>
          </div>
        </div>
        <div v-else-if="editableTabsValue == '2'" class="catalogue">bbbb</div>
      </div>
      <div class="recommendBox"></div>
    </div>
  </div>
</template>
<script setup>
import moment from 'moment'
import { ref, onBeforeMount, inject, reactive, onMounted } from 'vue'
const MG = inject('MG')
import { useRouter, useRoute } from 'vue-router'
const route = useRoute()
const router = useRouter()
let bookInfo = ref({})
let digitalTextId = ref('')
let editableTabsValue = ref('1')
const editableTabs = reactive([
  {
    title: '教材信息',
    name: '1',
  },
  {
    title: '目录',
    name: '2',
  },
  {
    title: '配套资源',
    name: '3',
  },
  {
    title: '题库',
    name: '4',
  },
  {
    title: '教师资源',
    name: '5',
  },
  {
    title: '资源统计',
    name: '6',
  },
])
onMounted(() => {
  digitalTextId.value = route.query.bookId
  getBookDetail(digitalTextId.value)
})
const getBookDetail = (id) => {
  const query = {
    path: '*',
    queryType: '*',
    productId: id,
    storeInfo: 'defaultGoodsStore1',
    coverSize: {
      height: 300,
      width: 210,
    },
    fields: {
      author: [],
      isbn: [],
      editionPrinting: [],
      publicationDate: [],
      content: [],
      authorIntroduction: [],
      catalogue: [],
      probationPage: [],
      teachingLevel: [],
      professionalCategory: [],
      executiveEditor: [],
    },
  }
  MG.store.getProductDetail(query).then((res) => {
    console.log(res, 'res')
    bookInfo.value = res.datas
    console.log(res.datas, 'res')
  })
}
</script>
<style lang="less" scoped>
.homePage {
  min-width: 1220px;
  min-height: calc(100vh - 61.8%);
  background-color: #fff;
  padding-bottom: 100px;
}
.infoBox {
  width: 100%;
  height: 530px;
  padding-top: 10px;
  background-color: #fff;
  background-image: url('@/assets/images/xiehe/detail/details_bg.png');
}
.infoTag {
  position: relative;
  width: 0px;
  height: 0px;
  border-right: 20px solid #fff;
  border-left: 503px solid #e50021;
  border-top: 19px solid #e50021;
  border-bottom: 19px solid #e50021;
}
.tagText {
  position: absolute;
  left: -480px;
  top: -9.5px;
  max-width: 480px;
  text-overflow: ellipsis;
  color: #fff;
  font-size: 18px;
  overflow: hidden;
  white-space: nowrap;
}
.bookDetail {
  display: flex;
  overflow: hidden;
  margin-top: 30px;
}
.bookImg {
  position: relative;
  width: 338px;
  height: 400px;
  box-shadow: 2px 2px 10px #f2f2f2;
}
.detailBox {
  flex: 1;
  height: 450px;
  position: relative;
  margin-top: 20px;
  overflow: hidden;
}
.collectBox {
  position: absolute;
  right: 80px;
  font-size: 14px;
  color: #999999;
  cursor: pointer;
}
.collectBox span:nth-child(1) {
  margin-right: 10px;
  font-size: 16px;
}
.collectBox span:nth-child(2) {
  margin-left: 10px;
  margin-right: 10px;
  font-size: 16px;
}
.iconfont {
  font-size: 25px !important;
  vertical-align: middle;
}
.bookTitle {
  width: 100%;
  height: 40px;
  line-height: 40px;
  padding-left: 100px;
  display: flex;
  padding-right: 240px;
  box-sizing: border-box;
}
.collectText {
  font-size: 16px;
  line-height: 25px;
  display: inline-block;
}
.bookName {
  flex: 1;
  font-size: 26px;
  color: #333;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
}
.bookTag {
  max-width: 200px;
  font-size: 16px;
  color: #333;
  line-height: 36px;
  margin-left: 15px;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
}
.authorBox {
  width: 80%;
  display: flex;
  padding: 20px;
  padding-left: 100px;
  position: relative;
}
.valueBox {
  margin-left: 20px;
}
.valueBox div {
  height: 30px;
}
.titleBox1 div {
  height: 30px;
}
.relationBox {
  position: absolute;
  right: 50px;
  color: #999;
  cursor: pointer;
  font-size: 14px;
}
.purchaseBox {
  margin-left: 100px;
  padding-top: 20px;
}
.priceBox {
  border-bottom: 1px dashed #ececec;
  background-color: #b2d9c8;
  height: 50px;
  line-height: 50px;
  padding-left: 20px;
}
.priceBox span:nth-child(1) {
  color: #000;
  font-weight: 700;
  font-size: 16px;
  padding-right: 20px;
}
.priceBox span:nth-child(2) {
  color: #e50021;
  font-size: 16px;
}
.priceBox span:nth-child(3) {
  color: #e50021;
  font-size: 22px;
  font-weight: 700;
  padding-right: 20px;
}
.priceBox span:nth-child(4) {
  color: #333;
  font-size: 16px;
  padding-right: 20px;
  text-decoration: line-through;
}
.buyInfo {
  padding: 20px 0px;
  border-bottom: 1px dashed #ececec;
  cursor: pointer;
}
.buyInfo img {
  margin-left: 10px;
}
.btnBox {
  margin-left: 100px;
  margin-top: 30px;
}
.infoItem {
  display: flex;
  margin-top: 40px;
}
.infoImg {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  border: 1px solid #ccc;
  background: #efefef;
  text-align: center;
  line-height: 60px;
  position: relative;
}
.infoImg i {
  font-size: 28px;
}
.infoList {
  margin-top: 20px;
  overflow: auto;
}
.infoContent {
  flex: 1;
  overflow: hidden;
  padding: 0 20px 0 10px;
}
.infoDialog {
  padding: 20px;
}
.infoTitle {
  width: 100%;
  display: flex;
  justify-content: space-between;
}
.infoText {
  margin-top: 24px;
  line-height: 20px;
}
.contactBox {
  padding: 0px 40px;
}
.contacItem {
  margin-top: 20px;
}
.contacIcon {
  padding-right: 20px;
}
.subBtn {
  margin-top: 20px;
  text-align: right;
}
.buyIcon {
  width: 24px;
  height: 24px;
  vertical-align: middle;
}
.crumbs {
  margin-top: 10px;
  border-bottom: 1px solid rgba(20, 73, 65, 0.26);
  padding-bottom: 20px;
}
.detailContent {
  margin-top: 30px;
  .resourceBox {
    width: 80%;
  }
  .textbookInfo {
    padding: 20px 0;
  }
}
.titleBorderBox {
  height: 30px;
  line-height: 30px;
  font-weight: 700;
  border-left: 6px solid #019e58;
  padding-left: 20px;
  font-size: 18px;
}
.textbookInfoItem {
  margin-top: 20px;
}
</style>
src/views/bookStore/index.vue
New file
@@ -0,0 +1,383 @@
<template>
  <div class="homePage">
    <div class="bannerBox imgBox">
      <img class="bannerImg" :src="banner[0]?.icon" @click="bannerLink(item)" />
      <div class="bannerText">
        <div>数字教材</div>
        <div class="enText">ABOUT US</div>
      </div>
    </div>
    <div class="contentBox" style="margin-top: 50px">
      <div class="imgBox">
        <img class="autoimg" src="@/assets/images/bookStore/feblei.png" />
      </div>
      <div class="classificationBox">
        <div style="width: 100px">分类:</div>
        <div class="classificaListBox">
          <div class="classificaItem" v-for="(item, index) in classfeild" :key="index">
            {{ item.name }}
          </div>
        </div>
      </div>
      <div class="bookList">
        <div class="bookfilterList">
          <div class="listTitle">
            <div>结果:共计***条</div>
            <div style="width: 300px">
              <el-input
                v-model="input3"
                placeholder="输入教材名称、作者姓名、出品方名称搜索"
                class="input-with-select"
              >
                <template #append>
                  <el-button :icon="Search" />
                </template>
              </el-input>
            </div>
          </div>
          <div>
            <div class="recommendList">
              <div
                class="recommendItem"
                v-for="item in bookListData"
                :key="item.id"
                @click="toDetail(item)"
              >
                <div class="recommendItemImg">
                  <img class="autoImg" :src="item.icon" />
                </div>
                <div class="infoBox">
                  <div class="bookName">{{ item.name }}</div>
                  <div class="author">
                    作者:{{ item.authorcaupress_author ? item.caupress_author : '-' }}
                  </div>
                  <div class="priceBox">
                    <span class="oldPrice" v-if="item.oldPrice">原价:¥{{ item.oldPrice }}</span>
                    <span class="price" v-if="item.price && item.price > 0">
                      定价:¥
                      <span>{{ item.price }}</span>
                    </span>
                    <span class="price" v-else> 定价:<span class="freePrice">免费</span> </span>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div v-if="!bookListData.length > 0">
            <el-empty class="noData" description="暂无数据" />
          </div>
          <div class="pagingBox">
            <el-pagination
              layout="total, prev, pager, next"
              :total="total"
              v-model:current-page="currentPage1"
              :page-size="20"
              @current-change="handleCurrentChange"
              hide-on-single-page="true"
            />
          </div>
        </div>
        <div class="recommendBox">
          <div class="recommendTitle">推荐教材</div>
          <div class="newRecommendList">
            <div class="recommendItem" v-for="item in bookListData" :key="item.id">
              <div class="recommendItemImg">
                <img class="autoImg" :src="item.icon" />
              </div>
              <div class="infoBox">
                <div class="bookName">{{ item.name }}</div>
                <div class="author">
                  作者:{{ item.authorcaupress_author ? item.caupress_author : '-' }}
                </div>
                <div class="priceBox">
                  <span class="oldPrice" v-if="item.oldPrice">原价:¥{{ item.oldPrice }}</span>
                  <span class="price" v-if="item.price && item.price > 0">
                    定价:¥
                    <span>{{ item.price }}</span>
                  </span>
                  <span class="price" v-else> 定价:<span class="freePrice">免费</span> </span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref, onBeforeMount, inject, reactive, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
const MG = inject('MG')
const toolClass = inject('toolClass')
const banner = reactive([])
const feildList = reactive([])
const classfeild = reactive([])
import { Search } from '@element-plus/icons-vue'
const input3 = ref('')
let bookListData = ref([])
const total = ref(50)
const currentPage1 = ref(1)
const router = useRouter()
const toDetail = (item) => {
  router.push({
    path: '/bookdetail',
    query: {
      bookId: item.id,
    },
  })
}
const getBanner = () => {
  MG.resource
    .getItem({
      path: 'banner\\educationPublishing',
      fields: { link: [] },
      paging: { start: 0, size: 9 },
    })
    .then((res) => {
      banner.push(...res.datas)
      console.log(res.datas)
    })
}
const handleCurrentChange = (val) => {
  currentPage1.value = val
  getBookList()
}
const getBookList = () => {
  MG.store
    .getProductList({
      path: 'recommendedTextbooks',
      paging: {
        start: 0,
        size: 5,
      },
      fields: {
        author: [],
      },
    })
    .then((res) => {
      console.log(res, '推荐教材')
      bookListData.value = res.datas
    })
}
const classifList = () => {
  const query = {
    refCodes: ['digitalTextbooks'],
  }
  MG.resource.getCmsTypeByRefCode(query).then((res) => {
    console.log(res, 'res')
    const types = toolClass.handleTypeList(res)
    const typeData = types[0].cmsTypeLinks[0].children
    feildList.push(...typeData)
    const temp_classfeild = typeData.find((item) => item.typeField.refCode === 'teachingLevel')
      ?.typeField.cfg.option
    classfeild.push({ name: '全部', value: 'all' }, ...temp_classfeild)
    console.log(typeData, 'typeData')
    console.log(classfeild, 'classfeild')
  })
}
onMounted(() => {
  getBanner()
  classifList()
  getBookList()
})
</script>
<style lang="less" scoped>
.homePage {
  min-width: 1220px;
  min-height: calc(100vh - 61.8%);
  background-color: #fff;
  padding-bottom: 100px;
  .bannerBox {
    height: 380px;
    position: relative;
    .bannerText {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 36px;
      font-weight: 700;
      color: #fff;
      text-shadow: 0px 0px 10px #000000;
      text-align: center;
    }
    .enText {
      font-size: 36px;
      opacity: 0.45;
      margin-top: 20px;
    }
  }
  .classificationBox {
    display: flex;
    justify-content: space-between;
    margin-top: 30px;
    .classificaListBox {
      display: flex;
      flex-wrap: wrap;
      .classificaItem {
        display: flex;
        align-items: center;
        justify-content: center;
        margin-right: 20px;
        margin-bottom: 20px;
        padding: 10px 16px;
        width: 200px;
        line-height: 20px;
        background: #f5f5f5;
        text-align: center;
      }
    }
  }
  .bookList {
    display: flex;
    justify-content: space-between;
    padding: 20px;
    .bookfilterList {
      width: 80%;
      border: 1px solid #e4e7ed;
      height: 100%;
      border-radius: 10px;
      .listTitle {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 20px 30px;
      }
    }
    .recommendBox {
      width: 19%;
      border: 1px solid #e4e7ed;
      border-radius: 10px;
      .recommendTitle {
        height: 50px;
        line-height: 50px;
        padding-left: 20px;
        border-bottom: 1px solid #e4e7ed;
        color: #333333;
        font-weight: 700;
      }
    }
  }
}
.recommendList {
  display: flex;
  padding: 20px;
  padding-top: 0;
  flex-wrap: wrap;
  justify-content: start;
  .recommendItem {
    margin-right: 20px;
    width: 22%;
    height: 300px;
    background-repeat: no-repeat;
    background-size: 100% 100%;
    cursor: pointer;
    border: 1px solid #dedede;
    background-color: #fff;
    padding-top: 10px;
    margin-top: 10px;
    &:last-child {
      margin-right: 0;
    }
  }
  .recommendItemImg {
    width: 150px;
    height: 200px;
    position: relative;
    margin: 0 auto;
  }
  .infoBox {
    text-align: center;
    margin-top: 10px;
  }
  .author {
    margin-top: 10px;
  }
  .priceBox {
    margin-top: 10px;
    .oldPrice {
      font-size: 16px;
      color: #444444;
      text-decoration: line-through;
      margin-right: 20px;
    }
    .price {
      span {
        font-weight: bold;
        font-size: 14px;
      }
    }
  }
}
.newRecommendList {
  padding-top: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  .recommendItem {
    margin-right: 20px;
    height: 300px;
    background-repeat: no-repeat;
    background-size: 100% 100%;
    cursor: pointer;
    background-color: #fff;
    padding-top: 10px;
    margin-top: 10px;
    &:last-child {
      margin-right: 0;
    }
  }
  .recommendItemImg {
    width: 150px;
    height: 200px;
    position: relative;
    margin: 0 auto;
  }
  .infoBox {
    text-align: center;
    margin-top: 10px;
  }
  .author {
    margin-top: 10px;
  }
  .priceBox {
    margin-top: 10px;
    .oldPrice {
      font-size: 16px;
      color: #444444;
      text-decoration: line-through;
      margin-right: 20px;
    }
    .price {
      span {
        font-weight: bold;
        font-size: 14px;
      }
    }
  }
}
.pagingBox {
  display: flex;
  justify-content: center;
  margin: 20px 0;
  padding-bottom: 30px;
}
</style>
src/views/educationalPublishing/index.vue
New file
@@ -0,0 +1,43 @@
<template>
  <div class="homePage">
    <el-carousel :height="screenheight + 'px'">
      <el-carousel-item v-for="(item, index) in banner" :key="index">
        <div class="bannerBox imgBox">
          <img id="autoHeight" class="bannerImg" :src="item.icon" @click="bannerLink(item)" />
        </div>
      </el-carousel-item>
    </el-carousel>
  </div>
</template>
<script setup>
import { ref, onBeforeMount, inject, reactive, onMounted } from 'vue'
const MG = inject('MG')
let screenheight = ref(document.documentElement.clientHeight / 2)
const banner = reactive([])
const getBanner = () => {
  MG.resource
    .getItem({
      path: 'banner\\homeBanner',
      fields: { link: [] },
      paging: { start: 0, size: 9 },
    })
    .then((res) => {
      banner.push(...res.datas)
      console.log(res.datas)
    })
}
onMounted(() => {
  getBanner()
})
</script>
<style lang="less" scoped>
.homePage {
  min-width: 1220px;
  min-height: calc(100vh - 61.8%);
  background-color: #fff;
  padding-bottom: 100px;
}
</style>
src/views/home/index.vue
@@ -1,16 +1,175 @@
<template>
  <div class="homePage">
    <el-carousel :height="screenheight">
      <el-carousel-item v-for="item in 4" :key="item">
        <h3 class="small justify-center" text="2xl">{{ item }}</h3>
    <el-carousel :height="screenheight + 'px'">
      <el-carousel-item v-for="(item, index) in banner" :key="index">
        <div class="bannerBox imgBox">
          <img id="autoHeight" class="bannerImg" :src="item.icon" @click="bannerLink(item)" />
        </div>
      </el-carousel-item>
    </el-carousel>
    <div class="contentBox" style="margin-top: 50px">
      <div class="informationBox">
        <div class="bookListTitle">
          <div class="title">新闻资讯</div>
          <div class="more">更多></div>
        </div>
        <div class="informationList">
          <div class="informationItem" v-for="(item, index) in informationList" :key="index">
            <div class="imgBox"><img class="autoImg" :src="item.icon" alt="" /></div>
            <div class="informationContent">
              <div class="informationTitle" :alt="item.name">{{ item.name }}</div>
              <div class="informationDate">{{ moment(item.publishDate).format('YYYY-MM-DD') }}</div>
              <div class="informationText">{{ item.description }}</div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="bookListBox">
      <div class="contentBox">
        <div class="bookListTitle">
          <div class="title">推荐教材</div>
          <div class="more">更多></div>
        </div>
        <div class="recommendList">
          <div class="recommendItem" v-for="item in bookListData" :key="item.id">
            <div class="recommendItemImg">
              <img class="autoImg" :src="item.icon" />
            </div>
            <div class="infoBox">
              <div class="bookName">{{ item.name }}</div>
              <div class="author">
                作者:{{ item.authorcaupress_author ? item.caupress_author : '-' }}
              </div>
              <div class="priceBox">
                <span class="oldPrice" v-if="item.oldPrice">原价:¥{{ item.oldPrice }}</span>
                <span class="price" v-if="item.price && item.price > 0">
                  定价:¥
                  <span>{{ item.price }}</span>
                </span>
                <span class="price" v-else> 定价:<span class="freePrice">免费</span> </span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="contentBox">
      <div class="funBox">
        <div class="authentication"></div>
        <div class="manual"></div>
      </div>
      <div class="bookListTitle">
        <div class="title" style="display: flex; line-height: 50px">
          <div>新闻资讯</div>
          <div class="titleTabs">
            <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
              <el-tab-pane label="高等职业教材" name="first"> </el-tab-pane>
              <el-tab-pane label="专升本教材" name="second"></el-tab-pane>
              <el-tab-pane label="协和医学院教材" name="third"></el-tab-pane>
            </el-tabs>
          </div>
        </div>
        <div class="more">更多></div>
      </div>
      <div class="recommendList">
        <div class="recommendItem" v-for="item in bookListData" :key="item.id">
          <div class="recommendItemImg">
            <img class="autoImg" :src="item.icon" />
          </div>
          <div class="infoBox">
            <div class="bookName">{{ item.name }}</div>
            <div class="author">
              作者:{{ item.authorcaupress_author ? item.caupress_author : '-' }}
            </div>
            <div class="priceBox">
              <span class="oldPrice" v-if="item.oldPrice">原价:¥{{ item.oldPrice }}</span>
              <span class="price" v-if="item.price && item.price > 0">
                定价:¥
                <span>{{ item.price }}</span>
              </span>
              <span class="price" v-else> 定价:<span class="freePrice">免费</span> </span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref } from 'vue'
let screenheight = ref(document.documentElement.clientHeight / 4)
import moment from 'moment'
import { ref, onBeforeMount, inject, reactive, onMounted } from 'vue'
let screenheight = ref(document.documentElement.clientHeight / 2)
const MG = inject('MG')
const config = inject('config')
const tool = inject('tool')
const banner = reactive([])
const informationList = reactive([])
let bookListData = ref([])
onBeforeMount(() => {
  console.log(document.documentElement.clientWidth / 2.628)
  window.onresize = () => {
    let c = 2.628
    if (document.documentElement.clientWidth >= 1220) {
      screenheight.value = document.documentElement.clientWidth / c
      console.log(document.documentElement.clientWidth / c)
    }
  }
})
onMounted(() => {
  getBanner()
  getInformationList()
  getBookList()
})
const getBookList = () => {
  MG.store
    .getProductList({
      path: 'recommendedTextbooks',
      paging: {
        start: 0,
        size: 5,
      },
      fields: {
        author: [],
      },
    })
    .then((res) => {
      console.log(res, '推荐教材')
      bookListData.value = res.datas
    })
}
const getInformationList = () => {
  MG.resource
    .getItem({
      path: 'information',
      fields: { publishDate: [], content: [] },
      paging: { start: 0, size: 9 },
    })
    .then((res) => {
      informationList.push(...res.datas)
      console.log(res.datas)
    })
}
const getBanner = () => {
  MG.resource
    .getItem({
      path: 'banner\\homeBanner',
      fields: { link: [] },
      paging: { start: 0, size: 9 },
    })
    .then((res) => {
      banner.push(...res.datas)
      console.log(res.datas)
    })
}
</script>
<style lang="less" scoped>
@@ -18,6 +177,7 @@
  min-width: 1220px;
  min-height: calc(100vh - 61.8%);
  background-color: #fff;
  padding-bottom: 100px;
}
.el-carousel__item h3 {
  color: #475669;
@@ -34,4 +194,161 @@
.el-carousel__item:nth-child(2n + 1) {
  background-color: #d3dce6;
}
.informationList {
  display: flex;
  flex-wrap: wrap;
  .informationItem {
    display: flex;
    width: 42%;
    min-height: 100px;
    margin-right: 5%;
    margin-bottom: 20px;
    border: 1px solid #ebebeb;
    border-radius: 10px;
    padding: 10px;
    cursor: pointer;
    .imgBox {
      width: 30%;
      height: 100%;
      position: relative;
    }
    .informationContent {
      width: 70%;
      padding-left: 10px;
      .informationTitle {
        font-size: 14px;
        width: 100%;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        color: #333333;
        font-weight: bold;
        margin-bottom: 10px;
      }
      .informationDate {
        margin-top: 10px;
      }
      .informationText {
        color: #666666;
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        margin-top: 10px;
        display: -webkit-box; /* 将对象作为弹性伸缩盒子模型显示 */
        -webkit-line-clamp: 3; /* 显示的行数 */
        -webkit-box-orient: vertical; /* 设置或检索伸缩盒对象的子元素的排列方式 */
        overflow: hidden; /* 溢出隐藏 */
      }
    }
  }
  .informationItem:hover {
    border: 1px solid #019e58;
  }
}
.bookListBox {
  width: 100%;
  padding: 80px 0;
  margin-top: 30px;
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-image: url('@/assets/images/tuijian-bg.png');
  background-repeat: no-repeat;
  background-size: 100% 100%;
}
.recommendList {
  display: flex;
  padding-top: 20px;
  .recommendItem {
    flex: 1;
    margin-right: 20px;
    height: 300px;
    background-repeat: no-repeat;
    background-size: 100% 100%;
    cursor: pointer;
    border: 1px solid #dedede;
    background-color: #fff;
    padding-top: 10px;
    &:last-child {
      margin-right: 0;
    }
  }
}
.recommendItemImg {
  width: 150px;
  height: 200px;
  position: relative;
  margin: 0 auto;
}
.infoBox {
  text-align: center;
  margin-top: 10px;
}
.author {
  margin-top: 10px;
}
.priceBox {
  margin-top: 10px;
  .oldPrice {
    font-size: 16px;
    color: #444444;
    text-decoration: line-through;
    margin-right: 20px;
  }
  .price {
    span {
      font-weight: bold;
      font-size: 14px;
    }
  }
}
.funBox {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 60px;
  margin-bottom: 60px;
  .authentication {
    width: 40%;
    height: 80px;
    background-repeat: no-repeat;
    background-size: 100% 100%;
    background-image: url('@/assets/images/xiehe/home/jiaoshirenzheng.png');
  }
  .manual {
    width: 40%;
    height: 80px;
    background-repeat: no-repeat;
    background-size: 100% 100%;
    background-image: url('@/assets/images/xiehe/home/jiaoshirenzheng.png');
  }
}
.titleTabs {
  margin-left: 50px;
}
.bookListTitle {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  border-bottom: 1px solid #ebebeb;
  padding-bottom: 20px;
  .title {
    font-size: 20px;
    color: #333333;
    font-weight: bold;
  }
  .more {
    font-size: 14px;
    color: #999999;
    cursor: pointer;
  }
}
</style>