YY 3 anni fa
commit
e5a786aab4
100 ha cambiato i file con 7129 aggiunte e 0 eliminazioni
  1. 3 0
      .env
  2. 33 0
      .eslintrc.js
  3. 24 0
      .gitignore
  4. 24 0
      README.md
  5. 3 0
      babel.config.js
  6. 64 0
      package.json
  7. BIN
      public/favicon.ico
  8. 17 0
      public/index.html
  9. BIN
      public/数据模板.xlsx
  10. 24 0
      src/App.vue
  11. BIN
      src/assets/fmzl.jpg
  12. BIN
      src/assets/icon.jpg
  13. BIN
      src/assets/kjpx.jpg
  14. BIN
      src/assets/logo.png
  15. BIN
      src/assets/noimage.jpg
  16. BIN
      src/assets/user.jpg
  17. BIN
      src/assets/userbj.jpg
  18. 88 0
      src/components/HelloWorld.vue
  19. 69 0
      src/components/c-select.vue
  20. 74 0
      src/components/footers.vue
  21. 17 0
      src/components/vForm.md
  22. 103 0
      src/components/vForm.vue
  23. 61 0
      src/components/vcheckbox.vue
  24. 67 0
      src/components/vdate.vue
  25. 61 0
      src/components/vselect copy.vue
  26. 62 0
      src/components/vselect.vue
  27. 55 0
      src/components/vupload.vue
  28. 285 0
      src/layout/chatCommon/chat.vue
  29. 88 0
      src/layout/common/admin-frame.vue
  30. 42 0
      src/layout/common/footers.vue
  31. 47 0
      src/layout/common/page.vue
  32. 7 0
      src/layout/common/top.md
  33. 127 0
      src/layout/common/top.vue
  34. 148 0
      src/layout/list/cashing/model-1.vue
  35. 145 0
      src/layout/list/cashing/model-2.vue
  36. 145 0
      src/layout/list/cashing/model-3.vue
  37. 72 0
      src/layout/list/model-1.vue
  38. 70 0
      src/layout/list/model-2.vue
  39. 99 0
      src/layout/list/model-3.vue
  40. 123 0
      src/layout/list/model-4.vue
  41. 98 0
      src/layout/list/model-5.vue
  42. 101 0
      src/layout/list/model-6.vue
  43. 100 0
      src/layout/login/login-1.vue
  44. 57 0
      src/layout/login/login-2.vue
  45. 97 0
      src/layout/login/register-1.vue
  46. 90 0
      src/layout/login/register-2.vue
  47. 26 0
      src/main.js
  48. 19 0
      src/plugins/axios.js
  49. 37 0
      src/plugins/check-res.js
  50. 11 0
      src/plugins/components.js
  51. 63 0
      src/plugins/couindex.js
  52. 5 0
      src/plugins/element.js
  53. 27 0
      src/plugins/loading.js
  54. 4 0
      src/plugins/meta.js
  55. 20 0
      src/plugins/setting.js
  56. 65 0
      src/plugins/stomp.js
  57. 5 0
      src/plugins/vant.js
  58. 3 0
      src/plugins/weixin.js
  59. 566 0
      src/router/index.js
  60. 122 0
      src/store/index.js
  61. 46 0
      src/store/live/cashing.js
  62. 43 0
      src/store/live/coupons.js
  63. 43 0
      src/store/live/couponsApply.js
  64. 43 0
      src/store/live/declare.js
  65. 58 0
      src/store/live/mechanism.js
  66. 43 0
      src/store/live/reward.js
  67. 25 0
      src/store/upload.js
  68. 117 0
      src/util/axios-wrapper.js
  69. 50 0
      src/util/methods-util.js
  70. 69 0
      src/util/user-util.js
  71. 84 0
      src/views/company/business/detail.vue
  72. 99 0
      src/views/company/business/index.vue
  73. 167 0
      src/views/company/innovate/achieve/index.vue
  74. 135 0
      src/views/company/innovate/achieve/parts/basic.vue
  75. 46 0
      src/views/company/innovate/achieve/parts/brief.vue
  76. 173 0
      src/views/company/innovate/achieve/parts/datalist.vue
  77. 186 0
      src/views/company/innovate/achieve/parts/research.vue
  78. 40 0
      src/views/company/innovate/achieve/parts/top.vue
  79. 80 0
      src/views/company/innovate/index.vue
  80. 36 0
      src/views/company/innovate/novelty/index.vue
  81. 84 0
      src/views/company/market/detail.vue
  82. 99 0
      src/views/company/market/index.vue
  83. 145 0
      src/views/company/parts/detail_1.vue
  84. 122 0
      src/views/company/parts/detail_2.vue
  85. 113 0
      src/views/company/parts/detail_3.vue
  86. 84 0
      src/views/company/parts/list_1.vue
  87. 81 0
      src/views/company/parts/list_2.vue
  88. 84 0
      src/views/company/parts/list_3.vue
  89. 84 0
      src/views/company/patent/detail.vue
  90. 97 0
      src/views/company/patent/index.vue
  91. 61 0
      src/views/exchange/business/detail.vue
  92. 76 0
      src/views/exchange/business/index.vue
  93. 105 0
      src/views/exchange/center copy/basic/index.vue
  94. 110 0
      src/views/exchange/center copy/index.vue
  95. 68 0
      src/views/exchange/center copy/parts/basic-1.vue
  96. 104 0
      src/views/exchange/center copy/parts/company-1.vue
  97. 91 0
      src/views/exchange/center copy/parts/user-1.vue
  98. 88 0
      src/views/exchange/center copy/user/index.vue
  99. 87 0
      src/views/exchange/center/adminCenter/mechanism/detail.vue
  100. 0 0
      src/views/exchange/center/adminCenter/mechanism/index.vue

+ 3 - 0
.env

@@ -0,0 +1,3 @@
+VUE_APP_AXIOS_BASE_URL = ''
+VUE_APP_ROUTER="jlstcompany"
+VUE_APP_HOST="http://broadcast.kqyjy.com"

+ 33 - 0
.eslintrc.js

@@ -0,0 +1,33 @@
+// https://eslint.org/docs/user-guide/configuring
+
+module.exports = {
+  root: true,
+  env: {
+    node: true,
+  },
+  extends: ['plugin:vue/essential', '@vue/prettier'],
+  plugins: ['vue'],
+  rules: {
+    'max-len': [
+      'warn',
+      {
+        code: 500,
+      },
+    ],
+    'no-unused-vars': 'off',
+    'no-console': 'off',
+    'prettier/prettier': [
+      'warn',
+      {
+        singleQuote: true,
+        trailingComma: 'es5',
+        bracketSpacing: true,
+        jsxBracketSameLine: true,
+        printWidth: 160,
+      },
+    ],
+  },
+  parserOptions: {
+    parser: 'babel-eslint',
+  },
+};

+ 24 - 0
.gitignore

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

+ 24 - 0
README.md

@@ -0,0 +1,24 @@
+# cysci-mobile
+
+## Project setup
+```
+npm install
+```
+
+### Compiles and hot-reloads for development
+```
+npm run serve
+```
+
+### Compiles and minifies for production
+```
+npm run build
+```
+
+### Lints and fixes files
+```
+npm run lint
+```
+
+### Customize configuration
+See [Configuration Reference](https://cli.vuejs.org/config/).

+ 3 - 0
babel.config.js

@@ -0,0 +1,3 @@
+module.exports = {
+  presets: ["@vue/cli-plugin-babel/preset"],
+};

+ 64 - 0
package.json

@@ -0,0 +1,64 @@
+{
+  "name": "jlst-company",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "@stomp/stompjs": "^6.1.0",
+    "axios": "^0.21.1",
+    "core-js": "^3.6.5",
+    "echarts": "^5.1.1",
+    "element": "^0.1.4",
+    "element-ui": "^2.15.1",
+    "jsonwebtoken": "^8.5.1",
+    "lodash": "^4.17.21",
+    "moment": "^2.29.1",
+    "naf-core": "^0.1.2",
+    "vant": "^2.12.15",
+    "vue": "^2.6.11",
+    "vue-meta": "^2.4.0",
+    "vue-router": "^3.2.0",
+    "vuex": "^3.4.0",
+    "weixin-js-sdk": "^1.6.0"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-plugin-router": "~4.5.0",
+    "@vue/cli-plugin-vuex": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "@vue/eslint-config-prettier": "^6.0.0",
+    "babel-eslint": "^10.1.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-prettier": "^3.3.1",
+    "eslint-plugin-vue": "^6.2.2",
+    "less": "^3.0.4",
+    "less-loader": "^5.0.0",
+    "prettier": "^2.2.1",
+    "vue-template-compiler": "^2.6.11"
+  },
+  "eslintConfig": {
+    "root": true,
+    "env": {
+      "node": true
+    },
+    "extends": [
+      "plugin:vue/essential",
+      "eslint:recommended",
+      "@vue/prettier"
+    ],
+    "parserOptions": {
+      "parser": "babel-eslint"
+    },
+    "rules": {}
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not dead"
+  ]
+}

BIN
public/favicon.ico


+ 17 - 0
public/index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title>加载中...</title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

BIN
public/数据模板.xlsx


+ 24 - 0
src/App.vue

@@ -0,0 +1,24 @@
+<template>
+  <div id="app">
+    <router-view />
+  </div>
+</template>
+
+<script>
+export default {
+  created() {},
+  methods: {},
+};
+</script>
+
+<style lang="less">
+p {
+  padding: 0;
+  margin: 0;
+}
+.textOver {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+</style>

BIN
src/assets/fmzl.jpg


BIN
src/assets/icon.jpg


BIN
src/assets/kjpx.jpg


BIN
src/assets/logo.png


BIN
src/assets/noimage.jpg


BIN
src/assets/user.jpg


BIN
src/assets/userbj.jpg


+ 88 - 0
src/components/HelloWorld.vue

@@ -0,0 +1,88 @@
+<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>

+ 69 - 0
src/components/c-select.vue

@@ -0,0 +1,69 @@
+<template>
+  <div id="c-select">
+    <van-cell :title="label" @click="show = true">
+      <span v-if="mval" style="color: #000">{{ mval }}</span>
+      <span v-else>{{ `请选择${label}` }}</span>
+    </van-cell>
+    <van-popup v-model="show" show-toolbar position="bottom">
+      <van-picker v-if="type === 'select'" :value-key="valueKey" :title="label" show-toolbar :columns="list" @confirm="onConfirm" @cancel="show = false" />
+      <van-checkbox-group v-model="multi" v-else>
+        <van-picker :title="label" :show-toolbar="true" :columns="list" @confirm="onConfirm" @cancel="show = false">
+          <template #option="item">
+            <van-checkbox :name="item">{{ item }}</van-checkbox>
+          </template>
+        </van-picker>
+      </van-checkbox-group>
+    </van-popup>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+export default {
+  name: 'c-select',
+  props: {
+    label: { type: String },
+    mval: { type: String },
+    list: { type: Array, default: () => [] },
+    type: { type: String },
+    valueKey: { type: String },
+  },
+  model: {
+    prop: 'mval',
+    event: 'change',
+  },
+  components: {},
+  data: function () {
+    return {
+      show: false,
+      selectList: [],
+      multi: [],
+    };
+  },
+  created() {},
+  methods: {
+    onConfirm(value) {
+      if (this.type === 'select') this.$emit('change', value);
+      else {
+        const str = this.multi.join(',');
+        this.$emit('change', str);
+      }
+      this.show = false;
+    },
+  },
+  computed: {
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+/deep/.van-cell__value {
+  text-align: left;
+}
+</style>

+ 74 - 0
src/components/footers.vue

@@ -0,0 +1,74 @@
+<template>
+  <div id="footers">
+    <van-grid :column-num="list.length" clickable>
+      <van-grid-item v-for="(i, index) in list" :key="`menu-${index}`" :text="i.label" :to="i.router" />
+    </van-grid>
+  </div>
+</template>
+
+<script>
+import { mapState, mapGetters, mapMutations, createNamespacedHelpers } from 'vuex';
+const { mapActions: column } = createNamespacedHelpers('column');
+export default {
+  name: 'footers',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      list: [],
+    };
+  },
+  mounted() {
+    this.initMenu();
+  },
+  methods: {
+    ...column(['query']),
+    ...mapMutations(['setMenu']),
+    async initMenu() {
+      let columns = sessionStorage.getItem('columns');
+      if (!columns) {
+        let res = await this.getColumns();
+        columns = res;
+      }
+      columns = JSON.parse(columns);
+      this.setMenu(columns);
+      this.$set(this, `list`, this.getMenu(this.keyWord));
+    },
+    async getColumns() {
+      const res = await this.query();
+      if (this.$checkRes(res)) {
+        sessionStorage.setItem('columns', JSON.stringify(res.data));
+        return JSON.stringify(res.data);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    ...mapGetters(['getMenu']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    keyWord() {
+      return this.$route.meta.key;
+    },
+  },
+  watch: {
+    $route: {
+      handler(to, form) {
+        this.initMenu();
+      },
+      deep: true,
+      immediate: true,
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+/deep/.van-grid-item__content {
+  padding: 11px 8px;
+}
+</style>

+ 17 - 0
src/components/vForm.md

@@ -0,0 +1,17 @@
+# vForm
+
+|属性名|数据类型|默认值|是否必要|描述|
+|:--:|:--:|:--:|:--:|:--:|
+|v-model|Object|`-`|true|存放值的地方(不知道咋解释好,┓( ´∀` )┏)|
+|fields|Array|`[]`|`-`|字段|
+
+### fields
+|属性名|数据类型|默认值|是否必要|描述|
+|:--:|:--:|:--:|:--:|:--:|
+|label|String|`-`|false|字段中文/XX文|
+|model|String|`-`|true|字段在数据库的key,不写就别用了,(╯‵□′)╯︵┻━┻|
+|rules|Array|`[]`|false|输入类型的验证,validator写法,不懂百度|
+|required|Boolean|`-`|false|是否必填/选|
+|type|String|`-`|false|本字段类型:input,select,date....|
+|selectKey|String|`-`|=>|若type为select类型,必填,表示在选择的时候,看哪个字段的内容|
+|selectProp|String|`-`|=>|若type为select类型,表示在选择的时候,选择哪个字段,若没有值,则选择这个object|

+ 103 - 0
src/components/vForm.vue

@@ -0,0 +1,103 @@
+<template>
+  <div id="vForm">
+    <van-form @submit="onSubmit">
+      <template v-for="(f, fi) in fields">
+        <template v-if="!f.type || f.type === 'input'">
+          <van-field
+            :key="`${fi}.${f.model}`"
+            v-model="value[f.model]"
+            :label="f.label"
+            :placeholder="`${f.label}`"
+            :rules="f.rules ? f.rules : []"
+            :required="f.required"
+          />
+        </template>
+        <template v-if="f.type === 'date'">
+          <v-date :key="`${fi}.${f.model}`" v-model="value[f.model]" :label="f.label" :required="f.required"></v-date>
+        </template>
+        <template v-if="f.type === 'select'">
+          <v-select
+            :key="`${fi}.${f.model}`"
+            v-model="value[f.model]"
+            :label="f.label"
+            :list="getSelectList(f.model)"
+            :labelKey="f.selectKey"
+            :prop="f.selectProp"
+            :required="f.required"
+          ></v-select>
+        </template>
+        <template v-if="f.type === 'textarea'">
+          <van-field
+            :key="`${fi}.${f.model}`"
+            v-model="value[f.model]"
+            :label="f.label"
+            rows="2"
+            autosize
+            type="textarea"
+            :placeholder="`请输入${f.label}`"
+            :required="f.required"
+          />
+        </template>
+      </template>
+      <div style="margin: 16px">
+        <van-button round block type="info" native-type="submit">提交</van-button>
+      </div>
+    </van-form>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import vDate from '@/components/vdate.vue';
+import vSelect from '@/components/vselect.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'vForm',
+  props: {
+    value: { type: Object, required: true },
+    fields: { type: Array, default: () => [] },
+  },
+
+  components: { vDate, vSelect },
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    onSubmit() {
+      // 进入submit后,只能说明,有rules的是按要求输入的,其余的select,date还未验证,需要此处验证
+      const needCheck = this.fields.filter((f) => f.required);
+      const checkResult = this.checkRequired(needCheck);
+      if (!checkResult) return;
+      this.$emit('submit', _.cloneDeep(this.value));
+    },
+    checkRequired(checkList) {
+      let res = true;
+      for (const field of checkList) {
+        const { model, label } = field;
+        if (!this.value[model]) {
+          this.$toast({ type: 'fail', message: `请完善${label}项` });
+          res = false;
+          break;
+        }
+      }
+      return res;
+    },
+    getSelectList(model) {
+      const selectList = _.get(this.$attrs, `${model}List`, []);
+      return selectList;
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 61 - 0
src/components/vcheckbox.vue

@@ -0,0 +1,61 @@
+<template>
+  <div id="vcheckbox">
+    <van-field :value="display" :label="label" :placeholder="`请选择${label}`" readonly @click="show = true" />
+    <van-popup v-model="show" show-toolbar position="bottom">
+      <van-picker :title="label" show-toolbar :value-key="labelKey" :columns="list" @confirm="onConfirm" @cancel="show = false" />
+    </van-popup>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'vcheckbox',
+  props: {
+    label: { type: String }, //字段中文
+    mval: { type: String }, //v-model
+    list: { type: Array }, //选择的列表
+    labelKey: { type: String, default: 'name' }, //如果选项为object,选择哪个字段作为显示的选项
+    prop: { type: String }, // 如果选项为object,选择哪个字段作为v-model的值,没有的话就把该项作为值给v-model
+  },
+  model: {
+    prop: 'mval',
+    event: 'change',
+  },
+  components: {},
+  data: function () {
+    return {
+      show: false,
+    };
+  },
+  created() {},
+  methods: {
+    onConfirm(value) {
+      if (this.prop) this.$emit('change', _.get(value, this.prop));
+      else this.$emit('change', value);
+      this.show = false;
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    display() {
+      let value = '';
+      if (this.mval) value = this.mval;
+      if (this.prop) {
+        const r = this.list.find((f) => f[this.prop] === value);
+        if (r) value = r[this.labelKey];
+      }
+      return value;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 67 - 0
src/components/vdate.vue

@@ -0,0 +1,67 @@
+<template>
+  <div id="vdate">
+    <van-field :value="mval" :label="label" :placeholder="`请选择${label}`" readonly @click="show = true" :required="required" />
+    <van-popup v-model="show" show-toolbar position="bottom">
+      <van-datetime-picker
+        :value="cdate"
+        type="date"
+        :title="`请选择${label}`"
+        :min-date="minDate"
+        :max-date="maxDate"
+        @cancel="show = false"
+        @confirm="toConfirm"
+      />
+    </van-popup>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+const moment = require('moment');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'vdate',
+  props: {
+    label: { type: String }, //字段中文
+    mval: { type: String }, //v-model
+    required: { type: Boolean, default: false },
+  },
+  model: {
+    prop: 'mval',
+    event: 'change',
+  },
+  components: {},
+  data: function () {
+    return {
+      show: false,
+      minDate: new Date(1990, 0, 1),
+      maxDate: new Date(),
+    };
+  },
+  created() {},
+  methods: {
+    toConfirm(val) {
+      this.$emit('change', moment(val).format('YYYY-MM-DD'));
+      this.show = false;
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    cdate() {
+      let date = '';
+      if (this.mval) {
+        date = new Date(this.mval);
+      }
+      return date;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 61 - 0
src/components/vselect copy.vue

@@ -0,0 +1,61 @@
+<template>
+  <div id="vselect">
+    <van-field :value="display" :label="label" :placeholder="`请选择${label}`" readonly @click="show = true" />
+    <van-popup v-model="show" show-toolbar position="bottom">
+      <van-picker :title="label" show-toolbar :value-key="labelKey" :columns="list" @confirm="onConfirm" @cancel="show = false" />
+    </van-popup>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'vselect',
+  props: {
+    label: { type: String }, //字段中文
+    mval: { type: String }, //v-model
+    list: { type: Array }, //选择的列表
+    labelKey: { type: String, default: 'name' }, //如果选项为object,选择哪个字段作为显示的选项
+    prop: { type: String }, // 如果选项为object,选择哪个字段作为v-model的值,没有的话就把该项作为值给v-model
+  },
+  model: {
+    prop: 'mval',
+    event: 'change',
+  },
+  components: {},
+  data: function () {
+    return {
+      show: false,
+    };
+  },
+  created() {},
+  methods: {
+    onConfirm(value) {
+      if (this.prop) this.$emit('change', _.get(value, this.prop));
+      else this.$emit('change', value);
+      this.show = false;
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    display() {
+      let value = '';
+      if (this.mval) value = this.mval;
+      if (this.prop) {
+        const r = this.list.find((f) => f[this.prop] === value);
+        if (r) value = r[this.labelKey];
+      }
+      return value;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 62 - 0
src/components/vselect.vue

@@ -0,0 +1,62 @@
+<template>
+  <div id="vselect">
+    <van-field :value="display" :label="label" :placeholder="`请选择${label}`" readonly @click="show = true" :required="required" />
+    <van-popup v-model="show" show-toolbar position="bottom">
+      <van-picker :title="label" show-toolbar :value-key="labelKey" :columns="list" @confirm="onConfirm" @cancel="show = false" />
+    </van-popup>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'vselect',
+  props: {
+    label: { type: String }, //字段中文
+    mval: { type: String }, //v-model
+    list: { type: Array }, //选择的列表
+    labelKey: { type: String, default: 'name' }, //如果选项为object,选择哪个字段作为显示的选项
+    prop: { type: String }, // 如果选项为object,选择哪个字段作为v-model的值,没有的话就把该项作为值给v-model
+    required: { type: Boolean, default: false },
+  },
+  model: {
+    prop: 'mval',
+    event: 'change',
+  },
+  components: {},
+  data: function () {
+    return {
+      show: false,
+    };
+  },
+  created() {},
+  methods: {
+    onConfirm(value) {
+      if (this.prop) this.$emit('change', _.get(value, this.prop));
+      else this.$emit('change', value);
+      this.show = false;
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    display() {
+      let value = '';
+      if (this.mval) value = this.mval;
+      if (this.prop) {
+        const r = this.list.find((f) => f[this.prop] === value);
+        if (r) value = r[this.labelKey];
+      }
+      return value;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 55 - 0
src/components/vupload.vue

@@ -0,0 +1,55 @@
+<template>
+  <div id="vupload">
+    <van-uploader :fileList="fileList" :after-read="upload" accept="*" @delete="toDelete" />
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import axios from 'axios';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'vupload',
+  props: {
+    fileList: { type: Array },
+    url: { type: String, required: true },
+  },
+  model: {
+    prop: 'fileList',
+    event: 'change',
+  },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    async upload({ file }) {
+      let formdata = new FormData();
+      formdata.append('file', file, file.name);
+      const res = await axios.post(this.url, formdata, { headers: { 'Content-Type': 'multipart/form-data' } });
+      if (res.status === 200 && res.data.errcode == 0) {
+        const { id, name, uri } = res.data;
+        const obj = { name, url: uri };
+        this.fileList.push(obj);
+      }
+    },
+    toDelete(file) {
+      console.log(file);
+      const index = this.fileList.findIndex((f) => _.isEqual(f, file));
+      if (index > -1) this.fileList.splice(index, 1);
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 285 - 0
src/layout/chatCommon/chat.vue

@@ -0,0 +1,285 @@
+<template>
+  <div id="chat">
+    <van-row>
+      <van-col span="24" class="main">
+        <van-col span="24" class="one" :style="{ height: client.height - 87 + 'px' }">
+          <template v-for="(i, index) in list">
+            <template v-if="isSender(i, index)">
+              <van-col span="24" class="senderTime" :key="`div${i.id}${index}`">
+                <span :key="`senderTime${i.id}${index}`">[{{ i.send_time }}] {{ i.sender_name }}</span>
+                <span v-if="i.type == '1'" v-html="i.content" :key="`senderContent${i.id}${index}`"></span>
+                <span v-else-if="i.type == '2'">
+                  {{ getFile(i.file) }}<van-button type="info" size="mini" class="downBtn" @click="downFile(i.file)">下载</van-button>
+                </span>
+              </van-col>
+            </template>
+            <template v-else>
+              <van-col span="24" class="receverTime" :key="`div${i.id}${index}`">
+                <span :key="`receverTime${i.id}${index}`"> {{ i.sender_name }} [{{ i.send_time }}]</span>
+                <span v-if="i.type == '1'" v-html="i.content" :key="`receverContent${i.id}${index}`"></span>
+                <span v-else-if="i.type == '2'">
+                  {{ getFile(i.file) }}<van-button type="info" size="mini" class="downBtn" @click="downFile(i.file)">下载</van-button>
+                </span>
+              </van-col>
+            </template>
+          </template>
+        </van-col>
+        <van-col span="24" class="two">
+          <van-col span="17" class="cont">
+            <van-field v-model="content" placeholder="请输入内容" />
+          </van-col>
+          <van-col span="7" class="btn">
+            <van-button type="info" size="small" @click="send">发送</van-button>
+            <van-button type="info" size="small" @click="other">其它</van-button>
+          </van-col>
+        </van-col>
+      </van-col>
+    </van-row>
+    <van-dialog v-model="show" class="dialog" title="文件" :showConfirmButton="false" :showCancelButton="false" :closeOnClickOverlay="false">
+      <van-form>
+        <van-field name="file" label="文件">
+          <template #input>
+            <van-uploader
+              :fileList="fileForm.file"
+              :max-count="1"
+              :after-read="(file) => toUpload(file, 'file')"
+              @delete="(file) => toDelete(file, 'file')"
+              accept="file"
+            />
+          </template>
+        </van-field>
+        <div class="btn">
+          <van-button type="danger" size="small" @click="twoClose">取消发送</van-button>
+          <van-button type="info" size="small" @click="twoSend">提交发送</van-button>
+        </div>
+      </van-form>
+    </van-dialog>
+  </div>
+</template>
+
+<script>
+import { Toast } from 'vant';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: upload } = createNamespacedHelpers('upload');
+const { mapActions: adminLogin } = createNamespacedHelpers('adminLogin');
+const { mapActions: patentchat } = createNamespacedHelpers('patentchat');
+const _ = require('lodash');
+export default {
+  name: 'chat',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      adminInfo: {},
+      content: '',
+      // 消息列表
+      list: [],
+      // 浏览器高度
+      client: {},
+      // 发送其他内容
+      show: false,
+      fileForm: {},
+    };
+  },
+  created() {
+    this.searchAdmin();
+    this.search();
+  },
+  methods: {
+    ...upload(['upload']),
+    ...adminLogin({ adminQuery: 'query' }),
+    ...patentchat(['create', 'query']),
+    // 查询
+    async search() {
+      let res = await this.query({ id: this.user._id });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+      }
+    },
+    // 发言,正常内容
+    async send() {
+      if (this.content) {
+        let arr = {
+          type: '1',
+          content: this.content,
+          sender_id: this.user._id,
+          sender_name: this.user.name,
+          receiver_id: this.adminInfo._id,
+          receiver_name: this.adminInfo.name,
+        };
+        let res = await this.create(arr);
+        if (this.$checkRes(res)) {
+          this.$toast({ type: `success`, message: `发言成功` });
+          this.content = '';
+          this.search();
+        }
+      } else {
+        this.$toast({ type: `fail`, message: `缺少必要信息` });
+      }
+    },
+    // 发言,发送文件
+    other() {
+      this.show = true;
+    },
+    // 提交发送
+    async twoSend() {
+      let data = this.fileForm;
+      if (data.file) {
+        let data = {
+          type: '2',
+          file: data.file,
+          sender_id: this.user._id,
+          sender_name: this.user.name,
+          receiver_id: this.adminInfo._id,
+          receiver_name: this.adminInfo.name,
+        };
+        let res = await this.create(data);
+        if (this.$checkRes(res)) {
+          this.$toast({ type: `success`, message: `发言成功` });
+          this.fileForm = { file: [] };
+          this.twoClose();
+          this.search();
+        }
+      } else {
+        this.$toast({ type: `fail`, message: `缺少必要信息` });
+      }
+    },
+    // 取消发送
+    twoClose() {
+      this.show = false;
+    },
+
+    async toUpload({ file }, model) {
+      // 上传,赋值
+      const res = await this.upload({ file, dir: 'chat' });
+      if (this.$checkRes(res)) {
+        this.$set(this.fileForm, model, [{ name: res.name, url: res.uri }]);
+      }
+    },
+    toDelete(file, model) {
+      const index = this.fileForm[model].findIndex((f) => _.isEqual(f, file));
+      this.fileForm[model].splice(index, 1);
+    },
+    // 处理文件
+    getFile(data) {
+      if (data.length > 0) {
+        return data[0].name;
+      }
+    },
+    // 下载文件
+    downFile(data) {
+      if (data.length > 0) {
+        let url = data.map((i) => i.url);
+        window.location.href = `${process.env.VUE_APP_HOST}/${url[0]}`;
+      } else {
+        this.$toast({ type: `fail`, message: `非正常文件,无法下载` });
+      }
+    },
+    // 判断发言人
+    isSender(data) {
+      return this.user.id !== data.sender_id;
+    },
+    // 查询管理员
+    async searchAdmin() {
+      let res = await this.adminQuery({ code: 'JLKJQY' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `adminInfo`, res.data[0]);
+      }
+    },
+  },
+  mounted() {
+    let client = {
+      height: document.documentElement.clientHeight || document.body.clientHeight,
+      width: document.documentElement.clientWidth || document.body.clientWidth,
+    };
+    this.$set(this, `client`, client);
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    overflow-x: hidden;
+    overflow-y: auto;
+    padding: 10px 5px;
+    .senderTime {
+      float: left;
+      width: 100%;
+      text-align: left;
+      color: #666;
+      font-size: 14px;
+      margin: 0 0 5px 0;
+    }
+    .senderTime span:last-child {
+      float: left;
+      width: 100%;
+      text-align: left;
+      color: #000;
+    }
+    .receverTime {
+      float: right;
+      width: 100%;
+      color: #666;
+      font-size: 14px;
+      margin: 0 0 5px 0;
+    }
+    .receverTime span:first-child {
+      float: right;
+      width: 100%;
+      text-align: right;
+    }
+    .receverTime span:last-child {
+      float: right;
+      width: 100%;
+      text-align: right;
+      color: #000;
+    }
+  }
+  .two {
+    height: 40px;
+    border-top: 1px solid #ccc;
+    .cont {
+      /deep/.van-cell {
+        line-height: 20px;
+        padding: 10px;
+      }
+    }
+    .btn {
+      text-align: center;
+      /deep/.van-button--small {
+        width: 54px;
+        height: 40px;
+        padding: 0;
+      }
+    }
+  }
+}
+.dialog {
+  .btn {
+    text-align: center;
+    .van-button {
+      margin: 8px;
+    }
+  }
+}
+.downBtn {
+  margin: 0 0 0 8px;
+  /deep/.van-button__text {
+    color: #ffffff !important;
+  }
+}
+</style>

+ 88 - 0
src/layout/common/admin-frame.vue

@@ -0,0 +1,88 @@
+<template>
+  <div id="admin-frame">
+    <van-row>
+      <van-col span="24" class="main" :style="{ height: client.height + 'px' }">
+        <van-col span="24" class="top" style="height: 40px" v-if="useTop">
+          <top :topType="topType" @search="search" :leftArrow="leftArrow" @back="back"></top>
+        </van-col>
+        <van-col span="24" class="info" :style="{ height: getHeight() }"><slot name="info"></slot></van-col>
+        <van-col span="24" class="page" style="height: 40px" v-if="usePage"><page :limit="limit" :total="total" @search="search"></page></van-col>
+      </van-col>
+    </van-row>
+  </div>
+</template>
+
+<script>
+import top from './top.vue';
+import page from './page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'admin-frame',
+  props: {
+    // 头部信息
+    useTop: { type: Boolean, default: () => true },
+    topType: { type: String, default: () => '1' },
+    leftArrow: { type: Boolean, default: () => true },
+    // 分页
+    usePage: { type: Boolean, default: () => true },
+    limit: { type: Number, default: () => 10 },
+    total: { type: Number, default: () => 0 },
+  },
+  components: {
+    top,
+    page,
+  },
+  data: function () {
+    return {
+      client: {},
+    };
+  },
+  created() {},
+  methods: {
+    back() {
+      this.$emit('back');
+    },
+    search(skip) {
+      this.$emit('search', skip);
+    },
+    // 计算高度
+    getHeight() {
+      let top = 0;
+      let page = 0;
+      if (this.useTop) top = 40;
+      if (this.usePage) page = 40;
+      return this.client.height - top - page + 'px';
+    },
+  },
+  mounted() {
+    let client = {
+      height: document.documentElement.clientHeight || document.body.clientHeight,
+      width: document.documentElement.clientWidth || document.body.clientWidth,
+    };
+    this.$set(this, `client`, client);
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .info {
+    overflow-x: hidden;
+    overflow-y: auto;
+    background-color: #f9f9f9;
+  }
+}
+</style>

+ 42 - 0
src/layout/common/footers.vue

@@ -0,0 +1,42 @@
+<template>
+  <div id="footers">
+    <div class="footers">
+      <van-grid :column-num="list.length" clickable>
+        <van-grid-item v-for="(i, index) in list" :key="`menu-${index}`" :text="i.label" :to="i.router" />
+      </van-grid>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'footers',
+  props: {
+    list: { type: Array, default: () => [] },
+  },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.footers {
+  position: fixed;
+  bottom: 0px;
+  width: 100%;
+}
+</style>

+ 47 - 0
src/layout/common/page.vue

@@ -0,0 +1,47 @@
+<template>
+  <div id="page">
+    <el-row>
+      <el-col :span="24" class="main">
+        <van-pagination v-model="currentPage" @change="changePage" :total-items="total" :items-per-page="limit" :show-page-size="5" force-ellipses />
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'page',
+  props: {
+    total: { type: Number },
+    limit: { type: Number, default: () => 6 },
+  },
+  components: {},
+  data: function () {
+    return {
+      currentPage: 1,
+    };
+  },
+  created() {},
+  methods: {
+    changePage(page) {
+      this.$emit('search', { skip: (page - 1) * this.limit });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 7 - 0
src/layout/common/top.md

@@ -0,0 +1,7 @@
+<!-- 头部类型 -->
+# topType
+## topType=="1" 带有查询,查询方法:search
+
+## topType=="2" 带有标题和返回,返回方法:back
+
+## topType=="3" 带有返回和查询,返回方法:back,查询方法:search

+ 127 - 0
src/layout/common/top.vue

@@ -0,0 +1,127 @@
+<template>
+  <div id="top">
+    <el-col :span="24" class="one" v-if="topType == '1'">
+      <van-search v-model="searchName" placeholder="请输入信息标题" @search="search" />
+    </el-col>
+    <el-col :span="24" class="two" v-else-if="topType == '2'">
+      <van-nav-bar :title="this.$route.meta.title" :left-arrow="leftArrow" @click-left="upBack">
+        <template #left>
+          <span v-if="leftArrow">
+            <van-icon name="arrow-left" />
+            <span style="color: #409eff">返回</span>
+          </span>
+        </template>
+      </van-nav-bar>
+    </el-col>
+    <el-col :span="24" class="thr" v-else-if="topType == '3'">
+      <el-col :span="4" class="back" @click.native="upBack"> <van-icon name="arrow-left" />返回 </el-col>
+      <el-col :span="20" class="search">
+        <van-search v-model="searchName" placeholder="请输入信息" @search="search" />
+      </el-col>
+    </el-col>
+    <el-col :span="24" class="four" v-else-if="topType == '4'">
+      <el-col :span="4" class="back" @click.native="upBack"> <van-icon name="arrow-left" />返回 </el-col>
+      <el-col :span="16" class="title">
+        {{ $route.meta.title }}
+      </el-col>
+      <el-col :span="4" class="add">
+        <van-button icon="plus" size="small" type="info" round @click="add" />
+      </el-col>
+    </el-col>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'top',
+  props: {
+    topType: { type: String, default: () => '1' },
+    // 只有类型为2时,有用
+    leftArrow: { type: Boolean, default: () => true },
+  },
+  components: {},
+  data: function () {
+    return {
+      searchName: '',
+    };
+  },
+  created() {},
+  methods: {
+    // 查询
+    search() {
+      this.$emit('search', { searchName: this.searchName });
+    },
+    // 返回
+    upBack() {
+      this.$emit('back');
+    },
+    // 添加
+    add() {
+      this.$emit('add');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.one {
+  /deep/.van-search {
+    padding: 3px 5px;
+  }
+}
+.two {
+  /deep/.van-nav-bar__content {
+    height: 40px;
+  }
+  /deep/.van-icon {
+    top: 2px;
+  }
+}
+.thr {
+  .back {
+    color: #409eff;
+    padding: 8px 0;
+    text-align: center;
+    .van-icon {
+      top: 3px;
+    }
+  }
+  .search {
+    /deep/.van-search {
+      padding: 2px 5px 2px 0px;
+    }
+  }
+}
+.four {
+  .back {
+    color: #409eff;
+    padding: 8px 0;
+    text-align: center;
+    .van-icon {
+      top: 3px;
+    }
+  }
+  .title {
+    text-align: center;
+    padding: 9px 0;
+  }
+  .add {
+    text-align: center;
+    padding: 4px 0;
+  }
+}
+</style>

+ 148 - 0
src/layout/list/cashing/model-1.vue

@@ -0,0 +1,148 @@
+<template>
+  <div id="model-6">
+    <el-row class="list">
+      <el-col :span="24" class="is_cashing">
+        <el-col :span="4" class="cashing">
+          {{ getCash(data.is_cashing) }}
+        </el-col>
+      </el-col>
+      <el-col :span="24" class="other">
+        <el-col :span="24" class="other_info textOver">
+          申请企业:<span>{{ data.company || '暂无' }}</span>
+        </el-col>
+        <el-col :span="24" class="other_info textOver">
+          联系电话:<span>{{ data.phone || '暂无' }}</span>
+        </el-col>
+        <el-col :span="24" class="other_info textOver">
+          中介机构:<span>{{ data.medium.name || '暂无' }}</span>
+        </el-col>
+        <el-col :span="24" class="other_info textOver">
+          审核状态:<span>{{ getStu(data.status) || '暂无' }}</span>
+        </el-col>
+      </el-col>
+      <el-col :span="24" class="btn">
+        <el-button type="primary" size="mini" @click="view">查看详情</el-button>
+        <el-button type="primary" size="mini" @click="edit" v-if="data.status == '-1'">重申</el-button>
+        <el-button type="primary" size="mini" @click="edit" v-if="data.status == '1' || data.status == '2'">上传合同</el-button>
+        <el-button type="primary" size="mini" @click="cash" v-if="data.status == '3' && data.is_cashing == '0'">我要兑付</el-button>
+        <el-button type="primary" size="mini" @click="cashview" v-if="data.is_cashing == '1'">兑付详情</el-button>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const { iscashing, declareStatus } = require('@/plugins/couindex');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-6',
+  props: {
+    data: { type: Object, default: () => {} },
+    router: { type: String },
+  },
+  components: {},
+  data: function () {
+    return {
+      kjpx: require('@a/kjpx.jpg'),
+    };
+  },
+  created() {},
+  methods: {
+    // 详情
+    view() {
+      this.$router.push({ path: '/adminCompany/cashing/declare/info', query: { id: this.data._id, status: this.data.status } });
+    },
+    // 重申
+    edit() {
+      this.$router.push({ path: '/adminCompany/cashing/declare/detail', query: { id: this.data._id, status: this.data.status } });
+    },
+    // 兑付
+    cash() {
+      this.$router.push({ path: '/adminCompany/cashing/declare/cashing', query: { id: this.data._id } });
+    },
+    // 兑付详情
+    cashview() {
+      this.$router.push({ path: '/adminCompany/cashing/declare/cashingInfo', query: { id: this.data._id } });
+    },
+    getCash(i) {
+      const r = iscashing.find((f) => f.value === i);
+      if (r) return r.label;
+      else return '';
+    },
+    getStu(i) {
+      const r = declareStatus.find((f) => f.value === i);
+      if (r) return r.label;
+      else return '';
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.list {
+  background-color: #fff;
+  border-radius: 5px;
+  margin: 0 0 10px 0;
+  padding: 0 0 8px 0;
+  .is_cashing {
+    margin: 0 0 5px 0;
+    .cashing {
+      text-align: center;
+      background-color: #409eff;
+      color: #fff;
+      font-size: 12px;
+      padding: 5px 0;
+      border-radius: 5px;
+    }
+  }
+  .other {
+    padding: 0 10px;
+    .other_info {
+      font-size: 14px;
+      color: #666;
+      margin: 0 0 10px 0;
+      span {
+        color: #000;
+      }
+    }
+  }
+  .btn {
+    text-align: center;
+    margin: 10px 0 0 0;
+  }
+}
+// .list {
+//   background-color: #fff;
+//   border-radius: 5px;
+//   margin: 0 0 10px 0;
+//   padding: 8px;
+//   .name {
+//     font-size: 16px;
+//     margin: 0 0 5px 0;
+//     font-weight: bold;
+//   }
+//   .other {
+//     .other_info {
+//       font-size: 14px;
+//       color: #666;
+//       margin: 0 0 5px 0;
+//       span {
+//         color: #000;
+//       }
+//     }
+//   }
+//   .btn {
+//     text-align: center;
+//     margin: 10px 0 0 0;
+//   }
+// }
+</style>

+ 145 - 0
src/layout/list/cashing/model-2.vue

@@ -0,0 +1,145 @@
+<template>
+  <div id="model-2">
+    <el-row class="list">
+      <el-col :span="24" class="is_cashing">
+        <el-col :span="4" class="cashing">
+          {{ getCash(data.is_cashing) }}
+        </el-col>
+      </el-col>
+      <el-col :span="24" class="other">
+        <el-col :span="24" class="other_info textOver">
+          申领类型:<span>{{ data.type || '暂无' }}</span>
+        </el-col>
+        <el-col :span="24" class="other_info textOver">
+          申请企业:<span>{{ data.company || '暂无' }}</span>
+        </el-col>
+        <el-col :span="24" class="other_info textOver">
+          申请人:<span>{{ data.apply_person || '暂无' }}</span>
+        </el-col>
+        <el-col :span="24" class="other_info textOver">
+          联系电话:<span>{{ data.phone || '暂无' }}</span>
+        </el-col>
+        <el-col :span="24" class="other_info textOver">
+          审核状态:<span>{{ getStu(data.status) || '暂无' }}</span>
+        </el-col>
+      </el-col>
+      <el-col :span="24" class="btn">
+        <el-button type="primary" size="mini" @click="view">查看详情</el-button>
+        <el-button type="primary" size="mini" @click="cash" v-if="data.status == '1' && data.is_cashing == '0'">我要兑付</el-button>
+        <el-button type="primary" size="mini" @click="cashview" v-if="data.is_cashing == '1'">兑付详情</el-button>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const { iscashing, rewardStatus } = require('@/plugins/couindex');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-2',
+  props: {
+    data: { type: Object, default: () => {} },
+    router: { type: String },
+  },
+  components: {},
+  data: function () {
+    return {
+      kjpx: require('@a/kjpx.jpg'),
+    };
+  },
+  created() {},
+  methods: {
+    // 详情
+    view() {
+      this.$router.push({ path: '/adminCompany/cashing/invention/info', query: { id: this.data._id } });
+    },
+    // 兑付
+    cash() {
+      this.$router.push({ path: '/adminCompany/cashing/invention/cashing', query: { id: this.data._id } });
+    },
+    // 兑付详情
+    cashview() {
+      this.$router.push({ path: '/adminCompany/cashing/invention/cashingInfo', query: { id: this.data._id } });
+    },
+    getCash(i) {
+      const r = iscashing.find((f) => f.value === i);
+      if (r) return r.label;
+      else return '';
+    },
+    getStu(i) {
+      const r = rewardStatus.find((f) => f.value === i);
+      if (r) return r.label;
+      else return '';
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.list {
+  background-color: #fff;
+  border-radius: 5px;
+  margin: 0 0 10px 0;
+  padding: 0 0 8px 0;
+  .is_cashing {
+    margin: 0 0 5px 0;
+    .cashing {
+      text-align: center;
+      background-color: #409eff;
+      color: #fff;
+      font-size: 12px;
+      padding: 5px 0;
+      border-radius: 5px;
+    }
+  }
+  .other {
+    padding: 0 10px;
+    .other_info {
+      font-size: 14px;
+      color: #666;
+      margin: 0 0 10px 0;
+      span {
+        color: #000;
+      }
+    }
+  }
+  .btn {
+    text-align: center;
+    margin: 10px 0 0 0;
+  }
+}
+// .list {
+//   background-color: #fff;
+//   border-radius: 5px;
+//   margin: 0 0 10px 0;
+//   padding: 8px;
+//   .name {
+//     font-size: 16px;
+//     margin: 0 0 5px 0;
+//     font-weight: bold;
+//   }
+//   .other {
+//     .other_info {
+//       font-size: 14px;
+//       color: #666;
+//       margin: 0 0 5px 0;
+//       span {
+//         color: #000;
+//       }
+//     }
+//   }
+//   .btn {
+//     text-align: center;
+//     margin: 10px 0 0 0;
+//   }
+// }
+</style>

+ 145 - 0
src/layout/list/cashing/model-3.vue

@@ -0,0 +1,145 @@
+<template>
+  <div id="model-2">
+    <el-row class="list">
+      <el-col :span="24" class="is_cashing">
+        <el-col :span="4" class="cashing">
+          {{ getCash(data.is_cashing) }}
+        </el-col>
+      </el-col>
+      <el-col :span="24" class="other">
+        <el-col :span="24" class="other_info textOver">
+          申领类型:<span>{{ data.type || '暂无' }}</span>
+        </el-col>
+        <el-col :span="24" class="other_info textOver">
+          申请企业:<span>{{ data.company || '暂无' }}</span>
+        </el-col>
+        <el-col :span="24" class="other_info textOver">
+          申请人:<span>{{ data.apply_person || '暂无' }}</span>
+        </el-col>
+        <el-col :span="24" class="other_info textOver">
+          联系电话:<span>{{ data.phone || '暂无' }}</span>
+        </el-col>
+        <el-col :span="24" class="other_info textOver">
+          审核状态:<span>{{ getStu(data.status) || '暂无' }}</span>
+        </el-col>
+      </el-col>
+      <el-col :span="24" class="btn">
+        <el-button type="primary" size="mini" @click="view">查看详情</el-button>
+        <el-button type="primary" size="mini" @click="cash" v-if="data.status == '1' && data.is_cashing == '0'">我要兑付</el-button>
+        <el-button type="primary" size="mini" @click="cashview" v-if="data.is_cashing == '1'">兑付详情</el-button>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const { iscashing, rewardStatus } = require('@/plugins/couindex');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-2',
+  props: {
+    data: { type: Object, default: () => {} },
+    router: { type: String },
+  },
+  components: {},
+  data: function () {
+    return {
+      kjpx: require('@a/kjpx.jpg'),
+    };
+  },
+  created() {},
+  methods: {
+    // 详情
+    view() {
+      this.$router.push({ path: '/adminCompany/cashing/reward/info', query: { id: this.data._id } });
+    },
+    // 兑付
+    cash() {
+      this.$router.push({ path: '/adminCompany/cashing/reward/cashing', query: { id: this.data._id } });
+    },
+    // 兑付详情
+    cashview() {
+      this.$router.push({ path: '/adminCompany/cashing/reward/cashingInfo', query: { id: this.data._id } });
+    },
+    getCash(i) {
+      const r = iscashing.find((f) => f.value === i);
+      if (r) return r.label;
+      else return '';
+    },
+    getStu(i) {
+      const r = rewardStatus.find((f) => f.value === i);
+      if (r) return r.label;
+      else return '';
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.list {
+  background-color: #fff;
+  border-radius: 5px;
+  margin: 0 0 10px 0;
+  padding: 0 0 8px 0;
+  .is_cashing {
+    margin: 0 0 5px 0;
+    .cashing {
+      text-align: center;
+      background-color: #409eff;
+      color: #fff;
+      font-size: 12px;
+      padding: 5px 0;
+      border-radius: 5px;
+    }
+  }
+  .other {
+    padding: 0 10px;
+    .other_info {
+      font-size: 14px;
+      color: #666;
+      margin: 0 0 10px 0;
+      span {
+        color: #000;
+      }
+    }
+  }
+  .btn {
+    text-align: center;
+    margin: 10px 0 0 0;
+  }
+}
+// .list {
+//   background-color: #fff;
+//   border-radius: 5px;
+//   margin: 0 0 10px 0;
+//   padding: 8px;
+//   .name {
+//     font-size: 16px;
+//     margin: 0 0 5px 0;
+//     font-weight: bold;
+//   }
+//   .other {
+//     .other_info {
+//       font-size: 14px;
+//       color: #666;
+//       margin: 0 0 5px 0;
+//       span {
+//         color: #000;
+//       }
+//     }
+//   }
+//   .btn {
+//     text-align: center;
+//     margin: 10px 0 0 0;
+//   }
+// }
+</style>

+ 72 - 0
src/layout/list/model-1.vue

@@ -0,0 +1,72 @@
+<template>
+  <div id="model-1">
+    <el-row class="list" @click.native="toDetail">
+      <el-col :span="24" class="title">
+        {{ data.title }}
+      </el-col>
+      <el-col :span="24" class="other">
+        <p>
+          更新时间:<span>{{ data.publish_time || '暂无' }}</span>
+        </p>
+        <p>
+          信息来源:<span>{{ data.origin || '暂无' }}</span>
+        </p>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-1',
+  props: { data: { type: Object, default: () => {} } },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    toDetail() {
+      this.$router.push({ path: this.detailRouter, query: { id: this.data._id } });
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    detailRouter() {
+      const key = this.$route.meta.key;
+      return `/${key}/detail`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.list {
+  padding: 10px 5px;
+  background: #fff;
+  margin: 0 0 5px 0;
+  border-radius: 5px;
+  .title {
+    font-size: 15px;
+    font-weight: bold;
+    margin: 0 0 5px 0;
+  }
+  .other {
+    p {
+      padding: 0 0 5px 0;
+      color: #666;
+      font-size: 14px;
+      span {
+        color: #000;
+      }
+    }
+  }
+}
+</style>

+ 70 - 0
src/layout/list/model-2.vue

@@ -0,0 +1,70 @@
+<template>
+  <div id="model-2">
+    <el-row class="list" @click.native="toDetail">
+      <el-col :span="24" class="title">
+        {{ data.title }}
+      </el-col>
+      <el-col :span="24" class="other">
+        <p>
+          <span>{{ data.origin || '暂无' }}</span>
+          <span>{{ data.publish_time || '暂无' }}</span>
+        </p>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-2',
+  props: { data: { type: Object, default: () => {} } },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    toDetail() {
+      this.$router.push({ path: this.detailRouter, query: { id: this.data._id } });
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    detailRouter() {
+      const key = this.$route.meta.key;
+      return `/${key}/detail`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.list {
+  padding: 10px 5px;
+  background: #fff;
+  margin: 0 0 5px 0;
+  border-radius: 5px;
+  .title {
+    font-size: 15px;
+    font-weight: bold;
+    margin: 0 0 5px 0;
+  }
+  .other {
+    p {
+      span {
+        display: inline-block;
+        width: 50%;
+        font-size: 14px;
+        color: #666;
+      }
+    }
+  }
+}
+</style>

+ 99 - 0
src/layout/list/model-3.vue

@@ -0,0 +1,99 @@
+<template>
+  <div id="model-3">
+    <el-row class="list" @click.native="toDetail">
+      <el-col :span="8" class="image">
+        <el-image :src="kjpx" fit="fit"></el-image>
+      </el-col>
+      <el-col :span="16" class="info">
+        <el-col :span="24" class="title">
+          {{ data.title }}
+        </el-col>
+        <el-col :span="24" class="other">
+          <p>
+            更新时间:<span>{{ data.publish_time || '暂无' }}</span>
+          </p>
+          <p>
+            信息来源:<span>{{ data.origin || '暂无' }}</span>
+          </p>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-3',
+  props: {
+    data: { type: Object, default: () => {} },
+    router: { type: String },
+  },
+  components: {},
+  data: function () {
+    return {
+      kjpx: require('@a/kjpx.jpg'),
+    };
+  },
+  created() {},
+  methods: {
+    toDetail() {
+      this.$router.push({ path: this.router ? this.router : this.detailRouter, query: { id: this.data._id } });
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    detailRouter() {
+      const key = this.$route.meta.key;
+      return `/${key}/detail`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.list {
+  padding: 10px 5px;
+  background: #fff;
+  margin: 0 0 5px 0;
+  border-radius: 5px;
+  .image {
+    text-align: center;
+    .el-image {
+      border: 1px solid #f9f9f9;
+      border-radius: 5px;
+    }
+  }
+  .info {
+    padding: 0 5px;
+    .title {
+      font-size: 15px;
+      font-weight: bold;
+      margin: 0 0 5px 0;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      -webkit-line-clamp: 2;
+      word-break: break-all;
+      display: -webkit-box;
+      -webkit-box-orient: vertical;
+      max-height: 40px;
+    }
+    .other {
+      p {
+        padding: 0 0 5px 0;
+        color: #666;
+        font-size: 14px;
+        span {
+          color: #000;
+        }
+      }
+    }
+  }
+}
+</style>

+ 123 - 0
src/layout/list/model-4.vue

@@ -0,0 +1,123 @@
+<template>
+  <div id="model-4">
+    <el-row class="list" @click.native="toDetail">
+      <el-col :span="24" class="title">
+        {{ data.title }}
+      </el-col>
+      <el-col :span="24" class="other">
+        <el-col :span="24" class="other_info">
+          更新时间:<span>{{ data.create_time || '暂无' }}</span>
+        </el-col>
+        <el-col :span="24" class="other_info brief">
+          信息简介:<span>{{ data.brief || '暂无' }}</span>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-4',
+  props: {
+    data: { type: Object, default: () => {} },
+    router: { type: String },
+  },
+  components: {},
+  data: function () {
+    return {
+      kjpx: require('@a/kjpx.jpg'),
+    };
+  },
+  created() {},
+  methods: {
+    toDetail() {
+      this.$router.push({ path: this.router ? this.router : this.detailRouter, query: { id: this.data._id } });
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    detailRouter() {
+      const key = this.$route.meta.key;
+      return `/${key}/detail`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.list {
+  background-color: #fff;
+  border-radius: 5px;
+  margin: 0 0 10px 0;
+  padding: 8px;
+  .title {
+    font-size: 16px;
+    margin: 0 0 5px 0;
+    font-weight: bold;
+  }
+  .other {
+    .other_info {
+      font-size: 14px;
+      color: #666;
+      margin: 0 0 5px 0;
+      span {
+        color: #000;
+      }
+    }
+    .brief {
+      overflow: hidden;
+      text-overflow: ellipsis;
+      -webkit-line-clamp: 2;
+      word-break: break-all;
+      display: -webkit-box;
+      -webkit-box-orient: vertical;
+    }
+  }
+}
+// .list {
+//   padding: 10px 5px;
+//   background: #fff;
+//   margin: 0 0 5px 0;
+//   border-radius: 5px;
+//   .image {
+//     text-align: center;
+//     .el-image {
+//       border: 1px solid #f9f9f9;
+//       border-radius: 5px;
+//     }
+//   }
+//   .info {
+//     padding: 0 5px;
+//     .title {
+//       font-size: 15px;
+//       font-weight: bold;
+//       margin: 0 0 5px 0;
+//       overflow: hidden;
+//       text-overflow: ellipsis;
+//       -webkit-line-clamp: 2;
+//       word-break: break-all;
+//       display: -webkit-box;
+//       -webkit-box-orient: vertical;
+//       max-height: 40px;
+//     }
+//     .other {
+//       p {
+//         padding: 0 0 5px 0;
+//         color: #666;
+//         font-size: 14px;
+//         span {
+//           color: #000;
+//         }
+//       }
+//     }
+//   }
+// }
+</style>

+ 98 - 0
src/layout/list/model-5.vue

@@ -0,0 +1,98 @@
+<template>
+  <div id="model-5">
+    <el-row class="list">
+      <el-col :span="24" class="name">
+        {{ data.name }}
+      </el-col>
+      <el-col :span="24" class="other">
+        <el-col :span="12" class="other_info textOver">
+          创新券类型:<span>{{ data.coupons_type || '暂无' }}</span>
+        </el-col>
+        <el-col :span="12" class="other_info textOver">
+          所属分类:<span>{{ data.classify || '暂无' }}</span>
+        </el-col>
+        <el-col :span="12" class="other_info textOver">
+          折扣类型:<span>{{ data.discount_type || '暂无' }}</span>
+        </el-col>
+        <el-col :span="12" class="other_info textOver">
+          适用服务类型:<span>{{ data.use_type || '暂无' }}</span>
+        </el-col>
+      </el-col>
+      <el-col :span="24" class="btn">
+        <el-button type="primary" size="mini" @click.native="toDetail">详情</el-button>
+        <el-button type="success" size="mini" @click.native="toApply">申领</el-button>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-5',
+  props: {
+    data: { type: Object, default: () => {} },
+    router: { type: String },
+  },
+  components: {},
+  data: function () {
+    return {
+      kjpx: require('@a/kjpx.jpg'),
+    };
+  },
+  created() {},
+  methods: {
+    toDetail() {
+      this.$router.push({ path: this.router ? this.router : this.detailRouter, query: { id: this.data._id } });
+    },
+    toApply() {
+      this.$router.push({ path: this.router ? this.router : this.applyRouter, query: { id: this.data._id } });
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    detailRouter() {
+      const key = this.$route.meta.key;
+      return `/adminCompany/${key}/detail`;
+    },
+    applyRouter() {
+      const key = this.$route.meta.key;
+      return `/adminCompany/${key}/apply`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.list {
+  background-color: #fff;
+  border-radius: 5px;
+  margin: 0 0 10px 0;
+  padding: 8px;
+  .name {
+    font-size: 16px;
+    margin: 0 0 5px 0;
+    font-weight: bold;
+  }
+  .other {
+    .other_info {
+      font-size: 14px;
+      color: #666;
+      margin: 0 0 5px 0;
+      span {
+        color: #000;
+      }
+    }
+  }
+  .btn {
+    text-align: center;
+    margin: 10px 0 0 0;
+  }
+}
+</style>

+ 101 - 0
src/layout/list/model-6.vue

@@ -0,0 +1,101 @@
+<template>
+  <div id="model-6">
+    <el-row class="list">
+      <el-col :span="24" class="name">
+        {{ data.coupons ? data.coupons.name : '暂无' }}
+      </el-col>
+      <el-col :span="24" class="other">
+        <el-col :span="12" class="other_info textOver">
+          申请人:<span>{{ data.apply_person || '暂无' }}</span>
+        </el-col>
+        <el-col :span="12" class="other_info textOver">
+          联系电话:<span>{{ data.phone || '暂无' }}</span>
+        </el-col>
+        <el-col :span="12" class="other_info textOver">
+          是否使用:<span>{{ getUse(data.is_use) || '暂无' }}</span>
+        </el-col>
+        <el-col :span="12" class="other_info textOver">
+          审核状态:<span>{{ getStu(data.status) || '暂无' }}</span>
+        </el-col>
+      </el-col>
+      <el-col :span="24" class="btn">
+        <el-button type="primary" size="mini" @click.native="toDetail">详情</el-button>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const { isuse, couponsapplyStatus } = require('@/plugins/couindex');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-6',
+  props: {
+    data: { type: Object, default: () => {} },
+    router: { type: String },
+  },
+  components: {},
+  data: function () {
+    return {
+      kjpx: require('@a/kjpx.jpg'),
+    };
+  },
+  created() {},
+  methods: {
+    toDetail() {
+      this.$router.push({ path: this.router ? this.router : this.detailRouter, query: { id: this.data._id } });
+    },
+    getUse(i) {
+      const r = isuse.find((f) => f.value === i);
+      if (r) return r.label;
+      else return '';
+    },
+    getStu(i) {
+      const r = couponsapplyStatus.find((f) => f.value === i);
+      if (r) return r.label;
+      else return '';
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    detailRouter() {
+      const key = this.$route.meta.key;
+      return `/adminCompany/${key}/resultInfo`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.list {
+  background-color: #fff;
+  border-radius: 5px;
+  margin: 0 0 10px 0;
+  padding: 8px;
+  .name {
+    font-size: 16px;
+    margin: 0 0 5px 0;
+    font-weight: bold;
+  }
+  .other {
+    .other_info {
+      font-size: 14px;
+      color: #666;
+      margin: 0 0 5px 0;
+      span {
+        color: #000;
+      }
+    }
+  }
+  .btn {
+    text-align: center;
+    margin: 10px 0 0 0;
+  }
+}
+</style>

+ 100 - 0
src/layout/login/login-1.vue

@@ -0,0 +1,100 @@
+<template>
+  <div id="login-1">
+    <van-row>
+      <van-col span="24" class="main">
+        <van-form @submit="onSubmit">
+          <van-field v-model="form.phone" name="phone" label="账号" placeholder="账号" :rules="[{ required: true, message: '账号' }]" />
+          <van-field v-model="form.password" type="password" name="password" label="密码" placeholder="密码" :rules="[{ required: true, message: '密码' }]" />
+          <van-field name="role" label="用户类别">
+            <template #input>
+              <van-radio-group v-model="form.role" direction="horizontal">
+                <van-radio name="4">个人用户</van-radio>
+                <!-- <van-radio name="5">企业用户</van-radio> -->
+              </van-radio-group>
+            </template>
+          </van-field>
+          <div style="margin: 16px">
+            <van-button round block type="info" native-type="submit">登录</van-button>
+          </div>
+        </van-form>
+        <van-col span="24" class="register">
+          <span class="text">还没有账号?</span>
+          <van-button type="info" size="mini" plain @click="regBtn">现在注册</van-button>
+        </van-col>
+      </van-col>
+    </van-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: organization } = createNamespacedHelpers('organization');
+const { mapActions: personal } = createNamespacedHelpers('personal');
+export default {
+  name: 'login-1',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      form: {},
+    };
+  },
+  created() {},
+  methods: {
+    ...personal(['perLogin']),
+    ...organization(['orgLogin', 'wxLogin']),
+    async onSubmit(values) {
+      if (values.role == '4') {
+        // 个人用户
+        let res = await this.perLogin({ user: values });
+        if (this.$checkRes(res)) {
+          this.$router.push({ path: this.$route.query.path });
+        } else {
+          this.$toast({ type: 'fail', message: res.errmsg });
+        }
+      } else if (values.role == '5') {
+        // 企业用户
+        values.institution_code = values.phone;
+        let res = await this.orgLogin({ user: values });
+        if (this.$checkRes(res)) {
+          this.$router.push({ path: this.$route.query.path });
+        } else {
+          this.$toast({ type: 'fail', message: res.errmsg });
+        }
+      }
+    },
+    // 注册
+    regBtn() {
+      this.$router.push({ path: '/register' });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .register {
+    text-align: center;
+    .text {
+      position: relative;
+      top: 4px;
+      padding: 0 10px;
+      font-size: 12px;
+      color: #666;
+    }
+  }
+}
+</style>

+ 57 - 0
src/layout/login/login-2.vue

@@ -0,0 +1,57 @@
+<template>
+  <div id="login-2">
+    <van-row>
+      <van-col span="24" class="main">
+        <van-form @submit="onSubmit">
+          <van-field v-model="form.code_phone" name="code_phone" label="账号" placeholder="账号" :rules="[{ required: true, message: '账号' }]" />
+          <van-field v-model="form.passwd" type="password" name="passwd" label="密码" placeholder="密码" :rules="[{ required: true, message: '密码' }]" />
+          <div style="margin: 16px">
+            <van-button round block type="info" native-type="submit">登录</van-button>
+          </div>
+        </van-form>
+      </van-col>
+    </van-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: adminLogin } = createNamespacedHelpers('adminLogin');
+export default {
+  name: 'login-2',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      form: {},
+    };
+  },
+  created() {},
+  methods: {
+    ...adminLogin(['login']),
+    async onSubmit(values) {
+      let res = await this.login({ user: values });
+      if (this.$checkRes(res)) {
+        this.$router.push({ path: '/exchange/center/index' });
+      } else {
+        this.$toast({ type: 'fail', message: res.errmsg });
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 97 - 0
src/layout/login/register-1.vue

@@ -0,0 +1,97 @@
+<template>
+  <div id="register-1">
+    <van-row>
+      <van-col span="24" class="main">
+        <van-form @submit="onSubmit" label-width="6em">
+          <van-field v-model="form.name" name="name" label="用户名" :rules="[{ required: true, message: '用户名' }]" />
+          <van-field v-model="form.phone" name="phone" label="手机号" :rules="[{ required: true, message: '手机号' }]" />
+          <van-field v-model="form.password" type="password" name="password" label="登录密码" :rules="[{ required: true, message: '登录密码' }]" />
+          <van-field v-model="form.code" name="code" label="邀请码" :rules="[{ required: false, message: '邀请码' }]" />
+          <van-field name="type" label="用户类别" :rules="[{ required: true, message: '用户类别' }]">
+            <template #input>
+              <van-radio-group v-model="form.type" direction="horizontal">
+                <van-radio name="4">个人用户</van-radio>
+                <!-- <van-radio name="5">企业用户</van-radio> -->
+              </van-radio-group>
+            </template>
+          </van-field>
+          <van-field v-model="form.email" name="email" label="电子邮箱" />
+          <van-field v-model="form.addr" name="addr" label="联系地址" />
+          <van-field v-model="form.office_phone" name="office_phone" label="办公电话" />
+          <van-field readonly clickable name="juris" :value="form.juris" label="所属辖区" placeholder="点击选择" @click="showPicker = true" />
+          <van-popup v-model="showPicker" position="bottom">
+            <van-picker show-toolbar :columns="jurisList" @confirm="confirm" @cancel="showPicker = false" />
+          </van-popup>
+          <div class="btn">
+            <van-button round type="danger" size="normal" @click="reseat">取消注册</van-button>
+            <van-button round type="primary" size="normal" native-type="submit" v-if="form.type == '4'">提交注册</van-button>
+            <van-button round type="info" size="normal" @click="next" v-if="form.type == '5'">下一步</van-button>
+          </div>
+        </van-form>
+      </van-col>
+    </van-row>
+  </div>
+</template>
+
+<script>
+import { juris } from '@common/dict/index';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'register-1',
+  props: {
+    form: { type: Object },
+  },
+  components: {},
+  data: function () {
+    return {
+      showPicker: false,
+      jurisList: juris,
+    };
+  },
+  created() {},
+  methods: {
+    // 取消注册
+    reseat() {
+      this.$router.push({ path: '/login' });
+    },
+    onSubmit(values) {
+      this.$emit('onSubmit', values);
+    },
+    // 下一步
+    next() {
+      this.$emit('next');
+    },
+
+    // 选择辖区
+    confirm(value) {
+      this.$set(this.form, `juris`, value);
+      this.showPicker = false;
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .btn {
+    margin: 16px;
+    text-align: center;
+    .van-button {
+      margin: 0 10px;
+    }
+  }
+}
+</style>

+ 90 - 0
src/layout/login/register-2.vue

@@ -0,0 +1,90 @@
+<template>
+  <div id="register-2">
+    <van-row>
+      <van-col span="24" class="main">
+        <van-form @submit="onSubmit" label-width="5em">
+          <van-field v-model="form.institution_code" name="institution_code" label="统一社会信用代码" />
+          <van-field v-model="form.companytype" name="companytype" label="注册类型" />
+          <van-field readonly clickable name="calendar" :value="form.companydate" label="注册时间" placeholder="点击选择日期" @click="showCalendar = true" />
+          <van-calendar v-model="showCalendar" @confirm="onConfirm" />
+          <van-field v-model="form.companycapital" name="companycapital" label="注册资金" />
+          <van-field v-model="form.companyperson" name="companyperson" label="企业法人" />
+          <van-field v-model="form.sndqyzsr" name="sndqyzsr" label="企业总收入" />
+          <van-field v-model="form.sndyffy" name="sndyffy" label="研发费用" />
+          <van-field v-model="form.companytotal" name="companytotal" label="企业总人数" />
+          <van-field v-model="form.zjzyfrs" name="zjzyfrs" label="研发人数" />
+          <van-field v-model="form.companybrief" name="companybrief" label="企业简介" rows="1" autosize type="textarea" />
+          <van-field v-model="form.mainproduct" name="mainproduct" label="主要产品" rows="1" autosize type="textarea" />
+          <van-field v-model="form.qualifications" name="qualifications" label="资质&荣誉" rows="1" autosize type="textarea" />
+          <div class="btn">
+            <van-button round type="danger" size="normal" @click="reseat">取消注册</van-button>
+            <van-button round type="info" size="normal" @click="up">上一步</van-button>
+            <van-button round type="primary" size="normal" native-type="submit">提交注册</van-button>
+          </div>
+        </van-form>
+      </van-col>
+    </van-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const _ = require('lodash');
+const moment = require('moment');
+export default {
+  name: 'register-2',
+  props: {
+    form: { type: Object },
+  },
+  components: {},
+  data: function () {
+    return {
+      showCalendar: false,
+    };
+  },
+  created() {},
+  methods: {
+    // 取消注册
+    reseat() {
+      this.$emit('reseat');
+    },
+    onSubmit(values) {
+      this.$emit('onSubmit', values);
+    },
+    // 上一步
+    up() {
+      this.$emit('up');
+    },
+    // 选择注册时间
+    onConfirm(value) {
+      this.$set(this.form, `companydate`, moment(value).format('YYYY-MM-DD'));
+      this.showCalendar = false;
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .btn {
+    margin: 16px;
+    text-align: center;
+    .van-button {
+      margin: 0 10px;
+    }
+  }
+}
+</style>

+ 26 - 0
src/main.js

@@ -0,0 +1,26 @@
+import Vue from 'vue';
+import App from './App.vue';
+import '@/plugins/weixin';
+import router from './router';
+import store from './store';
+import '@/plugins/element.js';
+import '@/plugins/vant';
+import '@/plugins/axios';
+import '@/plugins/check-res';
+import '@/plugins/meta';
+import '@/plugins/loading';
+import '@/plugins/setting';
+import InitStomp from '@/plugins/stomp';
+import '@/plugins/components';
+import '@frame/src/assets/icon/iconfont.css';
+Vue.config.productionTip = false;
+
+new Vue({
+  router,
+  store,
+  render: (h) => h(App),
+}).$mount('#app');
+InitStomp();
+window.vm = new Vue({
+  router,
+});

+ 19 - 0
src/plugins/axios.js

@@ -0,0 +1,19 @@
+import Vue from 'vue';
+import AxiosWrapper from '@/util/axios-wrapper';
+
+const Plugin = {
+  install(vue, options) {
+    // 3. 注入组件
+    vue.mixin({
+      created() {
+        if (this.$store && !this.$store.$axios) {
+          this.$store.$axios = this.$axios;
+        }
+      },
+    });
+    // 4. 添加实例方法
+    vue.prototype.$axios = new AxiosWrapper(options);
+  },
+};
+
+Vue.use(Plugin, { baseUrl: process.env.VUE_APP_AXIOS_BASE_URL });

+ 37 - 0
src/plugins/check-res.js

@@ -0,0 +1,37 @@
+/* eslint-disable no-underscore-dangle */
+/* eslint-disable no-param-reassign */
+/* eslint-disable no-unused-vars */
+/* eslint-disable no-shadow */
+import Vue from 'vue';
+import _ from 'lodash';
+import { Toast } from 'vant';
+const vm = new Vue({});
+const Plugin = {
+  install(Vue, options) {
+    // 4. 添加实例方法
+    Vue.prototype.$checkRes = (res, okText, errText) => {
+      let _okText = okText;
+      let _errText = errText;
+      if (!_.isFunction(okText) && _.isObject(okText) && okText != null) {
+        ({ okText: _okText, errText: _errText } = okText);
+      }
+      const { errcode = 0, errmsg } = res || {};
+      if (errcode === 0) {
+        if (_.isFunction(_okText)) {
+          return _okText();
+        }
+        if (_okText) {
+          Toast({ type: 'success', message: _okText });
+        }
+        return true;
+      }
+      if (_.isFunction(_errText)) {
+        return _errText();
+      }
+      Toast({ type: 'danger', message: errText });
+      return false;
+    };
+  },
+};
+
+Vue.use(Plugin);

+ 11 - 0
src/plugins/components.js

@@ -0,0 +1,11 @@
+import Vue from 'vue';
+import footers from '@/components/footers.vue';
+import top from '@/layout/common/top.vue';
+import page from '@/layout/common/page.vue';
+const Plugin = (vue) => {
+  vue.component('footers', footers);
+  vue.component('top', top);
+  vue.component('page', page);
+};
+
+Vue.use(Plugin);

+ 63 - 0
src/plugins/couindex.js

@@ -0,0 +1,63 @@
+// 创新券
+// 类型
+export const couponsType = ['科技创新券', '研发补贴', '奖励兑现'];
+// 折扣类型
+export const discounTtype = ['全额折扣券', '折扣券', '定额券'];
+// 适用服务类型
+export const useType = ['服务类型1', '服务类型2', '服务类型3'];
+// 所属分类
+export const classify = ['分类1', '分类2', '分类3'];
+// 状态
+export const couponsStatus = [
+  { label: '待上架', value: '0' },
+  { label: '上架', value: '1' },
+  { label: '下架', value: '-1' },
+];
+// 创新券申领
+// 状态
+export const couponsapplyStatus = [
+  { label: '待审中', value: '0' },
+  { label: '通过', value: '1' },
+  { label: '拒绝', value: '-1' },
+];
+// 是否使用
+export const isuse = [
+  { label: '未使用', value: '0' },
+  { label: '已使用', value: '1' },
+];
+// 高企申报
+// 是否使用
+export const iscashing = [
+  { label: '未兑付', value: '0' },
+  { label: '已兑付', value: '1' },
+  // { label: '已兑付', value: '2' },
+];
+// 状态
+export const declareStatus = [
+  { label: '企业信息审核审核中', value: '0' },
+  { label: '企业信息审核拒绝', value: '-1' },
+  { label: '上传合同', value: '1' },
+  { label: '上传合同', value: '2' },
+  { label: '高企申报成功', value: '3' },
+];
+// 状态
+export const declareapplyStatus = [
+  { label: '待审中', value: '0' },
+  { label: '通过', value: '1' },
+  { label: '拒绝', value: '-1' },
+];
+// 研发补贴,奖励兑现
+// 状态
+export const rewardStatus = [
+  { label: '待审中', value: '0' },
+  { label: '通过', value: '1' },
+  { label: '拒绝', value: '-1' },
+];
+
+// 兑付
+// 状态
+export const cashStatus = [
+  { label: '待审中', value: '0' },
+  { label: '通过', value: '1' },
+  { label: '拒绝', value: '-1' },
+];

+ 5 - 0
src/plugins/element.js

@@ -0,0 +1,5 @@
+import Vue from 'vue';
+import Element from 'element-ui';
+import 'element-ui/lib/theme-chalk/index.css';
+
+Vue.use(Element);

+ 27 - 0
src/plugins/loading.js

@@ -0,0 +1,27 @@
+/* eslint-disable no-console */
+/* eslint-disable no-param-reassign */
+
+import Vue from 'vue';
+
+const Plugin = {
+  // eslint-disable-next-line no-unused-vars
+  install(vue, options) {
+    // 3. 注入组件
+    vue.mixin({
+      created() {
+        // eslint-disable-next-line no-underscore-dangle
+        const isRoot = this.constructor === Vue;
+        // console.log(`rootId:${rootVue_uid}; thisId:${this._uid}`);
+        // if (rootVue_uid !== 3) {
+        //   console.log(this);
+        // }
+        if (isRoot) {
+          const el = document.getElementById('loading');
+          if (el) el.style.display = 'none';
+        }
+      },
+    });
+  },
+};
+
+Vue.use(Plugin, { baseUrl: process.env.VUE_APP_AXIOS_BASE_URL });

+ 4 - 0
src/plugins/meta.js

@@ -0,0 +1,4 @@
+import Vue from 'vue';
+import Meta from 'vue-meta';
+
+Vue.use(Meta);

+ 20 - 0
src/plugins/setting.js

@@ -0,0 +1,20 @@
+import Vue from 'vue';
+
+Vue.config.weixin = {
+  // baseUrl: process.env.BASE_URL + 'weixin',
+  // baseUrl: 'http://10.16.8.209:9005',
+};
+
+Vue.config.stomp = {
+  // brokerURL: 'ws://http://free.liaoningdoupo.com/ws',
+  brokerURL: '/ws', // ws://${location.host}/ws
+  connectHeaders: {
+    host: 'visit',
+    login: 'visit', //visit
+    passcode: 'visit', //visit123
+  },
+  // debug: true,
+  reconnectDelay: 5000,
+  heartbeatIncoming: 4000,
+  heartbeatOutgoing: 4000,
+};

+ 65 - 0
src/plugins/stomp.js

@@ -0,0 +1,65 @@
+/**
+ * 基于WebStomp的消息处理插件
+ */
+
+import Vue from 'vue';
+import _ from 'lodash';
+import assert from 'assert';
+import { Client } from '@stomp/stompjs/esm6/client';
+
+const Plugin = {
+  install(Vue, options) {
+    assert(_.isObject(options));
+    if (options.debug && !_.isFunction(options.debug)) {
+      options.debug = (str) => {
+        console.log(str);
+      };
+    }
+    assert(_.isString(options.brokerURL));
+    if (!options.brokerURL.startsWith('ws://')) {
+      options.brokerURL = `ws://${location.host}${options.brokerURL}`;
+    }
+
+    // 3. 注入组件
+    Vue.mixin({
+      beforeDestroy: function () {
+        if (this.$stompClient) {
+          this.$stompClient.deactivate();
+          delete this.$stompClient;
+        }
+      },
+    });
+
+    // 4. 添加实例方法
+    Vue.prototype.$stomp = function (subscribes = {}) {
+      // connect to mq
+      const client = new Client(options);
+      client.onConnect = (frame) => {
+        // Do something, all subscribes must be done is this callback
+        // This is needed because this will be executed after a (re)connect
+        console.log('[stomp] connected');
+        Object.keys(subscribes)
+          .filter((p) => _.isFunction(subscribes[p]))
+          .forEach((key) => {
+            client.subscribe(key, subscribes[key]);
+          });
+      };
+
+      client.onStompError = (frame) => {
+        // Will be invoked in case of error encountered at Broker
+        // Bad login/passcode typically will cause an error
+        // Complaint brokers will set `message` header with a brief message. Body may contain details.
+        // Compliant brokers will terminate the connection after any error
+        console.log('Broker reported error: ' + frame.headers['message']);
+        console.log('Additional details: ' + frame.body);
+      };
+
+      client.activate();
+
+      this.$stompClient = client;
+    };
+  },
+};
+export default () => {
+  Vue.use(Plugin, Vue.config.stomp);
+};

+ 5 - 0
src/plugins/vant.js

@@ -0,0 +1,5 @@
+import Vue from 'vue';
+import Vant from 'vant';
+import 'vant/lib/index.css';
+
+Vue.use(Vant);

+ 3 - 0
src/plugins/weixin.js

@@ -0,0 +1,3 @@
+import Vue from 'vue';
+const wx = require('weixin-js-sdk');
+Vue.prototype.$wx = wx;

+ 566 - 0
src/router/index.js

@@ -0,0 +1,566 @@
+import Vue from 'vue';
+import VueRouter from 'vue-router';
+import store from '@/store/index';
+const jwt = require('jsonwebtoken');
+const originalPush = VueRouter.prototype.push;
+VueRouter.prototype.push = function push(location) {
+  return originalPush.call(this, location).catch((err) => err);
+};
+Vue.use(VueRouter);
+// 2021-07-07
+// 科创资讯
+const scientific = [
+  {
+    path: '/scientific/notice/index',
+    meta: { title: '科创资讯-通知通告' },
+    component: () => import('../views/scientific/notice/index.vue'),
+  },
+  {
+    path: '/scientific/notice/detail',
+    meta: { title: '通知通告-详细信息' },
+    component: () => import('../views/scientific/notice/detail.vue'),
+  },
+  {
+    path: '/scientific/analysis/index',
+    meta: { title: '科创资讯-政策信息' },
+    component: () => import('../views/scientific/analysis/index.vue'),
+  },
+  {
+    path: '/scientific/analysis/detail',
+    meta: { title: '政策信息-详细信息' },
+    component: () => import('../views/scientific/analysis/detail.vue'),
+  },
+  {
+    path: '/scientific/industry/index',
+    meta: { title: '科创资讯-吉药资讯' },
+    component: () => import('../views/scientific/industry/index.vue'),
+  },
+  {
+    path: '/scientific/industry/detail',
+    meta: { title: '吉药资讯-详细信息' },
+    component: () => import('../views/scientific/industry/detail.vue'),
+  },
+  {
+    path: '/scientific/viewpoint/index',
+    meta: { title: '科创资讯-智库视点' },
+    component: () => import('../views/scientific/viewpoint/index.vue'),
+  },
+  {
+    path: '/scientific/viewpoint/detail',
+    meta: { title: '智库视点-详细信息' },
+    component: () => import('../views/scientific/viewpoint/detail.vue'),
+  },
+  {
+    path: '/scientific/navigation/index',
+    meta: { title: '科创资讯-数据导航' },
+    component: () => import('../views/scientific/navigation/index.vue'),
+  },
+];
+// 服务在线
+const service = [
+  {
+    path: '/service/contract/index',
+    meta: { title: '服务在线-技术合同' },
+    component: () => import('../views/service/contract/index.vue'),
+  },
+  {
+    path: '/service/achieve/index',
+    meta: { title: '服务在线-成果评价' },
+    component: () => import('../views/service/achieve/index.vue'),
+  },
+  {
+    path: '/service/achieve/detail',
+    meta: { title: '成果评价-详细信息' },
+    component: () => import('../views/service/achieve/detail.vue'),
+  },
+  {
+    path: '/service/novelty/index',
+    meta: { title: '服务在线-查新服务' },
+    component: () => import('../views/service/novelty/index.vue'),
+  },
+  {
+    path: '/service/patent/index',
+    meta: { title: '服务在线-专利运营' },
+    component: () => import('../views/service/patent/index.vue'),
+  },
+  {
+    path: '/service/continue/index',
+    meta: { title: '服务在线-高企咨询' },
+    component: () => import('../views/service/continue/index.vue'),
+  },
+];
+// 交流互动
+const exchange = [
+  {
+    path: '/exchange/project/index',
+    meta: { title: '交流互动-项目征集' },
+    component: () => import('../views/exchange/project/index.vue'),
+  },
+  {
+    path: '/exchange/question/index',
+    meta: { title: '交流互动-调查问卷' },
+    component: () => import('../views/exchange/question/index.vue'),
+  },
+  {
+    path: '/exchange/business/index',
+    meta: { title: '交流互动-咨询服务' },
+    component: () => import('../views/exchange/business/index.vue'),
+  },
+  {
+    path: '/exchange/business/detail',
+    meta: { title: '咨询服务-详细信息' },
+    component: () => import('../views/exchange/business/detail.vue'),
+  },
+  {
+    path: '/exchange/center/index',
+    meta: { title: '个人中心' },
+    component: () => import('../views/exchange/center/index.vue'),
+  },
+  // 管理用户
+  {
+    path: '/exchange/center/adminCenter/mechanism/index',
+    meta: { title: '机构用户' },
+    component: () => import('../views/exchange/center/adminCenter/mechanism/index.vue'),
+  },
+  {
+    path: '/exchange/center/adminCenter/mechanism/detail',
+    meta: { title: '机构用户-详细信息' },
+    component: () => import('../views/exchange/center/adminCenter/mechanism/detail.vue'),
+  },
+  {
+    path: '/exchange/center/adminCenter/users/index',
+    meta: { title: '平台用户' },
+    component: () => import('../views/exchange/center/adminCenter/users/index.vue'),
+  },
+  {
+    path: '/exchange/center/adminCenter/users/detail',
+    meta: { title: '平台用户-详细信息' },
+    component: () => import('../views/exchange/center/adminCenter/users/detail.vue'),
+  },
+  // 机构用户
+  {
+    path: '/exchange/center/mechCenter/users/index',
+    meta: { title: '平台用户' },
+    component: () => import('../views/exchange/center/mechCenter/users/index.vue'),
+  },
+  {
+    path: '/exchange/center/mechCenter/users/detail',
+    meta: { title: '平台用户-详细信息' },
+    component: () => import('../views/exchange/center/mechCenter/users/detail.vue'),
+  },
+  // 平台用户-专利信息
+  {
+    path: '/exchange/center/mechCenter/patent/index',
+    meta: { title: '专利信息' },
+    component: () => import('../views/exchange/center/mechCenter/patent/index.vue'),
+  },
+  // 个人(企业)用户
+  {
+    path: '/exchange/center/userCenter/basic/index',
+    meta: { title: '基本信息' },
+    component: () => import('../views/exchange/center/userCenter/basic/index.vue'),
+  },
+  {
+    path: '/exchange/center/userCenter/password/index',
+    meta: { title: '修改密码' },
+    component: () => import('../views/exchange/center/userCenter/password/index.vue'),
+  },
+  // {
+  //   path: '/exchange/center/user/index',
+  //   meta: { title: '关联用户' },
+  //   component: () => import('../views/exchange/center/user/index.vue'),
+  // },
+];
+//专利运营-2021-08-27
+const zlyy = [
+  // 管理员-我的消息
+  // 管理员-咨询服务
+  {
+    path: '/service/patent/admin/message/service',
+    meta: { title: '咨询服务' },
+    component: () => import('../views/service/patent/admin/message/service.vue'),
+  },
+  {
+    path: '/service/patent/admin/message/service_detail',
+    meta: { title: '咨询服务-聊天详情' },
+    component: () => import('../views/service/patent/admin/message/service_detail.vue'),
+  },
+  // 管理员-通知信息
+  {
+    path: '/service/patent/admin/message/notice',
+    meta: { title: '通知信息' },
+    component: () => import('../views/service/patent/admin/message/notice.vue'),
+  },
+  {
+    path: '/service/patent/admin/message/notice_create',
+    meta: { title: '通知信息-编辑通知' },
+    component: () => import('../views/service/patent/admin/message/notice_create.vue'),
+  },
+  // 管理员-审核通知
+  {
+    path: '/service/patent/admin/message/examine',
+    meta: { title: '审核通知' },
+    component: () => import('../views/service/patent/admin/message/examine.vue'),
+  },
+  // 管理员-专利预警
+  {
+    path: '/service/patent/admin/message/warning',
+    meta: { title: '专利预警' },
+    component: () => import('../views/service/patent/admin/message/warning.vue'),
+  },
+  // 管理员-专利审核
+  {
+    path: '/service/patent/admin/examine/patent',
+    meta: { title: '专利申请' },
+    component: () => import('../views/service/patent/admin/examine/patent.vue'),
+  },
+  // 国知局反馈消息
+  {
+    path: '/service/patent/admin/examine/hairmess',
+    meta: { title: '分发消息' },
+    component: () => import('../views/service/patent/admin/examine/hairmess.vue'),
+  },
+  {
+    path: '/service/patent/admin/examine/hairmess_create',
+    meta: { title: '分发消息-添加消息' },
+    component: () => import('../views/service/patent/admin/examine/hairmess_create.vue'),
+  },
+  {
+    path: '/service/patent/admin/examine/hairmess_autoCreate',
+    meta: { title: '分发消息-自动分发消息' },
+    component: () => import('../views/service/patent/admin/examine/hairmess_autoCreate.vue'),
+  },
+  {
+    path: '/service/patent/admin/examine/analysis',
+    meta: { title: '查新检索' },
+    component: () => import('../views/service/patent/admin/examine/analysis.vue'),
+  },
+  // 管理员-专利申请管理
+  {
+    path: '/service/patent/admin/patent/info',
+    meta: { title: '专利信息' },
+    component: () => import('../views/service/patent/admin/patent/info.vue'),
+  },
+  {
+    path: '/service/patent/admin/patent/info_create',
+    meta: { title: '专利信息-添加专利' },
+    component: () => import('../views/service/patent/admin/patent/info_create.vue'),
+  },
+  {
+    path: '/service/patent/admin/patent/info_import',
+    meta: { title: '专利信息-导入专利' },
+    component: () => import('../views/service/patent/admin/patent/info_import.vue'),
+  },
+  {
+    path: '/service/patent/admin/patent/info_result',
+    meta: { title: '专利信息-导出结果' },
+    component: () => import('../views/service/patent/admin/patent/info_result.vue'),
+  },
+  // 管理员-价值评估管理
+  {
+    path: '/service/patent/admin/patent/assessment',
+    meta: { title: '价值评估' },
+    component: () => import('../views/service/patent/admin/patent/assessment.vue'),
+  },
+  {
+    path: '/service/patent/admin/patent/assessment_examine',
+    meta: { title: '价值评估-审核信息' },
+    component: () => import('../views/service/patent/admin/patent/assessment_examine.vue'),
+  },
+  // 管理员-专利交易管理
+  {
+    path: '/service/patent/admin/patent/trans',
+    meta: { title: '专利交易' },
+    component: () => import('../views/service/patent/admin/patent/trans.vue'),
+  },
+  {
+    path: '/service/patent/admin/patent/trans_info',
+    meta: { title: '专利交易-详细信息' },
+    component: () => import('../views/service/patent/admin/patent/trans_info.vue'),
+  },
+  // 机构用户
+  // 机构用户-我的消息
+  {
+    path: '/service/patent/mech/message/unRead',
+    meta: { title: '未读信息' },
+    component: () => import('../views/service/patent/mech/message/unRead.vue'),
+  },
+  {
+    path: '/service/patent/mech/message/read',
+    meta: { title: '已读信息' },
+    component: () => import('../views/service/patent/mech/message/read.vue'),
+  },
+  {
+    path: '/service/patent/mech/message/notice',
+    meta: { title: '通知信息' },
+    component: () => import('../views/service/patent/mech/message/notice.vue'),
+  },
+  {
+    path: '/service/patent/mech/message/notice_create',
+    meta: { title: '通知信息-编辑通知' },
+    component: () => import('../views/service/patent/mech/message/notice_create.vue'),
+  },
+  // 机构用户-我的审核
+  {
+    path: '/service/patent/mech/examine/patent',
+    meta: { title: '专利审核' },
+    component: () => import('../views/service/patent/mech/examine/patent.vue'),
+  },
+  {
+    path: '/service/patent/mech/examine/contract',
+    meta: { title: '合同审核' },
+    component: () => import('../views/service/patent/mech/examine/contract.vue'),
+  },
+  {
+    path: '/service/patent/mech/examine/contract_check',
+    meta: { title: '合同审核-详细信息' },
+    component: () => import('../views/service/patent/mech/examine/contract_check.vue'),
+  },
+  {
+    path: '/service/patent/mech/examine/trans',
+    meta: { title: '交易审核' },
+    component: () => import('../views/service/patent/mech/examine/trans.vue'),
+  },
+  // 机构用户-我的专利
+  {
+    path: '/service/patent/mech/patent/information',
+    meta: { title: '专利信息' },
+    component: () => import('../views/service/patent/mech/patent/information/index.vue'),
+  },
+  {
+    path: '/service/patent/mech/patent/information/detail',
+    meta: { title: '专利信息-详细信息' },
+    component: () => import('../views/service/patent/mech/patent/information/detail.vue'),
+  },
+  {
+    path: '/service/patent/mech/patent/navigation',
+    meta: { title: '查新检索' },
+    component: () => import('../views/service/patent/mech/patent/navigation/index.vue'),
+  },
+  {
+    path: '/service/patent/mech/patent/navigation/info',
+    meta: { title: '查新检索-详细信息' },
+    component: () => import('../views/service/patent/mech/patent/navigation/info.vue'),
+  },
+  {
+    path: '/service/patent/mech/patent/early',
+    meta: { title: '专利预警' },
+    component: () => import('../views/service/patent/mech/patent/early/index.vue'),
+  },
+  // 机构用户-我的交易
+  {
+    path: '/service/patent/mech/transaction/index',
+    meta: { title: '专利交易' },
+    component: () => import('../views/service/patent/mech/transaction/index.vue'),
+  },
+  {
+    path: '/service/patent/mech/transaction/info',
+    meta: { title: '专利交易-详细信息' },
+    component: () => import('../views/service/patent/mech/transaction/info.vue'),
+  },
+  // 用户
+  // 用户-我的消息
+  {
+    path: '/service/patent/user/message/unRead',
+    meta: { title: '未读信息查看' },
+    component: () => import('../views/service/patent/user/message/unRead.vue'),
+  },
+  {
+    path: '/service/patent/user/message/read',
+    meta: { title: '已读信息查看' },
+    component: () => import('../views/service/patent/user/message/read.vue'),
+  },
+  {
+    path: '/service/patent/user/message/notice',
+    meta: { title: '通知查看' },
+    component: () => import('../views/service/patent/user/message/notice.vue'),
+  },
+  {
+    path: '/service/patent/user/message/read_chat',
+    meta: { title: '聊天' },
+    component: () => import('../views/service/patent/user/message/read_chat.vue'),
+  },
+  {
+    path: '/service/patent/user/chat/index',
+    meta: { title: '咨詢服务' },
+    component: () => import('../views/service/patent/user/chat/index.vue'),
+  },
+  // 用户-我的申请
+  // 用户-专利申请
+  {
+    path: '/service/patent/user/apply/apply',
+    meta: { title: '专利申请' },
+    component: () => import('../views/service/patent/user/apply/apply/index.vue'),
+  },
+  {
+    path: '/service/patent/user/apply/apply/detail',
+    meta: { title: '专利申请-审批单' },
+    component: () => import('../views/service/patent/user/apply/apply/detail.vue'),
+  },
+  {
+    path: '/service/patent/user/apply/apply/result',
+    meta: { title: '专利申请-审核结果' },
+    component: () => import('../views/service/patent/user/apply/apply/result.vue'),
+  },
+  {
+    path: '/service/patent/user/apply/apply/gzjDetail',
+    meta: { title: '专利申请-国知局信息' },
+    component: () => import('../views/service/patent/user/apply/apply/gzjDetail.vue'),
+  },
+
+  // 用户-查新检索
+  {
+    path: '/service/patent/user/apply/analysis',
+    meta: { title: '查新检索' },
+    component: () => import('../views/service/patent/user/apply/analysis/index.vue'),
+  },
+  {
+    path: '/service/patent/user/apply/analysis/detail',
+    meta: { title: '查新检索-交底书' },
+    component: () => import('../views/service/patent/user/apply/analysis/detail.vue'),
+  },
+  {
+    path: '/service/patent/user/apply/analysis/result',
+    meta: { title: '查新检索-审核结果' },
+    component: () => import('../views/service/patent/user/apply/analysis/result.vue'),
+  },
+  // 用户-价值评估
+  {
+    path: '/service/patent/user/apply/assessment',
+    meta: { title: '价值评估' },
+    component: () => import('../views/service/patent/user/apply/assessment/index.vue'),
+  },
+  {
+    path: '/service/patent/user/apply/assessment/detail',
+    meta: { title: '价值评估-申请评估' },
+    component: () => import('../views/service/patent/user/apply/assessment/detail.vue'),
+  },
+  {
+    path: '/service/patent/user/apply/assessment/result',
+    meta: { title: '价值评估-审核结果' },
+    component: () => import('../views/service/patent/user/apply/assessment/result.vue'),
+  },
+  // 用户-我的专利
+  {
+    path: '/service/patent/user/patent/information',
+    meta: { title: '专利信息' },
+    component: () => import('../views/service/patent/user/patent/information/index.vue'),
+  },
+  {
+    path: '/service/patent/user/patent/information/detail',
+    meta: { title: '专利信息-详细信息' },
+    component: () => import('../views/service/patent/user/patent/information/detail.vue'),
+  },
+  {
+    path: '/service/patent/user/patent/information/trans_create',
+    meta: { title: '专利信息-发起交易' },
+    component: () => import('../views/service/patent/user/patent/information/trans_create.vue'),
+  },
+  // 用户-专利导航
+  {
+    path: '/service/patent/user/patent/navigation',
+    meta: { title: '专利导航' },
+    component: () => import('../views/service/patent/user/patent/navigation/index.vue'),
+  },
+  // 用户-专利预警
+  {
+    path: '/service/patent/user/patent/early',
+    meta: { title: '专利预警' },
+    component: () => import('../views/service/patent/user/patent/early/index.vue'),
+  },
+  // 用户-专利交易
+  {
+    path: '/service/patent/user/transaction/index',
+    meta: { title: '专利交易' },
+    component: () => import('../views/service/patent/user/transaction/index.vue'),
+  },
+  {
+    path: '/service/patent/user/transaction/info',
+    meta: { title: '专利交易-详细信息' },
+    component: () => import('../views/service/patent/user/transaction/info.vue'),
+  },
+  {
+    path: '/service/patent/user/transaction/contract',
+    meta: { title: '专利交易-填写合同' },
+    component: () => import('../views/service/patent/user/transaction/contract.vue'),
+  },
+  // 公共专利
+  {
+    path: '/service/patent/market/index',
+    meta: { title: '专利超市' },
+    component: () => import('../views/service/patent/market/index.vue'),
+  },
+  {
+    path: '/service/patent/market/detail',
+    meta: { title: '专利超市-专利信息' },
+    component: () => import('../views/service/patent/market/detail.vue'),
+  },
+  {
+    path: '/service/patent/market/transDetail',
+    meta: { title: '专利超市-交易信息' },
+    component: () => import('../views/service/patent/market/transDetail.vue'),
+  },
+];
+const web = [
+  {
+    path: '/',
+    name: 'index',
+    meta: { title: '网站首页' },
+    component: () => import('../views/index.vue'),
+  },
+  ...scientific,
+  ...service,
+  ...exchange,
+  ...zlyy,
+  {
+    path: '/login',
+    name: 'login',
+    meta: { title: '登录', key: 'login' },
+    component: () => import('../views/login.vue'),
+  },
+  {
+    path: '/register',
+    name: 'register',
+    meta: { title: '账户注册', key: 'register' },
+    component: () => import('../views/register.vue'),
+  },
+];
+const routes = [...web];
+const router = new VueRouter({
+  mode: 'history',
+  base: process.env.VUE_APP_ROUTER,
+  routes,
+});
+router.beforeEach((to, from, next) => {
+  // let openid = 'oFqNO6VHEEwnMB_l1AD3pooBAkHk';
+  let openid = to.query.openid;
+  sessionStorage.setItem('openid', openid);
+  document.title = `${to.meta.title} `;
+  const token = localStorage.getItem('token');
+  // 不带参数
+  if (to.path == '/exchange/center/index') {
+    if (!token) {
+      next(`/login?path=${to.path}&&type=1`);
+    } else {
+      let user = jwt.decode(token);
+      store.commit('setUser', user, { root: true });
+      next();
+    }
+    // 带参数
+    // } else if (to.path == '/finance/apply') {
+    //   if (!token) {
+    //     next(`/login?path=${to.fullPath}`);
+    //   } else {
+    //     let user = jwt.decode(token);
+    //     store.commit('setUser', user, { root: true });
+    //     next();
+    //   }
+    //   // 已登录
+  } else {
+    let user = jwt.decode(token);
+    store.commit('setUser', user, { root: true });
+    next();
+  }
+});
+
+export default router;

+ 122 - 0
src/store/index.js

@@ -0,0 +1,122 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import * as ustate from '@common/src/store/user/state';
+import * as umutations from '@common/src/store/user/mutations';
+import statistics from '@common/src/store/statistics';
+import upload from './upload';
+import news from '@common/src/store/news';
+import column from '@common/src/store/column';
+import viewPoint from '@common/src/store/viewPoint';
+import questionnaire from '@common/src/store/question/questionnaire';
+import answer from '@common/src/store/question/answer';
+import question from '@common/src/store/question';
+import projectsolic from '@common/src/store/projectsolic';
+import organization from '@common/src/store/organization';
+import personal from '@common/src/store/personal';
+import expert from '@common/src/store/expert';
+import product from '@common/src/store/product';
+import patent from '@common/src/store/patent';
+import disclosure from '@common/src/store/patent/disclosure';
+import report from '@common/src/store/patent/report';
+import notice from '@common/src/store/patent/notice';
+import sell from '@common/src/store/patent/sell';
+import purchase from '@common/src/store/patent/purchase';
+import tradeorder from '@common/src/store/patent/tradeorder';
+// 直播平台
+import mechanism from './live/mechanism';
+import coupons from './live/coupons';
+import couponsApply from './live/couponsApply';
+import declare from './live/declare';
+import cashing from './live/cashing';
+import reward from './live/reward';
+// 成果评价
+import achieveApply from '@common/src/store/achieve/achieve_apply.js';
+
+// 管理员
+import adminLogin from '@common/src/store/adminLogin';
+// 邀请码
+import inviteCode from '@common/src/store/inviteCode';
+// 2021-08-21
+// 聊天
+import patentchat from '@common/src/store/patent/patentchat';
+// 审核通知
+import patentexamine from '@common/src/store/patent/patentexamine';
+// 通知
+import patentnotice from '@common/src/store/patent/patentnotice';
+// 专利申请
+import patentapply from '@common/src/store/patent/patentapply';
+// 专利申请预警表
+import patentwarning from '@common/src/store/patent/patentwarning';
+// 查新检索
+import patentanalysis from '@common/src/store/patent/patentanalysis';
+// 价值评估
+import patentassess from '@common/src/store/patent/patentassess';
+// 专利信息
+import patentinfo from '@common/src/store/patent/patentinfo';
+// 已授权专利预警表
+import patentearly from '@common/src/store/patent/patentearly';
+
+// 专利交易
+import patenttrans from '@common/src/store/patent/patenttrans';
+import mission from '@common/src/store/mission';
+const _ = require('lodash');
+
+Vue.use(Vuex);
+
+export default new Vuex.Store({
+  state: {
+    ...ustate,
+  },
+  mutations: {
+    ...umutations,
+  },
+  actions: {},
+  modules: {
+    statistics,
+    upload,
+    column,
+    news,
+    viewPoint,
+    questionnaire,
+    answer,
+    question,
+    projectsolic,
+    organization,
+    personal,
+    expert,
+    product,
+    patent,
+    // 直播平台
+    mechanism,
+    coupons,
+    couponsApply,
+    declare,
+    cashing,
+    reward,
+    // 成果评价
+    achieveApply,
+    // 交底书
+    disclosure,
+    report,
+    notice,
+    // 管理员
+    adminLogin,
+    inviteCode,
+    // 专利交易
+    sell,
+    purchase,
+    tradeorder,
+    // 专利运营
+    patentchat,
+    patentexamine,
+    patentnotice,
+    patentapply,
+    patentwarning,
+    patentanalysis,
+    patentassess,
+    patentinfo,
+    patentearly,
+    patenttrans,
+    mission,
+  },
+});

+ 46 - 0
src/store/live/cashing.js

@@ -0,0 +1,46 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+Vue.use(Vuex);
+const api = {
+  cashing: `/api/live/v0/cysci/cashing`,
+};
+const state = () => ({});
+const mutations = {};
+
+const actions = {
+  async query({ commit }, { skip = 0, limit, ...info } = {}) {
+    const res = await this.$axios.$get(`${api.cashing}`, {
+      skip,
+      limit,
+      ...info,
+    });
+    return res;
+  },
+  async create({ commit }, payload) {
+    const res = await this.$axios.$post(`${api.cashing}`, payload);
+    return res;
+  },
+  async fetch({ commit }, payload) {
+    const res = await this.$axios.$get(`${api.cashing}/${payload}`);
+    return res;
+  },
+  async update({ commit }, { id, ...data }) {
+    const res = await this.$axios.$post(`${api.cashing}/update/${id}`, data);
+    return res;
+  },
+  async delete({ commit }, payload) {
+    const res = await this.$axios.$delete(`${api.cashing}/${payload}`);
+    return res;
+  },
+  async fromFetch({ commit }, payload) {
+    const res = await this.$axios.$get(`${api.cashing}/from/${payload}`);
+    return res;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};

+ 43 - 0
src/store/live/coupons.js

@@ -0,0 +1,43 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+Vue.use(Vuex);
+const api = {
+  coupons: `/api/live/v0/cysci/coupons`,
+};
+const state = () => ({});
+const mutations = {};
+
+const actions = {
+  async query({ commit }, { skip = 0, limit, ...info } = {}) {
+    const res = await this.$axios.$get(`${api.coupons}`, {
+      skip,
+      limit,
+      ...info,
+    });
+    return res;
+  },
+  async create({ commit }, payload) {
+    const res = await this.$axios.$post(`${api.coupons}`, payload);
+    return res;
+  },
+  async fetch({ commit }, payload) {
+    const res = await this.$axios.$get(`${api.coupons}/${payload}`);
+    return res;
+  },
+  async update({ commit }, { id, ...data }) {
+    const res = await this.$axios.$post(`${api.coupons}/update/${id}`, data);
+    return res;
+  },
+
+  async delete({ commit }, payload) {
+    const res = await this.$axios.$delete(`${api.coupons}/${payload}`);
+    return res;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};

+ 43 - 0
src/store/live/couponsApply.js

@@ -0,0 +1,43 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+Vue.use(Vuex);
+const api = {
+  couponsApply: `/api/live/v0/cysci/couponsApply`,
+};
+const state = () => ({});
+const mutations = {};
+
+const actions = {
+  async query({ commit }, { skip = 0, limit, ...info } = {}) {
+    const res = await this.$axios.$get(`${api.couponsApply}`, {
+      skip,
+      limit,
+      ...info,
+    });
+    return res;
+  },
+  async create({ commit }, payload) {
+    const res = await this.$axios.$post(`${api.couponsApply}`, payload);
+    return res;
+  },
+  async fetch({ commit }, payload) {
+    const res = await this.$axios.$get(`${api.couponsApply}/${payload}`);
+    return res;
+  },
+  async update({ commit }, { id, ...data }) {
+    const res = await this.$axios.$post(`${api.couponsApply}/update/${id}`, data);
+    return res;
+  },
+
+  async delete({ commit }, payload) {
+    const res = await this.$axios.$delete(`${api.couponsApply}/${payload}`);
+    return res;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};

+ 43 - 0
src/store/live/declare.js

@@ -0,0 +1,43 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+import { registerCoordinateSystem } from 'echarts';
+Vue.use(Vuex);
+const api = {
+  declare: `/api/live/v0/cysci/declare`,
+};
+const state = () => ({});
+const mutations = {};
+
+const actions = {
+  async query({ commit }, { skip = 0, limit, ...info } = {}) {
+    const res = await this.$axios.$get(`${api.declare}`, {
+      skip,
+      limit,
+      ...info,
+    });
+    return res;
+  },
+  async create({ commit }, payload) {
+    const res = await this.$axios.$post(`${api.declare}`, payload);
+    return res;
+  },
+  async fetch({ commit }, payload) {
+    const res = await this.$axios.$get(`${api.declare}/${payload}`);
+    return res;
+  },
+  async update({ commit }, { id, ...data }) {
+    const res = await this.$axios.$post(`${api.declare}/update/${id}`, data);
+    return res;
+  },
+  async delete({ commit }, payload) {
+    const res = await this.$axios.$delete(`${api.declare}/${payload}`);
+    return res;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};

+ 58 - 0
src/store/live/mechanism.js

@@ -0,0 +1,58 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+Vue.use(Vuex);
+const api = {
+  mechanism: `/api/live/v0/cysci/mechanism`,
+};
+const state = () => ({});
+const mutations = {};
+
+const actions = {
+  async query({ commit }, { skip = 0, limit, ...info } = {}) {
+    const res = await this.$axios.$get(`${api.mechanism}`, {
+      skip,
+      limit,
+      ...info,
+    });
+    return res;
+  },
+  async create({ commit }, payload) {
+    const res = await this.$axios.$post(`${api.mechanism}`, payload);
+    return res;
+  },
+  async fetch({ commit }, payload) {
+    const res = await this.$axios.$get(`${api.mechanism}/${payload}`);
+    return res;
+  },
+  async update({ commit }, { id, ...data }) {
+    const res = await this.$axios.$post(`${api.mechanism}/update/${id}`, data);
+    return res;
+  },
+
+  async delete({ commit }, payload) {
+    const res = await this.$axios.$delete(`${api.mechanism}/${payload}`);
+    return res;
+  },
+  async password({ commit }, { id, passwd }) {
+    const res = await this.$axios.$post(`${api.mechanism}/password/${id}`, { passwd });
+    return res;
+  },
+  async login({ commit }, payload) {
+    const res = await this.$axios.$post(`${api.mechanism}/login`, payload);
+    const jwt = require('jsonwebtoken');
+    if (res.errcode === 0) {
+      localStorage.setItem('token', res.data);
+      localStorage.setItem('type', 'ZJJG');
+      const user = jwt.decode(res.data);
+      commit('setUser', user, { root: true });
+    }
+    return res;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};

+ 43 - 0
src/store/live/reward.js

@@ -0,0 +1,43 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+Vue.use(Vuex);
+const api = {
+  reward: `/api/live/v0/cysci/reward`,
+};
+const state = () => ({});
+const mutations = {};
+
+const actions = {
+  async query({ commit }, { skip = 0, limit, ...info } = {}) {
+    const res = await this.$axios.$get(`${api.reward}`, {
+      skip,
+      limit,
+      ...info,
+    });
+    return res;
+  },
+  async create({ commit }, payload) {
+    const res = await this.$axios.$post(`${api.reward}`, payload);
+    return res;
+  },
+  async fetch({ commit }, payload) {
+    const res = await this.$axios.$get(`${api.reward}/${payload}`);
+    return res;
+  },
+  async update({ commit }, { id, ...data }) {
+    const res = await this.$axios.$post(`${api.reward}/update/${id}`, data);
+    return res;
+  },
+
+  async delete({ commit }, payload) {
+    const res = await this.$axios.$delete(`${api.reward}/${payload}`);
+    return res;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};

+ 25 - 0
src/store/upload.js

@@ -0,0 +1,25 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+import axios from 'axios';
+Vue.use(Vuex);
+const api = {
+  upload: (dir) => `/files/jlstcompany/${dir}/upload`,
+};
+const state = () => ({});
+const mutations = {};
+
+const actions = {
+  async upload({ commit }, { file, dir }) {
+    var formdata = new FormData();
+    formdata.append('file', file, file.name);
+    const res = await axios.post(api.upload(dir), formdata, { headers: { 'Content-Type': 'multipart/form-data' } });
+    return res.data;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};

+ 117 - 0
src/util/axios-wrapper.js

@@ -0,0 +1,117 @@
+/* eslint-disable no-console */
+/* eslint-disable no-param-reassign */
+
+import _ from 'lodash';
+import Axios from 'axios';
+import { Util, Error } from 'naf-core';
+// import { Indicator } from 'mint-ui';
+import util from './user-util';
+
+const { trimData, isNullOrUndefined } = Util;
+const { ErrorCode } = Error;
+
+let currentRequests = 0;
+
+export default class AxiosWrapper {
+  constructor({ baseUrl = '', unwrap = true } = {}) {
+    this.baseUrl = baseUrl;
+    this.unwrap = unwrap;
+  }
+
+  // 替换uri中的参数变量
+  static merge(uri, query = {}) {
+    if (!uri.includes(':')) {
+      return uri;
+    }
+    const keys = [];
+    const regexp = /\/:([a-z0-9_]+)/gi;
+    let res;
+    // eslint-disable-next-line no-cond-assign
+    while ((res = regexp.exec(uri)) != null) {
+      keys.push(res[1]);
+    }
+    keys.forEach((key) => {
+      if (!isNullOrUndefined(query[key])) {
+        uri = uri.replace(`:${key}`, query[key]);
+      }
+    });
+    return uri;
+  }
+
+  $get(uri, query, options) {
+    return this.$request(uri, null, query, options);
+  }
+
+  $post(uri, data = {}, query, options) {
+    return this.$request(uri, data, query, options);
+  }
+  $delete(uri, data = {}, router, query, options = {}) {
+    options = { ...options, method: 'delete' };
+    return this.$request(uri, data, query, options, router);
+  }
+  async $request(uri, data, query, options) {
+    // TODO: 合并query和options
+    if (_.isObject(query) && _.isObject(options)) {
+      options = { ...options, params: query, method: 'get' };
+    } else if (_.isObject(query) && !query.params) {
+      options = { params: query };
+    } else if (_.isObject(query) && query.params) {
+      options = query;
+    }
+    if (!options) options = {};
+    if (options.params) options.params = trimData(options.params);
+    const url = AxiosWrapper.merge(uri, options.params);
+    currentRequests += 1;
+    // Indicator.open({
+    //   spinnerType: 'fading-circle',
+    // });
+
+    try {
+      const axios = Axios.create({
+        baseURL: this.baseUrl,
+      });
+      axios.defaults.headers.common.Authorization = util.token;
+      let res = await axios.request({
+        method: isNullOrUndefined(data) ? 'get' : 'post',
+        url,
+        data,
+        responseType: 'json',
+        ...options,
+      });
+      res = res.data;
+      const { errcode, errmsg, details } = res;
+      if (errcode) {
+        console.warn(`[${uri}] fail: ${errcode}-${errmsg} ${details}`);
+        return res;
+      }
+      // unwrap data
+      if (this.unwrap) {
+        res = _.omit(res, ['errmsg', 'details']);
+        const keys = Object.keys(res);
+        if (keys.length === 1 && keys.includes('data')) {
+          res = res.data;
+        }
+      }
+      return res;
+    } catch (err) {
+      let errmsg = '接口请求失败,请稍后重试';
+      if (err.response) {
+        const { status } = err.response;
+        if (status === 401) errmsg = '用户认证失败,请重新登录';
+        if (status === 403) errmsg = '当前用户不允许执行该操作';
+      }
+      console.error(
+        `[AxiosWrapper] 接口请求失败: ${err.config && err.config.url} - 
+        ${err.message}`
+      );
+      return { errcode: ErrorCode.SERVICE_FAULT, errmsg, details: err.message };
+    } finally {
+      /* eslint-disable */
+      currentRequests -= 1;
+      if (currentRequests <= 0) {
+        currentRequests = 0;
+        // Indicator.close();
+      }
+    }
+  }
+}

+ 50 - 0
src/util/methods-util.js

@@ -0,0 +1,50 @@
+import { Util } from 'naf-core';
+
+const { isNullOrUndefined } = Util;
+
+export default {
+  //判断信息是否过期
+  isDateOff(dataDate) {
+    const now = new Date(new Date().getTime() - 24 * 60 * 60 * 1000);
+    dataDate = new Date(dataDate);
+    return now.getTime() <= dataDate.getTime();
+  },
+  //判断企业是否可以执行此动作/显示
+  checkCorp(data) {
+    const { role, unit, selfUnit, status, displayType, userid } = data;
+    if (!isNullOrUndefined(selfUnit) && !isNullOrUndefined(status)) {
+      return role === 'corp' && selfUnit === unit && status === '0';
+    } else if (!isNullOrUndefined(displayType)) {
+      if (role === 'corp') {
+        return role === displayType;
+      } else {
+        return role === displayType && !isNullOrUndefined(userid);
+      }
+    }
+  },
+  //获取url的参数params
+  getParams() {
+    let str = location.href;
+    let num = str.indexOf('?');
+    const param = {};
+    str = str.substr(num + 1);
+    let num2 = str.indexOf('#');
+    let str2 = '';
+    if (num2 > 0) {
+      str2 = str.substr(0, num2);
+    } else {
+      num2 = str.indexOf('/');
+      str2 = str.substr(0, num2);
+    }
+    const arr = str2.split('&');
+    for (let i = 0; i < arr.length; i++) {
+      num = arr[i].indexOf('=');
+      if (num > 0) {
+        const name = arr[i].substring(0, num);
+        const value = arr[i].substr(num + 1);
+        param[name] = decodeURI(value);
+      }
+    }
+    return param;
+  },
+};

+ 69 - 0
src/util/user-util.js

@@ -0,0 +1,69 @@
+/* eslint-disable no-console */
+export default {
+  get user() {
+    const val = sessionStorage.getItem('user');
+    try {
+      if (val) return JSON.parse(val);
+    } catch (err) {
+      console.error(err);
+    }
+    return null;
+  },
+  set user(userinfo) {
+    sessionStorage.setItem('user', JSON.stringify(userinfo));
+  },
+  get token() {
+    return sessionStorage.getItem('token');
+  },
+  set token(token) {
+    sessionStorage.setItem('token', token);
+  },
+  get openid() {
+    return sessionStorage.getItem('openid');
+  },
+  set openid(openid) {
+    sessionStorage.setItem('openid', openid);
+  },
+  get isGuest() {
+    return !this.user || this.user.role === 'guest';
+  },
+  save({ userinfo, token }) {
+    sessionStorage.setItem('user', JSON.stringify(userinfo));
+    sessionStorage.setItem('token', token);
+  },
+
+  get corpInfo() {
+    const val = sessionStorage.getItem('corpInfo');
+    if (val) return JSON.parse(val);
+    return null;
+  },
+  set corpInfo(corpInfo) {
+    sessionStorage.setItem('corpInfo', JSON.stringify(corpInfo));
+  },
+  saveCorpInfo(corpInfo) {
+    sessionStorage.setItem('corpInfo', JSON.stringify(corpInfo));
+  },
+
+  get unit() {
+    const val = sessionStorage.getItem('unit');
+    if (val) return JSON.parse(val);
+    return null;
+  },
+  set unit(unitList) {
+    sessionStorage.setItem('unit', JSON.stringify(unitList));
+  },
+  saveUnit(unitList) {
+    sessionStorage.setItem('unit', JSON.stringify(unitList));
+  },
+  get userInfo() {
+    const val = sessionStorage.getItem('userInfo');
+    if (val) return JSON.parse(val);
+    return null;
+  },
+  set userInfo(userInfo) {
+    sessionStorage.setItem('userInfo', JSON.stringify(userInfo));
+  },
+  saveUserInfo(userInfo) {
+    sessionStorage.setItem('userInfo', JSON.stringify(userInfo));
+  },
+};

+ 84 - 0
src/views/company/business/detail.vue

@@ -0,0 +1,84 @@
+<template>
+  <div id="detail">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="top">
+          <top topType="2" @back="back"></top>
+        </el-col>
+        <el-col :span="24" class="info" :style="{ height: clientHeight + 'px' }">
+          <frame-detail :form="form"></frame-detail>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import frameDetail from '../parts/detail_3.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: product } = createNamespacedHelpers('product');
+export default {
+  name: 'detail',
+  props: {},
+  components: {
+    frameDetail,
+  },
+  data: function () {
+    return {
+      clientHeight: '',
+      form: {},
+    };
+  },
+  async created() {
+    if (this.id) await this.search();
+  },
+  methods: {
+    ...product(['fetch']),
+    async search() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `form`, res.data);
+      }
+    },
+    // 查看详情
+    back() {
+      this.$router.push({ path: '/company/business/index' });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  mounted() {
+    let clientHeight = (document.documentElement.clientHeight || document.body.clientHeight) - 40;
+    this.$set(this, `clientHeight`, clientHeight);
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .top {
+    height: 40px;
+    overflow: hidden;
+    border-bottom: 1px solid #f9f9f9;
+  }
+  .info {
+    overflow-x: hidden;
+    overflow-y: auto;
+    padding: 0 8px;
+  }
+}
+</style>

+ 99 - 0
src/views/company/business/index.vue

@@ -0,0 +1,99 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="top">
+          <top topType="1" @search="search"></top>
+        </el-col>
+        <el-col :span="24" class="info" :style="{ height: clientHeight + 'px' }">
+          <frame-list :list="list" @detail="detail"></frame-list>
+        </el-col>
+        <el-col :span="24" class="page">
+          <page :limit="limit" :total="total" @search="search" />
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import frameList from '../parts/list_3.vue';
+import page from '@/layout/common/page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: product } = createNamespacedHelpers('product');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    frameList,
+    page,
+  },
+  data: function () {
+    return {
+      clientHeight: '',
+      column: {},
+      list: [],
+      total: 0,
+      limit: 10,
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...product(['query']),
+    async search({ skip = 0, limit = this.limit, searchName, ...info } = {}) {
+      if (searchName) info.name = searchName;
+      info.type = '2';
+      info.status = '2';
+      let res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+      }
+    },
+    // 查看详情
+    detail(data) {
+      this.$router.push({ path: '/company/business/detail', query: { id: data._id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  mounted() {
+    let clientHeight = (document.documentElement.clientHeight || document.body.clientHeight) - 80;
+    this.$set(this, `clientHeight`, clientHeight);
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .top {
+    height: 40px;
+    overflow: hidden;
+    border-bottom: 1px solid #f9f9f9;
+  }
+  .info {
+    overflow-x: hidden;
+    overflow-y: auto;
+    background-color: #f1f1f1;
+    padding: 0 8px;
+  }
+  .page {
+    height: 40px;
+    overflow: hidden;
+    border-top: 1px solid #f1f1f1;
+  }
+}
+</style>

+ 167 - 0
src/views/company/innovate/achieve/index.vue

@@ -0,0 +1,167 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main" :style="{ height: clientHeight + 'px' }">
+        <van-form>
+          <van-col span="24" class="one" v-if="active == '1'">
+            <top title="基本信息"></top>
+            <frame-basic :basic="form.basic"></frame-basic>
+            <van-col span="24" class="btn">
+              <van-button type="primary" @click="timeBtn">临时保存</van-button>
+              <van-button type="info" @click="next('2')">下一页</van-button>
+            </van-col>
+          </van-col>
+          <van-col span="24" class="two" v-else-if="active == '2'">
+            <top title="信息简介"></top>
+            <frame-brief :brief="form.brief"></frame-brief>
+            <van-col span="24" class="btn">
+              <van-button type="info" @click="up('1')">上一页</van-button>
+              <van-button type="primary" @click="timeBtn">临时保存</van-button>
+              <van-button type="info" @click="next('3')">下一页</van-button>
+            </van-col>
+          </van-col>
+          <van-col span="24" class="thr" v-else-if="active == '3'">
+            <top title="主研人员名单"></top>
+            <frame-research :research="form.research"></frame-research>
+            <van-col span="24" class="btn">
+              <van-button type="info" @click="up('2')">上一页</van-button>
+              <van-button type="primary" @click="timeBtn">临时保存</van-button>
+              <van-button type="info" @click="next('4')">下一页</van-button>
+            </van-col>
+          </van-col>
+          <van-col span="24" class="four" v-else-if="active == '4'">
+            <top title="评价委托方提供资料清单"></top>
+            <frame-datalist :datalist="form.datalist"></frame-datalist>
+            <van-col span="24" class="btn">
+              <van-button type="info" @click="up('3')">上一页</van-button>
+              <van-button type="primary" @click="timeBtn">临时保存</van-button>
+              <van-button type="primary" @click="onSubmit">提交申报</van-button>
+            </van-col>
+          </van-col>
+        </van-form>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from './parts/top.vue';
+import frameBasic from './parts/basic.vue';
+import frameBrief from './parts/brief.vue';
+import frameResearch from './parts/research.vue';
+import frameDatalist from './parts/datalist.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: achieveApply } = createNamespacedHelpers('achieveApply');
+import { Dialog } from 'vant';
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    top,
+    frameBasic,
+    frameBrief,
+    frameResearch,
+    frameDatalist,
+  },
+  data: function () {
+    return {
+      clientHeight: '',
+      active: '1',
+      form: {
+        basic: {},
+        brief: {},
+        research: [],
+        datalist: {},
+      },
+    };
+  },
+  created() {},
+  methods: {
+    ...achieveApply(['create']),
+    // 临时保存
+    timeBtn() {
+      let data = this.form;
+      data.status = '10';
+      Dialog.confirm({
+        title: '信息提示',
+        messageAlign: 'left',
+        message:
+          '<strong><p>1:用户</p><p>当您进行成果申报时,系统会自动识别您是否为平台用户,未注册用户,系统会自动拾取【申请人】和【申请人电话】进行平台用户注册,您可用【申请人电话】和【初始密码123456】进行登录查看。</p></strong>',
+      })
+        .then(async () => {
+          let res = await this.create(data);
+          if (this.$checkRes(res)) {
+            this.$toast({ type: 'success', message: '临时保存申报成功,请登录到管理中心继续编辑' });
+            this.form = {};
+          } else {
+            this.$toast({ type: 'fail', message: res.errmsg });
+          }
+        })
+        .catch(() => {});
+    },
+    // 保存
+    onSubmit() {
+      let data = this.form;
+      Dialog.confirm({
+        title: '信息提示',
+        messageAlign: 'left',
+        message:
+          '<strong><p>1:用户</p><p>当您进行成果申报时,系统会自动识别您是否为平台用户,未注册用户,系统会自动拾取【申请人】和【申请人电话】进行平台用户注册,您可用【申请人电话】和【初始密码123456】进行登录查看。</p></strong>',
+      })
+        .then(async () => {
+          let res = await this.create(data);
+          if (this.$checkRes(res)) {
+            this.$toast({ type: 'success', message: '临时保存申报成功,请登录到管理中心继续编辑' });
+            this.form = {};
+          } else {
+            this.$toast({ type: 'fail', message: res.errmsg });
+          }
+        })
+        .catch(() => {});
+    },
+    // 上一页
+    up(type) {
+      this.$set(this, `active`, type);
+    },
+    // 下一页
+    next(type) {
+      this.$set(this, `active`, type);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  mounted() {
+    let clientHeight = (document.documentElement.clientHeight || document.body.clientHeight) - 84;
+    this.$set(this, `clientHeight`, clientHeight);
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  overflow-y: auto;
+  /deep/.van-checkbox {
+    float: left;
+    width: 50%;
+    margin: 0 0 5px 0;
+  }
+  .btn {
+    text-align: center;
+    padding: 10px 0;
+    button {
+      margin: 0 10px;
+    }
+  }
+}
+</style>

+ 135 - 0
src/views/company/innovate/achieve/parts/basic.vue

@@ -0,0 +1,135 @@
+<template>
+  <div id="basic">
+    <el-row>
+      <el-col :span="24" class="main">
+        <van-field v-model="basic.achieve_name" name="成果名称" label="成果名称" placeholder="成果名称" required />
+        <van-field name="checkboxGroup" label="成果类别" required>
+          <template #input>
+            <van-checkbox-group v-model="basic.achieve_type" direction="horizontal">
+              <van-checkbox :name="item.name" shape="square" v-for="(item, index) in achievetypeList" :key="index">{{ item.name }}</van-checkbox>
+            </van-checkbox-group>
+          </template>
+        </van-field>
+        <van-field v-model="basic.achieve_num" name="成果编号" label="成果编号" placeholder="成果编号" />
+        <van-field
+          readonly
+          clickable
+          name="calendar"
+          :value="basic.achieve_date"
+          label="成果取得时间"
+          placeholder="点击选择"
+          @click="showCalendar = true"
+          required
+        />
+        <van-calendar v-model="showCalendar" @confirm="onDate" />
+        <van-field readonly clickable name="picker" :value="basic.achieve_form" label="成果形式" placeholder="点击选择" required @click="forms = true" />
+        <van-popup v-model="forms" position="bottom">
+          <van-picker show-toolbar value-key="name" :columns="achieveformList" @confirm="onForm" @cancel="forms = false" />
+        </van-popup>
+        <van-field v-model="basic.apply_personal" name="申请人" label="申请人" placeholder="申请人" required />
+        <van-field v-model="basic.apply_phone" name="申请人电话" label="申请人电话" placeholder="申请人电话" required />
+        <van-field v-model="basic.apply_company" name="申请单位" label="申请单位" placeholder="申请单位" required />
+        <van-field v-model="basic.address" name="请输入地址" label="请输入地址" placeholder="请输入地址" required />
+        <van-field
+          readonly
+          clickable
+          name="picker"
+          :value="basic.apply_nature"
+          label="申请单位/申请人属性"
+          placeholder="点击选择"
+          @click="nature = true"
+          required
+        />
+        <van-popup v-model="nature" position="bottom">
+          <van-picker show-toolbar value-key="name" :columns="applynatureList" @confirm="onNature" @cancel="nature = false" />
+        </van-popup>
+        <van-field v-model="basic.contacts" name="联系人" label="联系人" placeholder="联系人" required />
+        <van-field v-model="basic.phone" name="联系电话" label="联系电话" placeholder="联系电话" required />
+        <van-field v-model="basic.email" name="邮箱" label="邮箱" placeholder="邮箱" required />
+        <van-field v-model="basic.fax" name="传真" label="传真" placeholder="传真" />
+        <van-field readonly clickable name="picker" :value="basic.objective" label="评价目的" placeholder="点击选择" required @click="objective = true" />
+        <van-popup v-model="objective" position="bottom">
+          <van-picker show-toolbar value-key="name" :columns="objectiveList" @confirm="onObjective" @cancel="objective = false" />
+        </van-popup>
+        <van-field readonly clickable name="picker" :value="basic.stage" label="成果所处阶段" placeholder="点击选择" required @click="stages = true" />
+        <van-popup v-model="stages" position="bottom">
+          <van-picker show-toolbar value-key="name" :columns="stageList" @confirm="onStage" @cancel="stages = false" />
+        </van-popup>
+        <van-field v-model="basic.output" name="经济效益产值" label="经济效益产值" placeholder="经济效益产值" required />
+        <van-field v-model="basic.profit" name="经济效益利润" label="经济效益利润" placeholder="经济效益利润" required />
+        <van-field v-model="basic.revenue" name="经济效益税收" label="经济效益税收" placeholder="经济效益税收" required />
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { achievetype, achieveform, applynature, objective, stage } = require('@common/src/store/achieve/achieveType');
+const moment = require('moment');
+export default {
+  name: 'basic',
+  props: {
+    basic: { type: Object },
+  },
+  components: {},
+  data: function () {
+    return {
+      // 成果类别
+      achievetypeList: achievetype,
+      // 成果时间
+      showCalendar: false,
+      // 成果形式
+      forms: false,
+      achieveformList: achieveform,
+      // 申请人属性
+      nature: false,
+      applynatureList: applynature,
+      // 评价目的
+      objective: false,
+      objectiveList: objective,
+      // 成果所处阶段
+      stages: false,
+      stageList: stage,
+    };
+  },
+  created() {},
+  methods: {
+    onDate(value) {
+      this.$set(this.basic, `achieve_date`, moment(value).format('YYYY-MM-DD'));
+      this.showCalendar = false;
+    },
+    onForm(value) {
+      this.$set(this.basic, `achieve_form`, value.name);
+      this.forms = false;
+    },
+    onNature(value) {
+      this.$set(this.basic, `apply_nature`, value.name);
+      this.nature = false;
+    },
+    onObjective(value) {
+      this.$set(this.basic, `objective`, value.name);
+      this.objective = false;
+    },
+    onStage(value) {
+      this.$set(this.basic, `stage`, value.name);
+      this.stages = false;
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 46 - 0
src/views/company/innovate/achieve/parts/brief.vue

@@ -0,0 +1,46 @@
+<template>
+  <div id="brief">
+    <el-row>
+      <el-col :span="24" class="main">
+        <van-field v-model="brief.achieve_brief" rows="4" autosize label="成果简介" type="textarea" placeholder="成果简介" />
+        <van-field v-model="brief.field" rows="4" autosize label="应用领域和技术原理" type="textarea" placeholder="应用领域和技术原理" />
+        <van-field v-model="brief.kpi_index" rows="4" autosize label="性能指标" type="textarea" placeholder="性能指标" />
+        <van-field v-model="brief.advanced" rows="4" autosize label="成果的创造性,先进性" type="textarea" placeholder="成果的创造性,先进性" />
+        <van-field v-model="brief.sense" rows="4" autosize label="作用意义" type="textarea" placeholder="作用意义" />
+        <van-field v-model="brief.prospect" rows="4" autosize label="推广应用的范围,条件和前景" type="textarea" placeholder="推广应用的范围,条件和前景" />
+        <van-field v-model="brief.opinion" rows="4" autosize label="存在的问题和改进意见" type="textarea" placeholder="存在的问题和改进意见" />
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'brief',
+  props: {
+    brief: { type: Object },
+  },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 173 - 0
src/views/company/innovate/achieve/parts/datalist.vue

@@ -0,0 +1,173 @@
+<template>
+  <div id="datalistw">
+    <el-row>
+      <el-col :span="24" class="main">
+        <van-field name="uploader" label="1.工作报告(必备)" label-width="8em">
+          <template #input>
+            <van-uploader
+              :fileList="datalists.work_report"
+              :max-count="1"
+              @delete="(file) => toDelete(file, 'work_report')"
+              :after-read="(file) => toUpload(file, 'work_report')"
+            />
+          </template>
+        </van-field>
+        <van-field name="uploader" label="2.技术报告(必备)" label-width="8em">
+          <template #input>
+            <van-uploader
+              :fileList="datalists.techol_report"
+              :max-count="1"
+              @delete="(file) => toDelete(file, 'techol_report')"
+              :after-read="(file) => toUpload(file, 'techol_report')"
+            />
+          </template>
+        </van-field>
+        <van-field name="uploader" label="3.国内外对比报告(必备)" label-width="14em">
+          <template #input>
+            <van-uploader
+              :fileList="datalists.compare_report"
+              :max-count="1"
+              @delete="(file) => toDelete(file, 'compare_report')"
+              :after-read="(file) => toUpload(file, 'compare_report')"
+            />
+          </template>
+        </van-field>
+        <van-field name="uploader" label="4.经济效益分析(必备)" label-width="11em">
+          <template #input>
+            <van-uploader
+              :fileList="datalists.benefit"
+              :max-count="1"
+              @delete="(file) => toDelete(file, 'benefit')"
+              :after-read="(file) => toUpload(file, 'benefit')"
+            />
+          </template>
+        </van-field>
+        <van-field name="uploader" label="5.科技查新报告(必备)" label-width="11em">
+          <template #input>
+            <van-uploader
+              :fileList="datalists.science_report"
+              :max-count="1"
+              @delete="(file) => toDelete(file, 'science_report')"
+              :after-read="(file) => toUpload(file, 'science_report')"
+            />
+          </template>
+        </van-field>
+        <van-field name="uploader" label="6.技术检测报告" label-width="8em">
+          <template #input>
+            <van-uploader
+              :fileList="datalists.techol_detect_report"
+              :max-count="1"
+              @delete="(file) => toDelete(file, 'techol_detect_report')"
+              :after-read="(file) => toUpload(file, 'techol_detect_report')"
+            />
+          </template>
+        </van-field>
+        <van-field name="uploader" label="7.用户证明" label-width="8em">
+          <template #input>
+            <van-uploader
+              :fileList="datalists.user_prove"
+              :max-count="1"
+              @delete="(file) => toDelete(file, 'user_prove')"
+              :after-read="(file) => toUpload(file, 'user_prove')"
+            />
+          </template>
+        </van-field>
+        <van-field name="uploader" label="8.专利证书" label-width="8em">
+          <template #input>
+            <van-uploader
+              :fileList="datalists.patent_cert"
+              :max-count="1"
+              @delete="(file) => toDelete(file, 'patent_cert')"
+              :after-read="(file) => toUpload(file, 'patent_cert')"
+            />
+          </template>
+        </van-field>
+        <van-field name="uploader" label="9.软著" label-width="8em">
+          <template #input>
+            <van-uploader
+              :fileList="datalists.software_copyright"
+              :max-count="1"
+              @delete="(file) => toDelete(file, 'software_copyright')"
+              :after-read="(file) => toUpload(file, 'software_copyright')"
+            />
+          </template>
+        </van-field>
+        <van-field name="uploader" label="10.论文" label-width="8em">
+          <template #input>
+            <van-uploader
+              :fileList="datalists.treatise"
+              :max-count="1"
+              @delete="(file) => toDelete(file, 'treatise')"
+              :after-read="(file) => toUpload(file, 'treatise')"
+            />
+          </template>
+        </van-field>
+        <van-field name="uploader" label="11.工法" label-width="8em">
+          <template #input>
+            <van-uploader :fileList="datalists.gf" :max-count="1" @delete="(file) => toDelete(file, 'gf')" :after-read="(file) => toUpload(file, 'gf')" />
+          </template>
+        </van-field>
+        <van-field name="uploader" label="12.企业标准等证明材料(必备)" label-width="14em">
+          <template #input>
+            <van-uploader
+              :fileList="datalists.company_standard"
+              :max-count="1"
+              @delete="(file) => toDelete(file, 'company_standard')"
+              :after-read="(file) => toUpload(file, 'company_standard')"
+            />
+          </template>
+        </van-field>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: upload } = createNamespacedHelpers('upload');
+export default {
+  name: 'datalistw',
+  props: {
+    datalist: { type: Object },
+  },
+  components: {},
+  data: function () {
+    return {
+      datalists: [],
+    };
+  },
+  created() {},
+  methods: {
+    ...upload(['upload']),
+    // 其他资料
+    async toUpload({ file }, model) {
+      // 上传,赋值
+      const res = await this.upload({ file, dir: 'file' });
+      if (this.$checkRes(res)) {
+        this.$set(this.datalists, model, [{ name: res.name, url: res.uri }]);
+        this.$set(this.datalist, model, { name: res.name, url: res.uri });
+      }
+    },
+    toDelete(file, model) {
+      const index = this.datalists[model].findIndex((f) => _.isEqual(f, file));
+      this.datalists[model].splice(index, 1);
+      this.$set(this.datalist, model, {});
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 186 - 0
src/views/company/innovate/achieve/parts/research.vue

@@ -0,0 +1,186 @@
+<template>
+  <div id="research">
+    <el-row>
+      <el-col :span="24" class="main">
+        <van-col span="24" class="btn">
+          <van-button type="primary" size="mini" @click="toAdd">添加主研人员</van-button>
+          <van-col span="24" style="color: #ff0000; margin: 5px 0; font-weight: bold"> 研发人员会影响后续资料归档功能,填写人数需3人以上! </van-col>
+        </van-col>
+        <van-col span="24" class="list" v-for="(item, index) in research" :key="index">
+          <van-col span="24" class="name">
+            {{ item.name }}
+          </van-col>
+          <van-col span="24" class="other">
+            <van-col span="24" class="otherInfo">
+              技术职称:<span>{{ item.zc }}</span>
+            </van-col>
+            <van-col span="24" class="otherInfo">
+              工作单位:<span>{{ item.company }}</span>
+            </van-col>
+          </van-col>
+          <van-col span="24" class="listBtn">
+            <van-button type="info" size="small" @click="toEdit(item)">编辑</van-button>
+            <van-button type="danger" size="small" @click="toDel(index)">删除</van-button>
+          </van-col>
+        </van-col>
+      </el-col>
+    </el-row>
+    <van-dialog v-model="researchShow" title="添加主研人员" show-cancel-button class="dialog" @confirm="confirm" @cancel="cancel">
+      <van-form>
+        <van-field v-model="researchForm.name" name="姓名" label="姓名" required />
+        <van-field name="radio" label="性别" required>
+          <template #input>
+            <van-radio-group v-model="researchForm.gender" direction="horizontal">
+              <van-radio name="男">男</van-radio>
+              <van-radio name="女">女</van-radio>
+            </van-radio-group>
+          </template>
+        </van-field>
+        <van-field v-model="researchForm.age" name="年龄" label="年龄" />
+        <van-field readonly clickable name="calendar" :value="researchForm.birth" label="出生日期" placeholder="点击选择" @click="showBirth = true" />
+        <van-calendar v-model="showBirth" @confirm="onBirth" />
+        <van-field v-model="researchForm.zc" name="技术职称" label="技术职称" required />
+        <van-field v-model="researchForm.education" name="学历" label="学历" required />
+        <van-field v-model="researchForm.degree" name="学位" label="学位" />
+        <van-field v-model="researchForm.major" name="现从事专业" label="现从事专业" />
+        <van-field name="radio" label="是否留学归国">
+          <template #input>
+            <van-radio-group v-model="researchForm.abroad" direction="horizontal">
+              <van-radio name="是">是</van-radio>
+              <van-radio name="否">否</van-radio>
+            </van-radio-group>
+          </template>
+        </van-field>
+        <van-field v-model="researchForm.company" name="工作单位" label="工作单位" required />
+        <van-field v-model="researchForm.work" rows="4" autosize label="在项目中承担的主要工作" type="textarea" placeholder="在项目中承担的主要工作" />
+        <van-field v-model="researchForm.devote" rows="4" autosize label="对成果创造性贡献" type="textarea" placeholder="对成果创造性贡献" />
+      </van-form>
+    </van-dialog>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const moment = require('moment');
+export default {
+  name: 'research',
+  props: {
+    research: { type: Array },
+  },
+  components: {},
+  data: function () {
+    return {
+      // 主研人员名单
+      researchShow: false,
+      researchForm: {},
+      // 出生日期
+      showBirth: false,
+    };
+  },
+  created() {},
+  methods: {
+    // 添加
+    toAdd() {
+      this.researchShow = true;
+    },
+    // 提交
+    confirm() {
+      let data = this.researchForm;
+      let qwe = this.research.find((i) => i.name == data.name);
+      let asd = this.research.findIndex((i) => i.name == data.name);
+      if (qwe) {
+        qwe = {
+          name: data.name,
+          gender: data.gender,
+          age: data.age,
+          birth: data.birth,
+          zc: data.zc,
+          education: data.education,
+          degree: data.degree,
+          major: data.major,
+          abroad: data.abroad,
+          company: data.company,
+          work: data.work,
+          devote: data.devote,
+        };
+        this.research.splice(asd, 1, qwe);
+      } else {
+        this.research.push(data);
+      }
+    },
+    // 取消提交
+    cancel() {
+      this.researchForm = {};
+      this.researchShow = false;
+    },
+    // 编辑
+    toEdit(data) {
+      this.$set(this, `researchForm`, data);
+      this.researchShow = true;
+    },
+    //删除
+    toDel(index) {
+      this.research.splice(index, 1);
+    },
+    onBirth(value) {
+      this.$set(this.researchForm, `birth`, moment(value).format('YYYY-MM-DD'));
+      this.showBirth = false;
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 0 8px;
+  .btn {
+    text-align: center;
+  }
+  .list {
+    background-color: #f1f1f1;
+    margin: 0 0 10px 0;
+    padding: 8px;
+    border-radius: 10px;
+    .name {
+      font-size: 16px;
+      font-weight: bold;
+      margin: 0 0 5px 0;
+    }
+    .other {
+      .otherInfo {
+        font-size: 14px;
+        color: #666;
+        margin: 0 0 5px 0;
+        span {
+          color: #000;
+        }
+      }
+    }
+    .listBtn {
+      text-align: center;
+      button {
+        margin: 0 10px;
+      }
+    }
+  }
+}
+.dialog {
+  /deep/.van-dialog__content {
+    height: 400px;
+    overflow-y: auto;
+  }
+}
+</style>

+ 40 - 0
src/views/company/innovate/achieve/parts/top.vue

@@ -0,0 +1,40 @@
+<template>
+  <div id="top">
+    <el-row>
+      <el-col :span="24" class="main">
+        <van-divider :style="{ color: '#1989fa', borderColor: '#1989fa', padding: '0 16px' }">{{ title }}</van-divider>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'top',
+  props: {
+    title: { type: String },
+  },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 80 - 0
src/views/company/innovate/index.vue

@@ -0,0 +1,80 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="top">
+          <top topType="2" :leftArrow="false"></top>
+        </el-col>
+        <el-col :span="24" class="info" :style="{ height: clientHeight + 'px' }">
+          <van-tabs v-model="activeName" color="#409eff" @change="onChange">
+            <van-tab title="高企自评" name="1"> 高企自评 </van-tab>
+            <van-tab title="成果评价" name="2">
+              <frame-2></frame-2>
+            </van-tab>
+            <van-tab title="查新服务" name="3"> <frame-3></frame-3></van-tab>
+            <van-tab title="项目申报" name="4">项目申报</van-tab>
+          </van-tabs>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from '@/layout/common/top.vue';
+import frame2 from './achieve/index.vue';
+import frame3 from './novelty/index.vue';
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    top,
+    frame2,
+    frame3,
+  },
+  data: function () {
+    return {
+      clientHeight: '',
+      activeName: '1',
+    };
+  },
+  async created() {},
+  methods: {
+    onChange(name) {
+      if (name == 4) window.location.href = 'http://www.jlkjxm.com';
+    },
+  },
+  mounted() {
+    let clientHeight = (document.documentElement.clientHeight || document.body.clientHeight) - 40;
+    this.$set(this, `clientHeight`, clientHeight);
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .top {
+    height: 40px;
+    overflow: hidden;
+    border-bottom: 1px solid #f9f9f9;
+  }
+  .info {
+    overflow-x: hidden;
+    overflow-y: auto;
+  }
+}
+</style>

+ 36 - 0
src/views/company/innovate/novelty/index.vue

@@ -0,0 +1,36 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main"> 查新服务 </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 84 - 0
src/views/company/market/detail.vue

@@ -0,0 +1,84 @@
+<template>
+  <div id="detail">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="top">
+          <top topType="2" @back="back"></top>
+        </el-col>
+        <el-col :span="24" class="info" :style="{ height: clientHeight + 'px' }">
+          <frame-detail :form="form"></frame-detail>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import frameDetail from '../parts/detail_1.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: product } = createNamespacedHelpers('product');
+export default {
+  name: 'detail',
+  props: {},
+  components: {
+    frameDetail,
+  },
+  data: function () {
+    return {
+      clientHeight: '',
+      form: {},
+    };
+  },
+  async created() {
+    if (this.id) await this.search();
+  },
+  methods: {
+    ...product(['fetch']),
+    async search() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `form`, res.data);
+      }
+    },
+    // 查看详情
+    back() {
+      this.$router.push({ path: '/company/market/index' });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  mounted() {
+    let clientHeight = (document.documentElement.clientHeight || document.body.clientHeight) - 40;
+    this.$set(this, `clientHeight`, clientHeight);
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .top {
+    height: 40px;
+    overflow: hidden;
+    border-bottom: 1px solid #f9f9f9;
+  }
+  .info {
+    overflow-x: hidden;
+    overflow-y: auto;
+    padding: 0 8px;
+  }
+}
+</style>

+ 99 - 0
src/views/company/market/index.vue

@@ -0,0 +1,99 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="top">
+          <top topType="1" @search="search"></top>
+        </el-col>
+        <el-col :span="24" class="info" :style="{ height: clientHeight + 'px' }">
+          <frame-list :list="list" @detail="detail"></frame-list>
+        </el-col>
+        <el-col :span="24" class="page">
+          <page :limit="limit" :total="total" @search="search" />
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import frameList from '../parts/list_1.vue';
+import page from '@/layout/common/page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: product } = createNamespacedHelpers('product');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    frameList,
+    page,
+  },
+  data: function () {
+    return {
+      clientHeight: '',
+      column: {},
+      list: [],
+      total: 0,
+      limit: 10,
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...product(['query']),
+    async search({ skip = 0, limit = this.limit, searchName, ...info } = {}) {
+      if (searchName) info.name = searchName;
+      info.type = '1';
+      info.status = '2';
+      let res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+      }
+    },
+    // 查看详情
+    detail(data) {
+      this.$router.push({ path: '/company/market/detail', query: { id: data._id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  mounted() {
+    let clientHeight = (document.documentElement.clientHeight || document.body.clientHeight) - 80;
+    this.$set(this, `clientHeight`, clientHeight);
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .top {
+    height: 40px;
+    overflow: hidden;
+    border-bottom: 1px solid #f9f9f9;
+  }
+  .info {
+    overflow-x: hidden;
+    overflow-y: auto;
+    background-color: #f1f1f1;
+    padding: 0 8px;
+  }
+  .page {
+    height: 40px;
+    overflow: hidden;
+    border-top: 1px solid #f1f1f1;
+  }
+}
+</style>

+ 145 - 0
src/views/company/parts/detail_1.vue

@@ -0,0 +1,145 @@
+<template>
+  <div id="detail_1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <van-swipe style="height: 219px">
+            <template v-if="form.image && form.image.length > 0">
+              <van-swipe-item v-for="(item, index) in form.image" :key="index">
+                <van-image :src="item.url" />
+              </van-swipe-item>
+            </template>
+            <template v-else>
+              <van-image :src="noimage" />
+            </template>
+          </van-swipe>
+        </el-col>
+        <el-col :span="24" class="two">
+          <p>
+            <span>产品名称:</span>
+            <span>{{ form.name || '暂无' }}</span>
+          </p>
+          <p>
+            <span>成果单位:</span>
+            <span>{{ form.company || '暂无' }}</span>
+          </p>
+          <p>
+            <span>所属领域:</span>
+            <span> {{ form.field || '暂无' }}</span>
+          </p>
+          <p>
+            <span>合作方式:</span>
+            <span>{{ form.cooperation || '暂无' }}</span>
+          </p>
+          <p>
+            <span>成果状态:</span>
+            <span>{{ form.achievestatus || '暂无' }}</span>
+          </p>
+          <p>
+            <span>成果来源:</span>
+            <span>{{ form.achievesource || '暂无' }}</span>
+          </p>
+          <p>
+            <span>成果权属:</span>
+            <span>{{ form.achieveown || '暂无' }}</span>
+          </p>
+          <p>
+            <span>意向价格:</span>
+            <span>{{ form.intentionprice || '暂无' }}</span>
+          </p>
+          <p>
+            <span>联系人:</span>
+            <span>{{ form.contacts || '暂无' }}</span>
+          </p>
+          <p>
+            <span>联系方式:</span>
+            <span>{{ form.email }}/{{ form.qqwx || '暂无' }}</span>
+          </p>
+          <p>
+            <span>项目路演:</span>
+            <span>{{ form.roadshow || '暂无' }}</span>
+          </p>
+          <p>
+            <span>成果简介:</span>
+            <span>{{ form.achievebrief || '暂无' }}</span>
+          </p>
+
+          <p>
+            <span>技术特点:</span>
+            <span>{{ form.features || '暂无' }}</span>
+          </p>
+          <p>
+            <span>技术团队:</span>
+            <span>{{ form.team || '暂无' }}</span>
+          </p>
+          <p>
+            <span>商业预期:</span>
+            <span>{{ form.expect || '暂无' }}</span>
+          </p>
+          <p>
+            <span>合作要求:</span>
+            <span>{{ form.condition || '暂无' }}</span>
+          </p>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'detail_1',
+  props: {
+    form: { type: Object },
+  },
+  components: {},
+  data: function () {
+    return {
+      noimage: require('@/assets/noimage.jpg'),
+    };
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  metaform() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    height: 220px;
+    border-bottom: 1px solid #f1f1f1;
+    .van-image {
+      width: 100%;
+      height: 219px;
+    }
+  }
+  .two {
+    p {
+      font-size: 16px;
+      color: #666;
+      padding: 10px;
+      border-bottom: 1px solid #ccc;
+      span:nth-child(2) {
+        color: #000;
+      }
+    }
+  }
+}
+/deep/.van-swipe__track {
+  width: 100% !important;
+}
+</style>

+ 122 - 0
src/views/company/parts/detail_2.vue

@@ -0,0 +1,122 @@
+<template>
+  <div id="detail_2">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-image v-if="form.img_url != undefined || null" :src="form.img_url"></el-image>
+          <el-image v-else :src="noimage"></el-image>
+        </el-col>
+        <el-col :span="24" class="two">
+          <p>
+            <span>专利有效性:</span>
+            <span>{{ form.term || '暂无' }}</span>
+          </p>
+          <p>
+            <span>名称:</span>
+            <span>{{ form.name || '暂无' }}</span>
+          </p>
+          <p>
+            <span>申请号:</span>
+            <span> {{ form.create_number || '暂无' }}</span>
+          </p>
+          <p>
+            <span>申请日:</span>
+            <span>{{ form.create_date || '暂无' }}</span>
+          </p>
+          <p>
+            <span>公开(公告)号:</span>
+            <span>{{ form.success_number || '暂无' }}</span>
+          </p>
+          <p>
+            <span>公开(公告)日:</span>
+            <span>{{ form.success_date || '暂无' }}</span>
+          </p>
+          <p>
+            <span>专利类型:</span>
+            <span>{{ form.type || '暂无' }}</span>
+          </p>
+          <p>
+            <span>发明人:</span>
+            <span>{{ form.inventor || '暂无' }}</span>
+          </p>
+          <p>
+            <span>发明人地址:</span>
+            <span>{{ form.address || '暂无' }}</span>
+          </p>
+          <p>
+            <span>申请人:</span>
+            <span>{{ form.apply_personal || '暂无' }}</span>
+          </p>
+          <p>
+            <span>代理人:</span>
+            <span>{{ form.agent_personal || '暂无' }}</span>
+          </p>
+          <p>
+            <span>代理机构:</span>
+            <span>{{ form.agent || '暂无' }}</span>
+          </p>
+
+          <p>
+            <span>摘要:</span>
+            <span>{{ form.abstract || '暂无' }}</span>
+          </p>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'detail_2',
+  props: {
+    form: { type: Object },
+  },
+  components: {},
+  data: function () {
+    return {
+      noimage: require('@/assets/noimage.jpg'),
+    };
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  metaform() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    height: 220px;
+    border-bottom: 1px solid #f1f1f1;
+    .el-image {
+      width: 100%;
+      height: 219px;
+    }
+  }
+  .two {
+    p {
+      font-size: 16px;
+      color: #666;
+      padding: 10px;
+      border-bottom: 1px solid #ccc;
+      span:nth-child(2) {
+        color: #000;
+      }
+    }
+  }
+}
+</style>

+ 113 - 0
src/views/company/parts/detail_3.vue

@@ -0,0 +1,113 @@
+<template>
+  <div id="detail_3">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <p>
+            <span>服务名称:</span>
+            <span>{{ form.name || '暂无' }}</span>
+          </p>
+          <p>
+            <span>需求程度:</span>
+            <span>{{ form.demand || '暂无' }}</span>
+          </p>
+          <p>
+            <span>信息属性:</span>
+            <span> {{ form.messattribute || '暂无' }}</span>
+          </p>
+          <p>
+            <span>联系人:</span>
+            <span>{{ form.contacts || '暂无' }}</span>
+          </p>
+          <p>
+            <span>QQ/微信:</span>
+            <span>{{ form.qqwx || '暂无' }}</span>
+          </p>
+          <p>
+            <span>联系电话:</span>
+            <span>{{ getphone(form.phone) || '暂无' }}</span>
+          </p>
+          <p>
+            <span>电子邮箱:</span>
+            <span>{{ form.email || '暂无' }}</span>
+          </p>
+          <p>
+            <span>信息描述:</span>
+            <span>{{ form.formrmationdesc || '暂无' }}</span>
+          </p>
+          <p>
+            <span>核心要素:</span>
+            <span>{{ form.coreelements || '暂无' }}</span>
+          </p>
+          <p>
+            <span>价格信息:</span>
+            <span>{{ form.priceform || '暂无' }}</span>
+          </p>
+          <p>
+            <span>商务预期:</span>
+            <span>{{ form.expect || '暂无' }}</span>
+          </p>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'detail_3',
+  props: {
+    form: { type: Object },
+  },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    getphone(value) {
+      if (value == undefined) {
+        return '暂无';
+      } else {
+        if (value.length === 11) {
+          let start = value.slice(0, 4);
+          let end = value.slice(-3);
+          return `${start}****${end}`;
+        } else {
+          return value;
+        }
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaform() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    p {
+      font-size: 16px;
+      color: #666;
+      padding: 10px;
+      border-bottom: 1px solid #ccc;
+      span:nth-child(2) {
+        color: #000;
+      }
+    }
+  }
+}
+</style>

+ 84 - 0
src/views/company/parts/list_1.vue

@@ -0,0 +1,84 @@
+<template>
+  <div id="list_1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="detail(item)">
+          <el-col :span="24" class="title textOver">
+            {{ item.name }}
+          </el-col>
+          <el-col :span="24" class="other">
+            <el-col :span="24" class="otherInfo">
+              成果单位:<span>{{ item.company || '暂无' }}</span>
+            </el-col>
+            <el-col :span="24" class="otherInfo">
+              所属领域:<span>{{ item.field || '暂无' }}</span>
+            </el-col>
+            <el-col :span="24" class="otherInfo">
+              合作方式:<span>{{ item.cooperation || '暂无' }}</span>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'list_1',
+  props: {
+    list: { type: Array },
+  },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    detail(data) {
+      this.$emit('detail', data);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  margin: 8px 0 0 0;
+  .list {
+    background-color: #fff;
+    margin: 0 0 10px 0;
+    box-shadow: 0 0 5px #f1f1f1;
+    padding: 8px;
+    .title {
+      font-size: 16px;
+      font-weight: bold;
+      margin: 0 0 5px 0;
+    }
+    .other {
+      .otherInfo {
+        font-size: 14px;
+        color: #666;
+        margin: 0 0 5px 0;
+        span {
+          color: #000;
+        }
+      }
+    }
+  }
+}
+</style>

+ 81 - 0
src/views/company/parts/list_2.vue

@@ -0,0 +1,81 @@
+<template>
+  <div id="list_2">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="detail(item)">
+          <el-col :span="24" class="title textOver">
+            {{ item.name }}
+          </el-col>
+          <el-col :span="24" class="other">
+            <el-col :span="24" class="otherInfo">
+              专利有效性:<span>{{ item.term || '暂无' }}</span>
+            </el-col>
+            <el-col :span="24" class="otherInfo">
+              颁发时间:<span>{{ item.success_date || '暂无' }}</span>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'list_2',
+  props: {
+    list: { type: Array },
+  },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    detail(data) {
+      this.$emit('detail', data);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  margin: 8px 0 0 0;
+  .list {
+    background-color: #fff;
+    margin: 0 0 10px 0;
+    box-shadow: 0 0 5px #f1f1f1;
+    padding: 8px;
+    .title {
+      font-size: 16px;
+      font-weight: bold;
+      margin: 0 0 5px 0;
+    }
+    .other {
+      .otherInfo {
+        font-size: 14px;
+        color: #666;
+        margin: 0 0 5px 0;
+        span {
+          color: #000;
+        }
+      }
+    }
+  }
+}
+</style>

+ 84 - 0
src/views/company/parts/list_3.vue

@@ -0,0 +1,84 @@
+<template>
+  <div id="list_3">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="detail(item)">
+          <el-col :span="24" class="title textOver">
+            {{ item.name }}
+          </el-col>
+          <el-col :span="24" class="other">
+            <el-col :span="24" class="otherInfo">
+              发布单位:<span>{{ item.company || '暂无' }}</span>
+            </el-col>
+            <el-col :span="24" class="otherInfo">
+              信息属性:<span>{{ item.messattribute || '暂无' }}</span>
+            </el-col>
+            <el-col :span="24" class="otherInfo">
+              联系方式:<span>{{ item.qqwx || '暂无' }}</span>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'list_3',
+  props: {
+    list: { type: Array },
+  },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    detail(data) {
+      this.$emit('detail', data);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  margin: 8px 0 0 0;
+  .list {
+    background-color: #fff;
+    margin: 0 0 10px 0;
+    box-shadow: 0 0 5px #f1f1f1;
+    padding: 8px;
+    .title {
+      font-size: 16px;
+      font-weight: bold;
+      margin: 0 0 5px 0;
+    }
+    .other {
+      .otherInfo {
+        font-size: 14px;
+        color: #666;
+        margin: 0 0 5px 0;
+        span {
+          color: #000;
+        }
+      }
+    }
+  }
+}
+</style>

+ 84 - 0
src/views/company/patent/detail.vue

@@ -0,0 +1,84 @@
+<template>
+  <div id="detail">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="top">
+          <top topType="2" @back="back"></top>
+        </el-col>
+        <el-col :span="24" class="info" :style="{ height: clientHeight + 'px' }">
+          <frame-detail :form="form"></frame-detail>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import frameDetail from '../parts/detail_2.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: patent } = createNamespacedHelpers('patent');
+export default {
+  name: 'detail',
+  props: {},
+  components: {
+    frameDetail,
+  },
+  data: function () {
+    return {
+      clientHeight: '',
+      form: {},
+    };
+  },
+  async created() {
+    if (this.id) await this.search();
+  },
+  methods: {
+    ...patent(['fetch']),
+    async search() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `form`, res.data);
+      }
+    },
+    // 查看详情
+    back() {
+      this.$router.push({ path: '/company/patent/index' });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  mounted() {
+    let clientHeight = (document.documentElement.clientHeight || document.body.clientHeight) - 40;
+    this.$set(this, `clientHeight`, clientHeight);
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .top {
+    height: 40px;
+    overflow: hidden;
+    border-bottom: 1px solid #f9f9f9;
+  }
+  .info {
+    overflow-x: hidden;
+    overflow-y: auto;
+    padding: 0 8px;
+  }
+}
+</style>

+ 97 - 0
src/views/company/patent/index.vue

@@ -0,0 +1,97 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="top">
+          <top topType="1" @search="search"></top>
+        </el-col>
+        <el-col :span="24" class="info" :style="{ height: clientHeight + 'px' }">
+          <frame-list :list="list" @detail="detail"></frame-list>
+        </el-col>
+        <el-col :span="24" class="page">
+          <page :limit="limit" :total="total" @search="search" />
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import frameList from '../parts/list_2.vue';
+import page from '@/layout/common/page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: patent } = createNamespacedHelpers('patent');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    frameList,
+    page,
+  },
+  data: function () {
+    return {
+      clientHeight: '',
+      column: {},
+      list: [],
+      total: 0,
+      limit: 10,
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...patent(['query']),
+    async search({ skip = 0, limit = this.limit, searchName, ...info } = {}) {
+      if (searchName) info.name = searchName;
+      let res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+      }
+    },
+    // 查看详情
+    detail(data) {
+      this.$router.push({ path: '/company/patent/detail', query: { id: data._id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  mounted() {
+    let clientHeight = (document.documentElement.clientHeight || document.body.clientHeight) - 80;
+    this.$set(this, `clientHeight`, clientHeight);
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .top {
+    height: 40px;
+    overflow: hidden;
+    border-bottom: 1px solid #f9f9f9;
+  }
+  .info {
+    overflow-x: hidden;
+    overflow-y: auto;
+    background-color: #f1f1f1;
+    padding: 0 8px;
+  }
+  .page {
+    height: 40px;
+    overflow: hidden;
+    border-top: 1px solid #f1f1f1;
+  }
+}
+</style>

+ 61 - 0
src/views/exchange/business/detail.vue

@@ -0,0 +1,61 @@
+<template>
+  <div id="detail">
+    <admin-frame :usePage="false" topType="2" @back="back">
+      <template v-slot:info> <detail-1 :form="form"></detail-1> </template>
+    </admin-frame>
+  </div>
+</template>
+
+<script>
+import detail1 from '../../scientific/parts/detail-1.vue';
+import adminFrame from '@/layout/common/admin-frame.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: news } = createNamespacedHelpers('news');
+export default {
+  name: 'detail',
+  props: {},
+  components: {
+    adminFrame,
+    detail1,
+  },
+  data: function () {
+    return {
+      form: {},
+    };
+  },
+  created() {
+    if (this.id) this.search();
+  },
+  methods: {
+    ...news(['fetch']),
+    async search() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `form`, res.data);
+      }
+    },
+    // 返回
+    back() {
+      this.$router.push({ path: '/exchange/business/index' });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 76 - 0
src/views/exchange/business/index.vue

@@ -0,0 +1,76 @@
+<template>
+  <div id="index">
+    <admin-frame @search="search" :limit="limit" :total="total">
+      <template v-slot:info>
+        <list-1 :list="list" @detail="detail"></list-1>
+      </template>
+    </admin-frame>
+  </div>
+</template>
+
+<script>
+import list1 from '../../scientific/parts/list-1.vue';
+import adminFrame from '@/layout/common/admin-frame.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: column } = createNamespacedHelpers('column');
+const { mapActions: news } = createNamespacedHelpers('news');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    adminFrame,
+    list1,
+  },
+  data: function () {
+    return {
+      column: {},
+      list: [],
+      total: 0,
+      limit: 10,
+    };
+  },
+  async created() {
+    await this.searchColumn();
+    await this.search();
+  },
+  methods: {
+    ...column({ columnQuery: 'query' }),
+    ...news(['query']),
+    async search({ skip = 0, limit = this.limit, searchName, ...info } = {}) {
+      if (searchName) info.title = searchName;
+      if (this.column) info.column_id = this.column.id;
+      let res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+      }
+    },
+    async searchColumn() {
+      let res = await this.columnQuery();
+      if (this.$checkRes(res)) {
+        let data = res.data.find((i) => i.site == 'zxfw');
+        if (data) this.$set(this, `column`, data);
+      }
+    },
+    // 查看详情
+    detail(data) {
+      this.$router.push({ path: '/exchange/business/detail', query: { id: data.id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 105 - 0
src/views/exchange/center copy/basic/index.vue

@@ -0,0 +1,105 @@
+<template>
+  <div id="index">
+    <admin-frame :usePage="false" topType="2" @back="back">
+      <template v-slot:info>
+        <van-tabs v-model="active">
+          <van-tab title="基本信息">
+            <basic-1 :userInfo="userInfo" @onSubmit="onSubmit"></basic-1>
+          </van-tab>
+          <van-tab title="详细信息" v-if="isCom(userInfo)">
+            <company-1 :userInfo="userInfo" @onSubmit="onSubmit"></company-1>
+          </van-tab>
+        </van-tabs>
+      </template>
+    </admin-frame>
+  </div>
+</template>
+
+<script>
+import basic1 from '../parts/basic-1.vue';
+import company1 from '../parts/company-1.vue';
+import adminFrame from '@/layout/common/admin-frame.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: organization } = createNamespacedHelpers('organization');
+const { mapActions: personal } = createNamespacedHelpers('personal');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    adminFrame,
+    basic1,
+    company1,
+  },
+  data: function () {
+    return {
+      active: 0,
+      userInfo: {},
+    };
+  },
+  async created() {
+    if (this.user) await this.search();
+  },
+  methods: {
+    ...organization(['fetch', 'update']),
+    ...personal({ personalFetch: 'fetch', personalUpdate: 'update' }),
+    async search() {
+      if (this.user.is_expert == undefined) {
+        let res = await this.fetch(this.user.id);
+        if (this.$checkRes(res)) {
+          this.$set(this, `userInfo`, res.data);
+        }
+      } else {
+        let res = await this.personalFetch(this.user.id);
+        if (this.$checkRes(res)) {
+          this.$set(this, `userInfo`, res.data);
+        }
+      }
+    },
+    // 保存基本信息
+    async onSubmit({ data }) {
+      if (this.user.is_expert == undefined) {
+        let res = await this.update(data);
+        if (this.$checkRes(res)) {
+          this.$notify({
+            message: '基本信息修改成功',
+            type: 'success',
+          });
+          this.search();
+        }
+      } else {
+        let res = await this.personalUpdate(data);
+        if (this.$checkRes(res)) {
+          this.$notify({
+            message: '基本信息修改成功',
+            type: 'success',
+          });
+          this.search();
+        }
+      }
+    },
+    back() {
+      this.$router.push({ path: '/exchange/center/index' });
+    },
+    // 判断是否是企业
+    isCom(data) {
+      if (data.is_expert == false || data.is_expert == true) return false;
+      else return true;
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 110 - 0
src/views/exchange/center copy/index.vue

@@ -0,0 +1,110 @@
+<template>
+  <div id="index">
+    <admin-frame :usePage="false" topType="2" :leftArrow="false">
+      <template v-slot:info>
+        <van-col span="24" class="one">
+          <van-col span="24" class="image">
+            <van-image :src="icon"></van-image>
+          </van-col>
+          <van-col span="24" class="other">
+            <van-col span="24" class="otherInfo">
+              {{ userInfo.name }}
+            </van-col>
+            <van-col span="24" class="otherInfo">
+              {{ userInfo.phone }}
+            </van-col>
+          </van-col>
+        </van-col>
+        <van-col span="24" class="two">
+          <van-cell title="基本信息" @click="btn('basic')" is-link />
+          <van-cell title="关联用户" @click="btn('user')" is-link />
+          <van-cell title="退出登录" @click="logout" is-link />
+          {{ user }}
+        </van-col>
+      </template>
+    </admin-frame>
+  </div>
+</template>
+
+<script>
+import adminFrame from '@/layout/common/admin-frame.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    adminFrame,
+  },
+  data: function () {
+    return {
+      icon: require('@a/icon.jpg'),
+      userInfo: {},
+    };
+  },
+  created() {
+    console.log(this.user);
+    if (this.user) this.$set(this, `userInfo`, this.user);
+  },
+  methods: {
+    btn(type) {
+      this.$router.push({ path: `/exchange/center/${type}/index` });
+    },
+    logout() {
+      let token = localStorage.removeItem('token');
+      let openid = sessionStorage.removeItem('openid');
+      if (token == undefined && openid == undefined) {
+        this.$notify({
+          message: '退出成功',
+          type: 'success',
+        });
+        this.$router.push({ path: '/login', query: { path: '/exchange/center/index', type: '1' } });
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.one {
+  margin: 0 0 8px 0;
+  background: url('~@/assets/userbj.jpg');
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+  .image {
+    text-align: center;
+    padding: 10px 0 10px 0;
+    .van-image {
+      width: 66px;
+      height: 66px;
+      /deep/.van-image__img {
+        border-radius: 90px;
+      }
+    }
+  }
+  .other {
+    text-align: center;
+    .otherInfo {
+      font-size: 16px;
+      color: #000;
+      font-weight: bold;
+      margin: 0 0 5px 0;
+    }
+  }
+}
+.two {
+  background: #fff;
+}
+</style>

+ 68 - 0
src/views/exchange/center copy/parts/basic-1.vue

@@ -0,0 +1,68 @@
+<template>
+  <div id="basic-1">
+    <van-row>
+      <van-col span="24" class="main">
+        <van-form>
+          <van-field v-model="userInfo.name" name="用户名称" label="用户名称" placeholder="用户名称" />
+          <van-field v-model="userInfo.phone" name="联系电话" label="联系电话" placeholder="联系电话" readonly />
+          <van-field v-model="userInfo.code" name="所属机构" label="所属机构" placeholder="所属机构" readonly />
+          <van-field v-model="userInfo.email" name="电子邮箱" label="电子邮箱" placeholder="电子邮箱" />
+          <van-field v-model="userInfo.addr" name="联系地址" label="联系地址" placeholder="联系地址" />
+          <van-field v-model="userInfo.office_phone" name="办公电话" label="办公电话" placeholder="办公电话" />
+          <van-field v-model="userInfo.profession" name="所属行业" label="所属行业" placeholder="所属行业" />
+          <van-field readonly clickable name="picker" :value="userInfo.juris" label="所属辖区" placeholder="点击选择" @click="showPicker = true" />
+          <van-popup v-model="showPicker" position="bottom">
+            <van-picker show-toolbar :columns="jurisList" @confirm="onConfirm" @cancel="showPicker = false" />
+          </van-popup>
+          <van-col span="24" class="btn">
+            <van-button round block type="info" @click="onSubmit">保存信息</van-button>
+            <!-- <van-button round block type="info" @click="upgradeBtn" v-if="userInfo.is_expert == false">升级用户</van-button> -->
+          </van-col>
+        </van-form>
+      </van-col>
+    </van-row>
+  </div>
+</template>
+
+<script>
+import { juris } from '@common/dict/index';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'basic-1',
+  props: {
+    userInfo: { type: Object },
+  },
+  components: {},
+  data: function () {
+    return {
+      showPicker: false,
+      jurisList: juris,
+    };
+  },
+  created() {},
+  methods: {
+    onSubmit() {
+      this.$emit('onSubmit', { data: this.userInfo });
+    },
+    onConfirm(value) {
+      this.$set(this.userInfo, `juris`, value);
+      this.showPicker = false;
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 104 - 0
src/views/exchange/center copy/parts/company-1.vue

@@ -0,0 +1,104 @@
+<template>
+  <div id="company-1">
+    <van-row>
+      <van-col span="24" class="main">
+        <van-form>
+          <van-field v-model="userInfo.institution_code" name="信用代码" label="信用代码" placeholder="信用代码" disabled />
+          <van-field v-model="userInfo.companyperson" name="企业法人" label="企业法人" placeholder="企业法人" />
+          <van-field v-model="userInfo.companycapital" name="注册资金" label="注册资金" placeholder="注册资金" />
+          <van-field
+            readonly
+            clickable
+            name="calendar"
+            :value="userInfo.companydate"
+            label="注册时间"
+            placeholder="点击选择日期"
+            @click="showCalendar = true"
+          />
+          <van-calendar v-model="showCalendar" @confirm="onConfirm" />
+          <van-field v-model="userInfo.companytype" name="注册类型" label="注册类型" placeholder="注册类型" />
+          <van-field v-model="userInfo.companytotal" name="企业总人数" label="企业总人数" placeholder="企业总人数" />
+          <van-field v-model="userInfo.sndyffy" name="研发费用" label="研发费用" placeholder="研发费用" />
+          <van-field v-model="userInfo.sndqyzsr" name="企业总收入" label="企业总收入" placeholder="企业总收入" />
+          <van-field v-model="userInfo.zjzyfrs" name="研发人数" label="研发人数" placeholder="研发人数" />
+          <van-field
+            v-model="userInfo.companybrief"
+            name="企业简介"
+            label="企业简介"
+            placeholder="企业简介"
+            type="textarea"
+            rows="2"
+            autosize
+            maxlength="300"
+            show-word-limit
+          />
+          <van-field
+            v-model="userInfo.mainproduct"
+            name="主要产品"
+            label="主要产品"
+            placeholder="主要产品"
+            type="textarea"
+            rows="2"
+            autosize
+            maxlength="300"
+            show-word-limit
+          />
+          <van-field
+            v-model="userInfo.qualifications"
+            name="企业资质"
+            label="企业资质"
+            placeholder="企业资质"
+            type="textarea"
+            rows="2"
+            autosize
+            maxlength="300"
+            show-word-limit
+          />
+          <van-col span="24" class="btn">
+            <van-button round block type="info" @click="onSubmit">保存信息</van-button>
+          </van-col>
+        </van-form>
+      </van-col>
+    </van-row>
+  </div>
+</template>
+
+<script>
+var moment = require('moment');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'company-1',
+  props: { userInfo: { type: Object } },
+  components: {},
+  data: function () {
+    return {
+      showCalendar: false,
+    };
+  },
+  created() {},
+  methods: {
+    onSubmit() {
+      this.$emit('onSubmit', { data: this.userInfo });
+    },
+    onConfirm(date) {
+      this.$set(this.userInfo, `companydate`, moment(date).format('YYYY-MM-DD'));
+      this.showCalendar = false;
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 91 - 0
src/views/exchange/center copy/parts/user-1.vue

@@ -0,0 +1,91 @@
+<template>
+  <div id="list-1">
+    <van-col span="24" class="main">
+      <van-col span="24" class="list" v-for="(item, index) in list" :key="index">
+        <van-col span="24" class="title">
+          {{ item.name }}
+        </van-col>
+        <van-col span="24" class="other">
+          <van-col span="24" class="otherInfo">
+            组织机构代码:<span>{{ item.institution_code || '暂无' }}</span>
+          </van-col>
+          <van-col span="24" class="otherInfo">
+            所属辖区:<span>{{ item.juris || '暂无' }}</span>
+          </van-col>
+        </van-col>
+        <van-col span="24" class="btn">
+          <el-button type="primary" size="mini" @click="bind(item)" v-if="item.openid == null">绑定</el-button>
+          <el-button type="danger" size="mini" @click="removeBind(item)" v-if="item.openid">解绑</el-button>
+        </van-col>
+      </van-col>
+    </van-col>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'list-1',
+  props: {
+    list: { type: Array },
+  },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    // 绑定微信
+    bind(data) {
+      this.$emit('bind', data);
+    },
+    // 接触绑定
+    removeBind(data) {
+      this.$emit('removeBind', data);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 8px 8px 0 8px;
+  .list {
+    background-color: #fff;
+    margin: 0 0 8px 0;
+    padding: 8px;
+    border-radius: 5px;
+    .title {
+      font-size: 16px;
+      font-weight: bold;
+      margin: 0 0 5px 0;
+    }
+    .other {
+      .otherInfo {
+        font-size: 14px;
+        color: #666;
+        margin: 0 0 5px 0;
+        span {
+          color: #000;
+        }
+      }
+    }
+    .btn {
+      text-align: center;
+    }
+  }
+}
+</style>

+ 88 - 0
src/views/exchange/center copy/user/index.vue

@@ -0,0 +1,88 @@
+<template>
+  <div id="index">
+    <admin-frame @search="search" :limit="limit" :total="total" topType="3" @back="back">
+      <template v-slot:info>
+        <user-1 :list="list" @bind="wxBind" @removeBind="removeBind"></user-1>
+      </template>
+    </admin-frame>
+  </div>
+</template>
+
+<script>
+import user1 from '../parts/user-1.vue';
+import adminFrame from '@/layout/common/admin-frame.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: organization } = createNamespacedHelpers('organization');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    adminFrame,
+    user1,
+  },
+  data: function () {
+    return {
+      list: [],
+      total: 0,
+      limit: 10,
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...organization(['getList', 'bind', 'bindRemove']),
+    async search({ skip = 0, limit = this.limit, searchName, ...info } = {}) {
+      if (searchName) info.name = this.searchName;
+      info.phone = this.user.phone;
+      let res = await this.getList({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+      }
+    },
+    // 绑定微信
+    async wxBind(data) {
+      let arr = { id: data._id, openid: sessionStorage.getItem('openid') };
+      let res = await this.bind(arr);
+      if (this.$checkRes(res)) {
+        this.$notify({
+          message: '用户绑定成功',
+          type: 'success',
+        });
+        this.search();
+      }
+    },
+    // 解除绑定
+    async removeBind(data) {
+      let arr = { id: data._id, openid: sessionStorage.getItem('openid') };
+      let res = await this.bindRemove(arr);
+      if (this.$checkRes(res)) {
+        this.$notify({
+          message: '用户解绑成功',
+          type: 'success',
+        });
+        this.search();
+      }
+    },
+    back() {
+      this.$router.push({ path: '/exchange/center/index' });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 87 - 0
src/views/exchange/center/adminCenter/mechanism/detail.vue

@@ -0,0 +1,87 @@
+<template>
+  <div id="detail">
+    <admin-frame :usePage="false" topType="2" :rightArrow="false" @back="back" :useNav="false">
+      <template v-slot:info>
+        <detail-1 :form="form" :pidList="pidList" @onSubmit="onSubmit"></detail-1>
+      </template>
+    </admin-frame>
+  </div>
+</template>
+
+<script>
+import detail1 from './parts/detail_1.vue';
+import adminFrame from '@frame/src/components/mobile-frame/mobile-main.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: adminLogin } = createNamespacedHelpers('adminLogin');
+export default {
+  name: 'detail',
+  props: {},
+  components: {
+    adminFrame,
+    detail1,
+  },
+  data: function () {
+    return {
+      form: {},
+      pidList: [],
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...adminLogin(['query', 'fetch', 'update', 'delete']),
+    async search() {
+      let res = await this.query({ role: '1' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `pidList`, res.data);
+      }
+      if (this.id) {
+        res = await this.fetch(this.id);
+        if (this.$checkRes(res)) {
+          res.data.pidName = this.pidList.find((i) => i.id == res.data.pid).name;
+          this.$set(this, `form`, res.data);
+        }
+      }
+    },
+    // 查看详情
+    async onSubmit(data) {
+      data.role = '2';
+      if (data.id) {
+        let res = await this.update(data);
+        if (this.$checkRes(res)) {
+          this.$toast({ type: `success`, message: `信息修改成功` });
+          this.back();
+        }
+      } else {
+        let res = await this.create(data);
+        if (this.$checkRes(res)) {
+          this.$toast({ type: `success`, message: `信息创建成功` });
+          this.back();
+        }
+      }
+    },
+    back() {
+      this.$router.push({ path: `/exchange/center/adminCenter/mechanism/index` });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 0 - 0
src/views/exchange/center/adminCenter/mechanism/index.vue


Some files were not shown because too many files changed in this diff