asd123a20 %!s(int64=3) %!d(string=hai) anos
pai
achega
bb5649e25e

+ 1 - 0
.env

@@ -0,0 +1 @@
+VUE_APP_BASEURL=http://127.0.0.1:8001

+ 53 - 0
lib/plug/axios.js

@@ -0,0 +1,53 @@
+/* eslint-disable no-const-assign */
+import axios from 'axios'
+// import router from '../../src/router/index'
+import { Notify } from '@nutui/nutui'
+// 构建axios实例
+axios.create({
+  baseURL: process.env.BASE_API,
+  timeout: 10000
+})
+axios.interceptors.request.use(config => {
+  const token = sessionStorage.getItem('token')
+  if (token) {
+    config.headers.Authorization = 'Bearer ' + token
+  }
+  return config
+},
+err => {
+  return Promise.reject(err)
+})
+axios.interceptors.response.use(
+  response => {
+    if (response.data.errcode !== 0 || response.data.errcode === 403) {
+      if (response.data.errmsg.cmd) {
+        Notify.warn(response.data.errmsg.cmd)
+        return false
+      }
+      Notify.warn(response.data.errmsg)
+      return false
+    }
+    return response.data
+  },
+  error => {
+    const { status, data } = error.response
+    if (status === 401) {
+      Notify.warn('请重新登录')
+      // router.push('/login')
+      return false
+    }
+    if (status === 500) {
+      if (data.cmd) {
+        Notify.warn(data.cmd)
+        return false
+      }
+      if (data.errmsg) {
+        Notify.warn(data.errmsg)
+        return false
+      }
+    }
+    Notify.warn(data.message || data.errmsg)
+    return data
+  }
+)
+export default axios

+ 9 - 0
lib/plug/dict.js

@@ -0,0 +1,9 @@
+const dict = {
+  install (app) {
+    app.config.globalProperties.$dict = function (item) {
+      const dict = this.$store.state.dict
+      return dict[item]
+    }
+  }
+}
+export default dict

+ 7 - 0
lib/plug/setting.js

@@ -0,0 +1,7 @@
+import * as Vue from 'vue'
+const { config } = Vue.createApp({})
+config.weixin = {
+  // baseUrl: process.env.BASE_URL + 'weixin',
+  // baseUrl: `http://${location.host}`
+  
+}

+ 32 - 30
package-lock.json

@@ -1167,6 +1167,16 @@
       "integrity": "sha1-K1o6s/kYzKSKjHVMCBaOPwPrphs=",
       "dev": true
     },
+    "@nutui/nutui": {
+      "version": "3.1.5",
+      "resolved": "https://registry.nlark.com/@nutui/nutui/download/@nutui/nutui-3.1.5.tgz",
+      "integrity": "sha1-JATaRhE3fTeZQlKSr7h5D1oWoZM=",
+      "requires": {
+        "sass": "^1.34.0",
+        "vue": "^3.0.5",
+        "vue-router": "^4.0.4"
+      }
+    },
     "@soda/friendly-errors-webpack-plugin": {
       "version": "1.8.0",
       "resolved": "https://registry.npm.taobao.org/@soda/friendly-errors-webpack-plugin/download/@soda/friendly-errors-webpack-plugin-1.8.0.tgz?cache=0&sync_timestamp=1607927401282&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40soda%2Ffriendly-errors-webpack-plugin%2Fdownload%2F%40soda%2Ffriendly-errors-webpack-plugin-1.8.0.tgz",
@@ -2309,7 +2319,6 @@
       "version": "3.1.2",
       "resolved": "https://registry.npm.taobao.org/anymatch/download/anymatch-3.1.2.tgz",
       "integrity": "sha1-wFV8CWrzLxBhmPT04qODU343hxY=",
-      "dev": true,
       "requires": {
         "normalize-path": "^3.0.0",
         "picomatch": "^2.0.4"
@@ -2545,6 +2554,14 @@
       "integrity": "sha1-1h9G2DslGSUOJ4Ta9bCUeai0HFk=",
       "dev": true
     },
+    "axios": {
+      "version": "0.21.4",
+      "resolved": "https://registry.nlark.com/axios/download/axios-0.21.4.tgz",
+      "integrity": "sha1-xnuQ3AVo5cHPKwuFjEO6KOLtpXU=",
+      "requires": {
+        "follow-redirects": "^1.14.0"
+      }
+    },
     "babel-eslint": {
       "version": "10.1.0",
       "resolved": "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.1.0.tgz?cache=0&sync_timestamp=1611946213770&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-eslint%2Fdownload%2Fbabel-eslint-10.1.0.tgz",
@@ -2713,9 +2730,7 @@
     "binary-extensions": {
       "version": "2.2.0",
       "resolved": "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-2.2.0.tgz?cache=0&sync_timestamp=1610299322955&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbinary-extensions%2Fdownload%2Fbinary-extensions-2.2.0.tgz",
-      "integrity": "sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0=",
-      "dev": true,
-      "optional": true
+      "integrity": "sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0="
     },
     "bindings": {
       "version": "1.5.0",
@@ -3172,8 +3187,6 @@
       "version": "3.5.2",
       "resolved": "https://registry.nlark.com/chokidar/download/chokidar-3.5.2.tgz",
       "integrity": "sha1-26OXb8rbAW9m/TZQIdkWANAcHnU=",
-      "dev": true,
-      "optional": true,
       "requires": {
         "anymatch": "~3.1.2",
         "braces": "~3.0.2",
@@ -3189,8 +3202,6 @@
           "version": "3.0.2",
           "resolved": "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz",
           "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=",
-          "dev": true,
-          "optional": true,
           "requires": {
             "fill-range": "^7.0.1"
           }
@@ -3199,8 +3210,6 @@
           "version": "7.0.1",
           "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz",
           "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=",
-          "dev": true,
-          "optional": true,
           "requires": {
             "to-regex-range": "^5.0.1"
           }
@@ -3208,16 +3217,12 @@
         "is-number": {
           "version": "7.0.0",
           "resolved": "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz",
-          "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=",
-          "dev": true,
-          "optional": true
+          "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss="
         },
         "to-regex-range": {
           "version": "5.0.1",
           "resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz",
           "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=",
-          "dev": true,
-          "optional": true,
           "requires": {
             "is-number": "^7.0.0"
           }
@@ -5958,8 +5963,7 @@
     "follow-redirects": {
       "version": "1.14.3",
       "resolved": "https://registry.nlark.com/follow-redirects/download/follow-redirects-1.14.3.tgz",
-      "integrity": "sha1-atp4EY2NJMruWVWVrM3ArGq9Ai4=",
-      "dev": true
+      "integrity": "sha1-atp4EY2NJMruWVWVrM3ArGq9Ai4="
     },
     "for-in": {
       "version": "1.0.2",
@@ -6048,7 +6052,6 @@
       "version": "2.3.2",
       "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-2.3.2.tgz?cache=0&sync_timestamp=1612536422255&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffsevents%2Fdownload%2Ffsevents-2.3.2.tgz",
       "integrity": "sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro=",
-      "dev": true,
       "optional": true
     },
     "function-bind": {
@@ -6147,7 +6150,6 @@
       "version": "5.1.2",
       "resolved": "https://registry.nlark.com/glob-parent/download/glob-parent-5.1.2.tgz?cache=0&sync_timestamp=1626760235241&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob-parent%2Fdownload%2Fglob-parent-5.1.2.tgz",
       "integrity": "sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ=",
-      "dev": true,
       "requires": {
         "is-glob": "^4.0.1"
       }
@@ -7040,8 +7042,6 @@
       "version": "2.1.0",
       "resolved": "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-2.1.0.tgz",
       "integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=",
-      "dev": true,
-      "optional": true,
       "requires": {
         "binary-extensions": "^2.0.0"
       }
@@ -7169,8 +7169,7 @@
     "is-extglob": {
       "version": "2.1.1",
       "resolved": "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz",
-      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
-      "dev": true
+      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
     },
     "is-fullwidth-code-point": {
       "version": "3.0.0",
@@ -7182,7 +7181,6 @@
       "version": "4.0.1",
       "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz",
       "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=",
-      "dev": true,
       "requires": {
         "is-extglob": "^2.1.1"
       }
@@ -8307,8 +8305,7 @@
     "normalize-path": {
       "version": "3.0.0",
       "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz",
-      "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=",
-      "dev": true
+      "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU="
     },
     "normalize-range": {
       "version": "0.1.2",
@@ -8827,8 +8824,7 @@
     "picomatch": {
       "version": "2.3.0",
       "resolved": "https://registry.nlark.com/picomatch/download/picomatch-2.3.0.tgz",
-      "integrity": "sha1-8fBh3o9qS/AiiS4tEoI0+5gwKXI=",
-      "dev": true
+      "integrity": "sha1-8fBh3o9qS/AiiS4tEoI0+5gwKXI="
     },
     "pify": {
       "version": "4.0.1",
@@ -9920,8 +9916,6 @@
       "version": "3.6.0",
       "resolved": "https://registry.npm.taobao.org/readdirp/download/readdirp-3.6.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freaddirp%2Fdownload%2Freaddirp-3.6.0.tgz",
       "integrity": "sha1-dKNwvYVxFuJFspzJc0DNQxoCpsc=",
-      "dev": true,
-      "optional": true,
       "requires": {
         "picomatch": "^2.2.1"
       }
@@ -10304,6 +10298,14 @@
       "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=",
       "dev": true
     },
+    "sass": {
+      "version": "1.40.0",
+      "resolved": "https://registry.nlark.com/sass/download/sass-1.40.0.tgz?cache=0&sync_timestamp=1631577524998&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsass%2Fdownload%2Fsass-1.40.0.tgz",
+      "integrity": "sha1-/6cQbZwBhRafWwjqqxPWNN75SPI=",
+      "requires": {
+        "chokidar": ">=3.0.0 <4.0.0"
+      }
+    },
     "sax": {
       "version": "1.2.4",
       "resolved": "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz",

+ 2 - 0
package.json

@@ -8,6 +8,8 @@
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
+    "@nutui/nutui": "^3.1.5",
+    "axios": "^0.21.4",
     "core-js": "^3.6.5",
     "vue": "^3.0.0",
     "vue-router": "^4.0.0-0",

+ 1 - 1
public/index.html

@@ -5,7 +5,7 @@
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
-    <title><%= htmlWebpackPlugin.options.title %></title>
+    <title>佳泰医疗健康管理</title>
   </head>
   <body>
     <noscript>

+ 12 - 22
src/App.vue

@@ -1,30 +1,20 @@
 <template>
-  <div id="nav">
-    <router-link to="/">Home</router-link> |
-    <router-link to="/about">About</router-link>
-  </div>
+<div id="app">
   <router-view/>
+</div>
 </template>
 
 <style lang="less">
-#app {
-  font-family: Avenir, Helvetica, Arial, sans-serif;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-  text-align: center;
-  color: #2c3e50;
+html, body, #app{
+  width: 100%;
+  height: 100%;
+  margin: 0;
+  padding: 0;
+  background: #eee;
 }
-
-#nav {
-  padding: 30px;
-
-  a {
-    font-weight: bold;
-    color: #2c3e50;
-
-    &.router-link-exact-active {
-      color: #42b983;
-    }
-  }
+*,
+*::before,
+*::after {
+  box-sizing: border-box;
 }
 </style>

+ 0 - 60
src/components/HelloWorld.vue

@@ -1,60 +0,0 @@
-<template>
-  <div class="hello">
-    <h1>{{ msg }}</h1>
-    <p>
-      For a guide and recipes on how to configure / customize this project,<br>
-      check out the
-      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
-    </p>
-    <h3>Installed CLI Plugins</h3>
-    <ul>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
-    </ul>
-    <h3>Essential Links</h3>
-    <ul>
-      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
-      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
-      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
-      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
-      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
-    </ul>
-    <h3>Ecosystem</h3>
-    <ul>
-      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
-      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
-      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
-      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
-      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
-    </ul>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'HelloWorld',
-  props: {
-    msg: String
-  }
-}
-</script>
-
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped lang="less">
-h3 {
-  margin: 40px 0 0;
-}
-ul {
-  list-style-type: none;
-  padding: 0;
-}
-li {
-  display: inline-block;
-  margin: 0 10px;
-}
-a {
-  color: #42b983;
-}
-</style>

+ 4 - 2
src/main.js

@@ -2,5 +2,7 @@ import { createApp } from 'vue'
 import App from './App.vue'
 import router from './router'
 import store from './store'
-
-createApp(App).use(store).use(router).mount('#app')
+import NutUI from '@nutui/nutui'
+import dict from '@lib/plug/dict'
+import '@nutui/nutui/dist/style.css'
+createApp(App).use(store).use(router).use(NutUI).use(dict).mount('#app')

+ 82 - 7
src/router/index.js

@@ -1,6 +1,19 @@
 import { createRouter, createWebHistory } from 'vue-router'
 import Home from '../views/Home.vue'
-
+import page from '../views/content/pages.vue'
+import list from '../views/content/list.vue'
+import details from '../views/content/details.vue'
+import hospitallList from '../views/medical/hospitallList.vue'
+import hospitalDetails from '../views/medical/hospitalDetails.vue'
+import specialistList from '../views/medical/specialistList.vue'
+import specialistDetails from '../views/medical/specialistDetails.vue'
+import order from '../views/user/order.vue'
+import userInfo from '../views/user/userInfo.vue'
+import orderDetails from '../views/user/orderDetails.vue'
+import register from '../views/register.vue'
+import reserve from '../views/reserve.vue'
+import login from '../views/login.vue'
+import pay from '../views/pay.vue'
 const routes = [
   {
     path: '/',
@@ -8,12 +21,74 @@ const routes = [
     component: Home
   },
   {
-    path: '/about',
-    name: 'About',
-    // route level code-splitting
-    // this generates a separate chunk (about.[hash].js) for this route
-    // which is lazy-loaded when the route is visited.
-    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
+    path: '/page',
+    name: 'page',
+    component: page
+  },
+  {
+    path: '/list',
+    name: 'list',
+    component: list
+  },
+  {
+    path: '/details/:_id',
+    name: 'details',
+    component: details
+  },
+  {
+    path: '/hospitallList',
+    name: 'hospitallList',
+    component: hospitallList
+  },
+  {
+    path: '/hospitalDetails/:_id',
+    name: 'hospitalDetails',
+    component: hospitalDetails
+  },
+  {
+    path: '/specialistList',
+    name: 'specialistList',
+    component: specialistList
+  },
+  {
+    path: '/specialistDetails/:_id',
+    name: 'specialistDetails',
+    component: specialistDetails
+  },
+  {
+    path: '/order',
+    name: 'order',
+    component: order
+  },
+  {
+    path: '/userInfo',
+    name: 'userInfo',
+    component: userInfo
+  },
+  {
+    path: '/orderDetails/:_id',
+    name: 'orderDetails',
+    component: orderDetails
+  },
+  {
+    path: '/register/:path',
+    name: 'register',
+    component: register
+  },
+  {
+    path: '/reserve',
+    name: 'reserve',
+    component: reserve
+  },
+  {
+    path: '/login/:path',
+    name: 'login',
+    component: login
+  },
+  {
+    path: '/pay/:_id',
+    name: 'pay',
+    component: pay
   }
 ]
 

+ 155 - 1
src/store/index.js

@@ -1,11 +1,165 @@
 import { createStore } from 'vuex'
-
+import axios from '@lib/plug/axios.js'
+const uri = '/naf/items/'
+const codes = ['region']
+const api = {
+  pagedetails: '/api/pages/fetch/',
+  contentlist: '/api/content/query',
+  contentfetch: '/api/content/fetch/',
+  hospitalquery: '/api/hospital/query',
+  hospitaldetails: '/api/hospital/fetch/',
+  specialistquery: '/api/specialist/query',
+  specialistdetails: '/api/specialist/fetch/',
+  orderquery: '/api/order/query',
+  orderdetails: '/api/order/fetch/',
+  ordercreate: '/api/order/create',
+  register: '/api/user/create',
+  userquery: '/api/user/query',
+  userupdate: '/api/user/update',
+  subjectquery: '/api/subject/query',
+  orderPay: '/api/weixin/orderPay'
+}
 export default createStore({
   state: {
+    dict: {},
+    pageItem: null,
+    contentList: [],
+    contentItem: null,
+    hospitalList: [],
+    subjectList: [],
+    specialistlList: [],
+    specialistlItem: null,
+    hospitalItem: null,
+    orderList: [],
+    orderItem: []
   },
   mutations: {
+    // 字典
+    setdice (state, { type, list }) {
+      state.dict[type] = list
+    },
+    details (state, payload) {
+      state.pageItem = payload.data
+    },
+    contentlist (state, payload) {
+      state.contentList = payload.data
+    },
+    contentfetch (state, payload) {
+      state.contentItem = payload.data
+    },
+    hospitalquery (state, payload) {
+      state.hospitalList = payload.data
+    },
+    hospitaldetails (state, payload) {
+      state.hospitalItem = payload.data
+    },
+    subjectquery (state, payload) {
+      state.subjectList = payload.data
+    },
+    specialistquery (state, payload) {
+      state.specialistlList = payload.data
+    },
+    specialistdetails (state, payload) {
+      state.specialistlItem = payload.data
+    },
+    orderquery (state, payload) {
+      state.orderList = payload.data
+    },
+    orderdetails (state, payload) {
+      state.orderItem = payload.data
+    }
   },
   actions: {
+    // 字典
+    async init ({ commit }) {
+      codes.filter(async e => {
+        const res = await axios.get(`${uri}${e}/list`)
+        if (res.errcode === 0) {
+          commit('setdice', { type: e, list: res.data })
+        }
+      })
+    },
+    // 单字典
+    async dictinit ({ commit }, e) {
+      const res = await axios.get(`${uri}${e}/list`)
+      if (res.errcode === 0) {
+        commit('setdice', { type: e, list: res.data })
+      }
+      return res
+    },
+    async pagedetails ({ commit }, { code }) {
+      const res = await axios.get(`${api.pagedetails}${code}`)
+      if (res.errcode === 0) commit('details', res)
+      return res
+    },
+    async contentquery ({ commit }, { code }) {
+      const res = await axios.get(`${api.contentlist}`, { params: { column: code } })
+      if (res.errcode === 0) commit('contentlist', res)
+      return res
+    },
+    async contentfetch ({ commit }, { _id }) {
+      const res = await axios.get(`${api.contentfetch}${_id}`)
+      if (res.errcode === 0) commit('contentfetch', res)
+      return res
+    },
+    // 医院
+    async hospitalquery ({ commit }, { region } = {}) {
+      const res = await axios.get(`${api.hospitalquery}`, { params: { region } })
+      if (res.errcode === 0) commit('hospitalquery', res)
+      return res
+    },
+    async hospitaldetails ({ commit }, { _id }) {
+      const res = await axios.get(`${api.hospitaldetails}${_id}`)
+      if (res.errcode === 0) commit('hospitaldetails', res)
+      return res
+    },
+    // 科室
+    async subjectquery ({ commit }, { hospitalId } = {}) {
+      const res = await axios.get(`${api.subjectquery}`, { params: { hospitalId } })
+      if (res.errcode === 0) commit('subjectquery', res)
+      return res
+    },
+    // 专家
+    async specialistquery ({ commit }, { subjectId } = {}) {
+      const res = await axios.get(`${api.specialistquery}`, { params: { subjectId } })
+      if (res.errcode === 0) commit('specialistquery', res)
+      return res
+    },
+    async specialistdetails ({ commit }, { _id }) {
+      const res = await axios.get(`${api.specialistdetails}${_id}`)
+      if (res.errcode === 0) commit('specialistdetails', res)
+      return res
+    },
+    async orderquery ({ commit }, { openid }) {
+      const res = await axios.get(api.orderquery, { params: { openid } })
+      if (res.errcode === 0) commit('orderquery', res)
+      return res
+    },
+    async orderdetails ({ commit }, { _id }) {
+      const res = await axios.get(`${api.orderdetails}${_id}`)
+      if (res.errcode === 0) commit('orderdetails', res)
+      return res
+    },
+    async ordercreate ({ commit }, payload) {
+      const res = await axios.post(api.ordercreate, payload)
+      return res
+    },
+    async orderPay ({ commit }, payload) {
+      const res = await axios.post(api.orderPay, payload)
+      return res
+    },
+    async register ({ commit }, { name, openid, phone }) {
+      const res = await axios.post(`${api.register}`, { name, openid, phone })
+      return res
+    },
+    async userquery ({ commit }, { openid }) {
+      const res = await axios.get(`${api.userquery}`, { params: { openid } })
+      return res
+    },
+    async userupdate ({ commit }, { openid, _id, name, phone }) {
+      const res = await axios.post(`${api.userupdate}`, { openid, _id, name, phone })
+      return res
+    }
   },
   modules: {
   }

+ 0 - 5
src/views/About.vue

@@ -1,5 +0,0 @@
-<template>
-  <div class="about">
-    <h1>This is an about page</h1>
-  </div>
-</template>

+ 2 - 7
src/views/Home.vue

@@ -1,18 +1,13 @@
 <template>
   <div class="home">
-    <img alt="Vue logo" src="../assets/logo.png">
-    <HelloWorld msg="Welcome to Your Vue.js App"/>
+    Home
   </div>
 </template>
 
 <script>
-// @ is an alias to /src
-import HelloWorld from '@/components/HelloWorld.vue'
 
 export default {
   name: 'Home',
-  components: {
-    HelloWorld
-  }
+  components: {}
 }
 </script>

+ 41 - 0
src/views/content/details.vue

@@ -0,0 +1,41 @@
+<template>
+  <div class="details">
+    <h2 class="title">{{ contentItem && contentItem.title }}</h2>
+    <p class="slug">{{ contentItem && contentItem.slug }}</p>
+    <div class="content" v-html="contentItem && contentItem.content"></div>
+  </div>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex'
+export default {
+  name: 'details',
+  components: {},
+  async created () {
+    const _id = this.$route.params._id
+    await this.contentfetch({ _id })
+  },
+  computed: {
+    ...mapState(['contentItem'])
+  },
+  methods: {
+    ...mapActions(['contentfetch'])
+  }
+}
+</script>
+<style lang="less" scoped>
+.title {
+  width: 100%;
+  text-align: center;
+}
+.slug {
+  width: 90%;
+  margin: 2% auto;
+  color: #999;
+  font-size: 0.8em;
+}
+.content {
+  width: 90%;
+  margin: 2% auto;
+}
+</style>

+ 68 - 0
src/views/content/list.vue

@@ -0,0 +1,68 @@
+<template>
+  <div class="list">
+    <div class="box" v-for="(item, index) in contentList" :key="index" @click="btn(item)">
+      <img class="img" :src="item.thumbnail" alt="缩略图">
+      <div class="text">
+        <div class="title">{{ item.title }}</div>
+        <p class="slug">{{ item.slug }}</p>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex'
+export default {
+  name: 'list',
+  components: {},
+  async created () {
+    const uri = window.location.href
+    const temp = uri.split('?')[1]
+    const pram = new URLSearchParams('?' + temp)
+    const code = pram.get('code')
+    await this.contentquery({ code })
+  },
+  computed: {
+    ...mapState(['contentList'])
+  },
+  methods: {
+    ...mapActions(['contentquery']),
+    btn (e) {
+      this.$router.push(`/details/${e._id}`)
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.box {
+  display: flex;
+  width: 90%;
+  margin: 5% auto;
+  padding: 3% 0;
+  border-radius: 15px;
+  background: #fff;
+  .img {
+    width: 25%;
+    margin-right: 5%;
+    margin-left: 5%;
+  }
+  .text {
+    width: 65%;
+    .title {
+      font-size: 1.2em;
+      font-weight: 700;
+      width: 90%;
+      overflow:hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+    .slug {
+      color: #666;
+      width: 90%;
+      overflow:hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+  }
+}
+</style>

+ 37 - 0
src/views/content/pages.vue

@@ -0,0 +1,37 @@
+<template>
+  <div class="pages">
+    <h2 class="title">{{ pageItem && pageItem.title }}</h2>
+    <div class="content" v-html="pageItem && pageItem.content"></div>
+  </div>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex'
+export default {
+  name: 'pages',
+  components: {},
+  async created () {
+    const uri = window.location.href
+    const temp = uri.split('?')[1]
+    const pram = new URLSearchParams('?' + temp)
+    const code = pram.get('code')
+    await this.pagedetails({ code })
+  },
+  computed: {
+    ...mapState(['pageItem'])
+  },
+  methods: {
+    ...mapActions(['pagedetails'])
+  }
+}
+</script>
+<style lang="less" scoped>
+.title {
+  width: 100%;
+  text-align: center;
+}
+.content {
+  width: 90%;
+  margin: 2% auto;
+}
+</style>

+ 45 - 0
src/views/login.vue

@@ -0,0 +1,45 @@
+<template>
+  <div class="login"></div>
+</template>
+
+<script>
+import { mapActions } from 'vuex'
+// const getUrl = process.env.VUE_APP_BASEURL
+export default {
+  name: 'login',
+  data () {
+    return {}
+  },
+  components: {},
+  async mounted () {
+    const path = this.$route.params.path
+    // 判断缓存是否存在
+    const openid = sessionStorage.getItem('openid')
+    if (!openid) {
+      // 调用登录授权
+      const uri = window.location.href
+      // window.location.href = `/api/weixin/getopenid?redirect_uri=${uri}`
+      window.location.replace(`/api/weixin/getopenid?redirect_uri=${uri}`)
+    } else {
+      // 查询用户信息
+      const res = await this.userquery({ openid })
+      if (res.errcode !== 0) return
+      if (res.data.length > 0) {
+        const userinfo = JSON.stringify(res.data[0])
+        sessionStorage.setItem('userinfo', userinfo)
+        // 已注册 跳转要去的页
+        this.$router.push(`/${path}`)
+      } else {
+        // 未注册  跳转注册页
+        this.$router.push(`/register/${path}`)
+      }
+    }
+  },
+  computed: {},
+  methods: {
+    ...mapActions(['getopenid', 'userquery'])
+  }
+}
+</script>
+
+<style lang="less" scoped></style>

+ 40 - 0
src/views/medical/hospitalDetails.vue

@@ -0,0 +1,40 @@
+<template>
+  <div class="details">
+    <img class="img" :src="hospitalItem && hospitalItem.thumbnail">
+    <h2>{{ hospitalItem && hospitalItem.name }}</h2>
+    <p>级别:{{ hospitalItem && hospitalItem.level }}</p>
+    <p>地址:{{ hospitalItem && hospitalItem.address }}</p>
+    <div class="content" v-html="hospitalItem && hospitalItem.content"></div>
+  </div>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex'
+export default {
+  name: 'details',
+  components: {},
+  async created () {
+    const _id = this.$route.params._id
+    await this.hospitaldetails({ _id })
+  },
+  computed: {
+    ...mapState(['hospitalItem'])
+  },
+  methods: {
+    ...mapActions(['hospitaldetails'])
+  }
+}
+</script>
+<style lang="less" scoped>
+.details {
+  width: 90%;
+  margin: 0 auto;
+  .img {
+      width: 100%;
+      margin: 5% auto;
+  }
+  .content {
+    line-height: 1.5em;
+  }
+}
+</style>

+ 68 - 0
src/views/medical/hospitallList.vue

@@ -0,0 +1,68 @@
+<template>
+  <div class="list">
+    <div class="box" v-for="(item, index) in hospitalList" :key="index" @click="btn(item)">
+      <img class="img" :src="item.thumbnail" alt="缩略图">
+      <div class="text">
+        <div class="title">{{ item.name }}</div>
+        <p class="slug">{{ item.address }}</p>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex'
+export default {
+  name: 'list',
+  data () {
+    return {
+      type: null
+    }
+  },
+  async created () {
+    await this.hospitalquery()
+  },
+  computed: {
+    ...mapState(['hospitalList'])
+  },
+  methods: {
+    ...mapActions(['hospitalquery']),
+    btn (e) {
+      this.$router.push(`/hospitalDetails/${e._id}`)
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.box {
+  display: flex;
+  width: 90%;
+  margin: 5% auto;
+  padding: 3% 0;
+  border-radius: 15px;
+  background: #fff;
+  .img {
+    width: 25%;
+    margin-right: 5%;
+    margin-left: 5%;
+  }
+  .text {
+    width: 65%;
+    .title {
+      font-size: 1.2em;
+      font-weight: 700;
+      width: 90%;
+      overflow:hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+    .slug {
+      color: #666;
+      width: 90%;
+      overflow:hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+  }
+}
+</style>

+ 40 - 0
src/views/medical/specialistDetails.vue

@@ -0,0 +1,40 @@
+<template>
+  <div class="details">
+    <img class="img" :src="specialistlItem && specialistlItem.thumbnail">
+    <h2>{{ specialistlItem && specialistlItem.name }}</h2>
+    <p>科室:{{ specialistlItem && specialistlItem.subjectName }}</p>
+    <p>专业:{{ specialistlItem && specialistlItem.ability }}</p>
+    <div class="content" v-html="specialistlItem && specialistlItem.content"></div>
+  </div>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex'
+export default {
+  name: 'details',
+  components: {},
+  async created () {
+    const _id = this.$route.params._id
+    await this.specialistdetails({ _id })
+  },
+  computed: {
+    ...mapState(['specialistlItem'])
+  },
+  methods: {
+    ...mapActions(['specialistdetails'])
+  }
+}
+</script>
+<style lang="less" scoped>
+.details {
+  width: 90%;
+  margin: 0 auto;
+  .img {
+      width: 100%;
+      margin: 5% auto;
+  }
+  .content {
+    line-height: 1.5em;
+  }
+}
+</style>

+ 67 - 0
src/views/medical/specialistList.vue

@@ -0,0 +1,67 @@
+<template>
+  <div class="list">
+    <div class="box" v-for="(item, index) in specialistlList" :key="index" @click="btn(item)">
+      <img class="img" :src="item.thumbnail" alt="缩略图">
+      <div class="text">
+        <div class="title">{{ item.name }}</div>
+        <p class="slug">{{ item.subjectName }}</p>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex'
+export default {
+  name: 'list',
+  data () {
+    return {}
+  },
+  async created () {
+    await this.specialistquery()
+  },
+  computed: {
+    ...mapState(['specialistlList'])
+  },
+  methods: {
+    ...mapActions(['specialistquery']),
+    btn (e) {
+      console.log(e._id)
+      this.$router.push(`/specialistDetails/${e._id}`)
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.box {
+  display: flex;
+  width: 90%;
+  margin: 5% auto;
+  padding: 3% 0;
+  border-radius: 15px;
+  background: #fff;
+  .img {
+    width: 25%;
+    margin-right: 5%;
+    margin-left: 5%;
+  }
+  .text {
+    width: 65%;
+    .title {
+      font-size: 1.2em;
+      font-weight: 700;
+      width: 90%;
+      overflow:hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+    .slug {
+      color: #666;
+      width: 90%;
+      overflow:hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+  }
+}
+</style>

+ 83 - 0
src/views/pay.vue

@@ -0,0 +1,83 @@
+/* eslint-disable vue/valid-v-model */
+<template>
+  <div class="reserve">
+    <nut-input v-model="infos.name" :disabled="true" label="地区"/>
+    <nut-input v-model="infos.hospitalName" :disabled="true" label="医院"/>
+    <nut-input v-model="infos.subjectName" :disabled="true" label="科室"/>
+    <nut-input v-model="infos.specialistName" :disabled="true" label="专家"/>
+    <nut-input v-model="infos.money" :disabled="true" label="金额"/>
+    <nut-input v-model="infos.time" :disabled="true" label="时间"/>
+    <nut-input v-model="infos.status" :disabled="true" label="状态"/>
+    <nut-textarea class="text" :disabled="true" placeholder="备注" v-model="infos.remark" rows="10" autosize />
+    <nut-button class="btn" shape="square" type="success" @click="pay">支付订单</nut-button>
+  </div>
+</template>
+
+<script>
+import { mapActions, mapState } from 'vuex'
+export default {
+  name: 'reserve',
+  data () {
+    return {
+      region: []
+    }
+  },
+  async created () {
+    const _id = this.$route.params._id
+    await this.orderdetails({ _id })
+    // 查地区字典
+    const res = await this.dictinit('region')
+    if (res.errcode === 0) {
+      this.region = this.$dict('region')
+    }
+  },
+  computed: {
+    ...mapState(['orderItem']),
+    infos () {
+      const info = { ...this.orderItem }
+      if (info.status === '0') {
+        info.status = '未付款'
+      } else {
+        info.status = '已付款'
+      }
+      const namelist = this.region.filter(e => e.code === info.code)
+      info.name = namelist[0]?.name
+      return info
+    }
+  },
+  methods: {
+    ...mapActions(['orderdetails', 'orderPay', 'dictinit']),
+    // 支付
+    async pay () {
+      // 预支付订单
+      const res = await this.orderPay(this.orderItem)
+      console.log(res)
+      if (res.errcode === 0) {
+        // 支付
+        window.location.replace('/api/weixin/pay')
+      }
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.reserve {
+  width: 90%;
+  margin: 0 auto;
+  /deep/ .nut-input input {
+    border: none;
+  }
+  .nut-input {
+    width: 100%;
+    margin-top: 2%;
+  }
+  .btn {
+    width: 100%;
+    margin-top: 5%;
+  }
+  .text {
+    width: 100%;
+    margin-top: 5%;
+  }
+}
+</style>

+ 71 - 0
src/views/register.vue

@@ -0,0 +1,71 @@
+<template>
+  <div class="register">
+    <nut-input placeholder="请输入姓名" v-model="info.name" :require-show="true" label="姓名" @clear="clear"/>
+    <nut-input :require-show="true" v-model="info.phone" max-length="11" label="手机号" />
+    <nut-button class="btn" type="success" shape="square" @click="btn">提交</nut-button>
+  </div>
+</template>
+
+<script>
+import { mapActions } from 'vuex'
+import { Toast } from '@nutui/nutui'
+export default {
+  name: 'register',
+  data () {
+    return {
+      info: {
+        name: '',
+        phone: ''
+      },
+      path: null
+    }
+  },
+  components: {},
+  async created () {
+    this.path = this.$route.params.path
+  },
+  computed: {},
+  methods: {
+    ...mapActions(['register']),
+    clear () {
+      this.info.name = null
+    },
+    async btn () {
+      const openid = sessionStorage.getItem('openid')
+      if (this.info.name == null || this.info.name === '') {
+        Toast.fail('请输入姓名')
+        return false
+      }
+      if (this.info.phone == null || this.info.phone === '') {
+        Toast.fail('请输入手机号')
+        return false
+      }
+      if (!openid) {
+        Toast.fail('请返回进行微信授权')
+        return false
+      }
+      this.info.openid = openid
+      const res = await this.register(this.info)
+      if (res.errcode === 0 || !res.errcode) {
+        this.$router.push(`/${this.path}`)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.register {
+  width: 95%;
+  margin: 0 auto;
+  .nut-input {
+    margin: 2% auto;
+  }
+  /deep/ .nut-input input {
+    border: none;
+  }
+  .btn {
+    width: 100%;
+  }
+}
+</style>

+ 184 - 0
src/views/reserve.vue

@@ -0,0 +1,184 @@
+<template>
+  <div class="reserve">
+    <nut-cell title="请选择地区" :desc="desc" @click="show = true"></nut-cell>
+    <nut-picker
+        v-model:visible="show"
+        :list-data="regionList"
+        title="地区选择"
+        @confirm="confirm"
+    ></nut-picker>
+    <nut-cell title="请选择医院" :desc="hospitaltitle" @click="hospitalcell"></nut-cell>
+    <nut-picker
+        v-model:visible="hospitalshow"
+        :list-data="hospitalItems"
+        title="医院选择"
+        @confirm="hospitalConfirm"
+    ></nut-picker>
+    <nut-cell title="请选择科室" :desc="subjecttitle" @click="subjectcell"></nut-cell>
+    <nut-picker
+        v-model:visible="subjectshow"
+        :list-data="subjectItems"
+        title="科室选择"
+        @confirm="subjectConfirm"
+    ></nut-picker>
+    <nut-cell title="请选择专家" :desc="specialistltitle" @click="specialistlcell"></nut-cell>
+    <nut-picker
+      v-model:visible="specialistlshow"
+      :list-data="specialistlItems"
+      title="专家选择"
+      @confirm="specialistlConfirm"
+    ></nut-picker>
+    <nut-input class="money" text-align="right" v-model="info.money" :disabled="true" label="金额"/>
+    <nut-textarea class="text" :disabled="pay" placeholder="请输入备注" v-model="value" rows="10" autosize />
+    <nut-button class="btn" shape="square" type="success" @click="btn">提交订单</nut-button>
+  </div>
+</template>
+
+<script>
+import { mapActions, mapState } from 'vuex'
+import { Toast } from '@nutui/nutui'
+export default {
+  name: 'reserve',
+  data () {
+    return {
+      pay: false,
+      value: '',
+      specialistlshow: false,
+      specialistltitle: null,
+      subjecttitle: null,
+      subjectshow: false,
+      hospitaltitle: null,
+      hospitalshow: false,
+      desc: null,
+      show: false,
+      listData: [],
+      info: {
+        money: '0.00'
+      }
+    }
+  },
+  async created () {
+    const userinfo = sessionStorage.getItem('userinfo')
+    if (!userinfo) {
+      this.$router.push('/login/reserve')
+      return false
+    }
+    const { name, openid, phone } = JSON.parse(userinfo)
+    this.info.name = name
+    this.info.openid = openid
+    this.info.phone = phone
+    // 查地区字典
+    const res = await this.dictinit('region')
+    if (res.errcode === 0) {
+      this.listData = this.$dict('region')
+    }
+  },
+  computed: {
+    ...mapState(['hospitalList', 'subjectList', 'specialistlList']),
+    regionList () {
+      const list = []
+      this.listData.filter(e => list.push(e.name))
+      return list
+    },
+    hospitalItems () {
+      const list = []
+      this.hospitalList.filter(e => list.push(e.name))
+      return list
+    },
+    subjectItems () {
+      const list = []
+      this.subjectList.filter(e => list.push(e.name))
+      return list
+    },
+    specialistlItems () {
+      const list = []
+      this.specialistlList.filter(e => list.push(e.name))
+      return list
+    }
+  },
+  methods: {
+    ...mapActions(['hospitalquery', 'subjectquery', 'specialistquery', 'dictinit', 'ordercreate']),
+    async confirm (e) {
+      this.desc = e
+      this.info.code = this.listData.filter(a => a.name === e)[0].code
+      // 请求医院
+      await this.hospitalquery({ region: this.info.code })
+    },
+    // 医院点击
+    hospitalcell () {
+      if (!this.info.code) {
+        Toast.fail('请先选择地区')
+        return false
+      }
+      this.hospitalshow = true
+    },
+    // 医院选择
+    async hospitalConfirm (e) {
+      this.hospitaltitle = e
+      const { code, name } = this.hospitalList.filter(a => a.name === e)[0]
+      this.info.hospitalId = code
+      this.info.hospitalName = name
+      // 请求科室
+      await this.subjectquery({ hospitalId: code })
+    },
+    // 科室点击
+    subjectcell () {
+      if (!this.info.hospitalId || !this.info.hospitalName) {
+        Toast.fail('请先选择医院')
+        return false
+      }
+      this.subjectshow = true
+    },
+    // 科室选择
+    async subjectConfirm (e) {
+      this.subjecttitle = e
+      const { code, name } = this.subjectList.filter(a => a.name === e)[0]
+      this.info.subjectId = code
+      this.info.subjectName = name
+      // 请求专家
+      await this.specialistquery({ subjectId: code })
+    },
+    // 专家点击
+    specialistlcell () {
+      if (!this.info.subjectId || !this.info.subjectName) {
+        Toast.fail('请先选择科室')
+        return false
+      }
+      this.specialistlshow = true
+    },
+    // 专家选择
+    async specialistlConfirm (e) {
+      this.specialistltitle = e
+      const { code, name, money } = this.specialistlList.filter(a => a.name === e)[0]
+      this.info.specialistId = code
+      this.info.specialistName = name
+      this.info.money = money
+    },
+    // 提交订单
+    async btn () {
+      this.info.remark = this.value
+      const res = await this.ordercreate(this.info)
+      if (res.errcode === 0) {
+        this.$router.push(`/pay/${res.data._id}`)
+      }
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.reserve {
+  width: 90%;
+  margin: 0 auto;
+  /deep/ .nut-input input {
+    border: none;
+  }
+  .text {
+    width: 100%;
+    margin-top: 5%;
+  }
+  .btn {
+    width: 100%;
+    margin-top: 5%;
+  }
+}
+</style>

+ 74 - 0
src/views/user/order.vue

@@ -0,0 +1,74 @@
+<template>
+  <div class="order">
+    <div class="box" v-for="(item, index) in orderList" :key="index" @click="btn(item)">
+      <div class="title">{{ item.name }}</div>
+      <div class="status" :class="item.status === '1' ? 'status1' : 'status2'">{{ item.status === '1' ? '已付款' : '未付款' }}</div>
+      <div class="text">
+        <div class="time">{{ item.time }}</div>
+        <nut-price :price="item.money"  :decimal-digits="3" :need-symbol="true" :thousands="true" />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex'
+export default {
+  name: 'order',
+  data () {
+    return {}
+  },
+  computed: {
+    ...mapState(['orderList'])
+  },
+  async created () {
+    const userinfo = sessionStorage.getItem('userinfo')
+    if (!userinfo) {
+      this.$router.push('/login/order')
+      return false
+    }
+    const { openid } = JSON.parse(userinfo)
+    await this.orderquery({ openid })
+  },
+  methods: {
+    ...mapActions(['orderquery']),
+    btn (e) {
+      this.$router.push(`/orderDetails/${e._id}`)
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.box {
+  width: 90%;
+  margin: 5% auto;
+  background: #fff;
+  padding: 5% 0;
+  border-radius: 5px;
+  .title {
+    font-size: 1.2em;
+    font-weight: 700;
+    text-indent: 1em;
+  }
+  .status {
+    line-height: 2em;
+    text-indent: 1em;
+  }
+  .status1 {
+    color: #00b350;
+  }
+  .status2 {
+    color: #fa2c19;
+  }
+  .text {
+    width: 100%;
+    display: flex;
+    .time {
+      width: 60%;
+      line-height: 2em;
+      text-indent: 1em;
+    }
+  }
+}
+</style>

+ 117 - 0
src/views/user/orderDetails.vue

@@ -0,0 +1,117 @@
+<template>
+  <div class="details">
+    <h2>订单详情</h2>
+    <nut-row>
+      <nut-col :span="12">
+        <div class="flex-content title">姓名:</div>
+      </nut-col>
+      <nut-col :span="12">
+        <div class="flex-content flex-content-light content">{{ orderItem && orderItem.name }}</div>
+      </nut-col>
+    </nut-row>
+    <nut-row>
+      <nut-col :span="12">
+        <div class="flex-content title">手机号:</div>
+      </nut-col>
+      <nut-col :span="12">
+        <div class="flex-content flex-content-light content">{{ orderItem && orderItem.phone }}</div>
+      </nut-col>
+    </nut-row>
+    <nut-row>
+      <nut-col :span="6">
+        <div class="flex-content title">医院名称:</div>
+      </nut-col>
+      <nut-col :span="18">
+        <div class="flex-content flex-content-light content">{{ orderItem && orderItem.hospitalName }}</div>
+      </nut-col>
+    </nut-row>
+    <nut-row>
+      <nut-col :span="12">
+        <div class="flex-content title">科室名称:</div>
+      </nut-col>
+      <nut-col :span="12">
+        <div class="flex-content flex-content-light content">{{ orderItem && orderItem.subjectName }}</div>
+      </nut-col>
+    </nut-row>
+    <nut-row>
+      <nut-col :span="12">
+        <div class="flex-content title">专家名称:</div>
+      </nut-col>
+      <nut-col :span="12">
+        <div class="flex-content flex-content-light content">{{ orderItem && orderItem.specialistName }}</div>
+      </nut-col>
+    </nut-row>
+    <nut-row>
+      <nut-col :span="12">
+        <div class="flex-content title">订单金额:</div>
+      </nut-col>
+      <nut-col :span="12">
+        <div class="flex-content flex-content-light content">{{ orderItem && orderItem.money }}</div>
+      </nut-col>
+    </nut-row>
+    <nut-row>
+      <nut-col :span="12">
+        <div class="flex-content title">订单状态:</div>
+      </nut-col>
+      <nut-col :span="12">
+        <div class="flex-content flex-content-light content">{{ orderItem && orderItem.status === '1' ? '已付款' : '未付款' }}</div>
+      </nut-col>
+    </nut-row>
+    <nut-row>
+      <nut-col :span="12">
+        <div class="flex-content title">订单时间:</div>
+      </nut-col>
+      <nut-col :span="12">
+        <div class="flex-content flex-content-light content">{{ orderItem && orderItem.time }}</div>
+      </nut-col>
+    </nut-row>
+    <nut-row>
+      <nut-col :span="12">
+        <div class="flex-content title">备注:</div>
+      </nut-col>
+      <nut-col :span="12">
+        <div class="flex-content flex-content-light content">{{ orderItem && orderItem.remark }}</div>
+      </nut-col>
+    </nut-row>
+  </div>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex'
+export default {
+  name: 'details',
+  components: {},
+  async created () {
+    const _id = this.$route.params._id
+    await this.orderdetails({ _id })
+  },
+  computed: {
+    ...mapState(['orderItem'])
+  },
+  methods: {
+    ...mapActions(['orderdetails'])
+  }
+}
+</script>
+<style lang="less" scoped>
+.details {
+    width: 90%;
+    margin: 0 auto;
+    h2 {
+      width: 100%;
+      text-align: center;
+    }
+    .nut-row {
+      display: block;
+      margin: 5% auto;
+      font-size: 1em;
+      .title {
+        text-align: left;
+        color: #666;
+      }
+      .content {
+        text-align: right;
+      }
+    }
+}
+</style>

+ 67 - 0
src/views/user/userInfo.vue

@@ -0,0 +1,67 @@
+<template>
+  <div class="userinfo">
+    <nut-input placeholder="请输入姓名" v-model="info.name" :require-show="true" label="姓名" @clear="clear"/>
+    <nut-input :require-show="true" v-model="info.phone" max-length="11" label="手机号" />
+    <nut-button class="btn" type="success" shape="square" @click="btn">提交修改</nut-button>
+  </div>
+</template>
+
+<script>
+import { mapActions } from 'vuex'
+import { Toast } from '@nutui/nutui'
+export default {
+  name: 'register',
+  data () {
+    return {
+      info: {},
+      path: null
+    }
+  },
+  components: {},
+  async created () {
+    const userinfo = sessionStorage.getItem('userinfo')
+    if (!userinfo) {
+      this.$router.push('/login/userInfo')
+      return false
+    }
+    this.info = JSON.parse(userinfo)
+  },
+  computed: {},
+  methods: {
+    ...mapActions(['userupdate']),
+    clear () {
+      this.info.name = null
+    },
+    async btn () {
+      if (this.info.name == null || this.info.name === '') {
+        Toast.fail('请输入姓名')
+        return false
+      }
+      if (this.info.phone == null || this.info.phone === '') {
+        Toast.fail('请输入手机号')
+        return false
+      }
+      const res = await this.userupdate(this.info)
+      console.log(res)
+      if (res.errcode === 0 || !res.errcode) Toast.success('修改成功')
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.userinfo {
+  width: 90%;
+  margin: 5% auto;
+  .nut-input {
+    margin-top: 5%;
+  }
+  /deep/ .nut-input input {
+    border: none;
+  }
+  .btn {
+    width: 100%;
+    margin-top: 5%;
+  }
+}
+</style>

+ 12 - 7
vue.config.js

@@ -1,6 +1,5 @@
+const baseUrl = '/yl-web'
 const path = require('path')
-const baseUrl = '/admin'
-
 const frameSrc = path.resolve(__dirname)
 module.exports = {
   publicPath: baseUrl,
@@ -8,18 +7,16 @@ module.exports = {
   configureWebpack: {
     resolve: {
       alias: {
-        '@frame': frameSrc,
-        '@naf': path.join(frameSrc, '/naf'),
         '@lib': path.join(frameSrc, '/lib')
       }
     }
   },
   devServer: {
-    port: 4000,
+    port: 3000,
     proxy: {
       '/api/': {
-        target: 'http://localhost:8001'
-        // target: 'http://192.168.4.1:7001'
+        target: 'http://192.168.0.81:8001'
+        // target: 'http://medical.cc-lotus.info'
       },
       '/tyylfiles/': {
         target: 'http://localhost:8009',
@@ -28,6 +25,14 @@ module.exports = {
       },
       '/files/tyyl/': {
         target: 'http://localhost:8006'
+      },
+      '/auth': {
+        target: 'http://wx.cc-lotus.info',
+        pathRewrite: { '^/auth': '/api/auth' }
+      },
+      '/naf/': {
+        target: 'http://localhost:8002'
+        // target: 'http://192.168.4.1:7001'
       }
     }
   }