Browse Source

维基官网平台后台管理系统

master
aBin 4 years ago
commit
b6d9f66773
  1. 3
      .browserslistrc
  2. 8
      .editorconfig
  3. 3
      .env
  4. 10
      .env.development
  5. 10
      .env.production
  6. 45
      .eslintrc.js
  7. 23
      .gitignore
  8. 13
      .prettierrc
  9. 24
      README.md
  10. 13
      babel.config.js
  11. 1
      commitlint.config.js
  12. 13778
      package-lock.json
  13. 53
      package.json
  14. BIN
      public/favicon.ico
  15. BIN
      public/img/icons/android-chrome-192x192.png
  16. BIN
      public/img/icons/android-chrome-512x512.png
  17. BIN
      public/img/icons/android-chrome-maskable-192x192.png
  18. BIN
      public/img/icons/android-chrome-maskable-512x512.png
  19. BIN
      public/img/icons/apple-touch-icon-120x120.png
  20. BIN
      public/img/icons/apple-touch-icon-152x152.png
  21. BIN
      public/img/icons/apple-touch-icon-180x180.png
  22. BIN
      public/img/icons/apple-touch-icon-60x60.png
  23. BIN
      public/img/icons/apple-touch-icon-76x76.png
  24. BIN
      public/img/icons/apple-touch-icon.png
  25. BIN
      public/img/icons/favicon-16x16.png
  26. BIN
      public/img/icons/favicon-32x32.png
  27. BIN
      public/img/icons/msapplication-icon-144x144.png
  28. BIN
      public/img/icons/mstile-150x150.png
  29. 3
      public/img/icons/safari-pinned-tab.svg
  30. 18
      public/index.html
  31. 2
      public/robots.txt
  32. 82
      public/sdk.js
  33. 15
      rest/http-client.env.json
  34. 56
      rest/project.http
  35. 74
      src/App.vue
  36. BIN
      src/assets/logo.png
  37. 312
      src/common/portrait.styl
  38. 292
      src/components/Activity/ActivityAdd.vue
  39. 294
      src/components/Activity/ActivityDate.vue
  40. 337
      src/components/Activity/ActivityEdit.vue
  41. 101
      src/components/Activity/ActivitySearch.vue
  42. 239
      src/components/Banner/BannerAdd.vue
  43. 183
      src/components/Banner/BannerDate.vue
  44. 260
      src/components/Banner/BannerEdit.vue
  45. 148
      src/components/Banner/BannerSearch.vue
  46. 78
      src/components/BtnCom/BtnCon.vue
  47. 221
      src/components/CVideo/VideoAdd.vue
  48. 206
      src/components/CVideo/VideoDate.vue
  49. 221
      src/components/CVideo/VideoEdit.vue
  50. 54
      src/components/CVideo/VideoSearch.vue
  51. 233
      src/components/Challenge/ChallengeAdd.vue
  52. 192
      src/components/Challenge/ChallengeDate.vue
  53. 195
      src/components/Challenge/ChallengeEdit.vue
  54. 74
      src/components/Challenge/ChallengeSearch.vue
  55. 106
      src/components/Comment/CommentDate.vue
  56. 38
      src/components/Comment/CommentSearch.vue
  57. 181
      src/components/Community/CommentDate.vue
  58. 53
      src/components/Community/CommentSearch.vue
  59. 255
      src/components/Community/CommunityDate.vue
  60. 76
      src/components/Community/CommunitySearch.vue
  61. 233
      src/components/Course/CourseAdd.vue
  62. 205
      src/components/Course/CourseDate.vue
  63. 195
      src/components/Course/CourseEdit.vue
  64. 74
      src/components/Course/CourseSearch.vue
  65. 158
      src/components/Development/Detail.vue
  66. 639
      src/components/Development/DevelopmentAdd.vue
  67. 227
      src/components/Development/DevelopmentDate.vue
  68. 766
      src/components/Development/DevelopmentEdit.vue
  69. 64
      src/components/Development/DevelopmentSearch.vue
  70. 105
      src/components/Development/mixins/addMixin.js
  71. 46
      src/components/EditableCellSelect/EditableCellSelect.vue
  72. 174
      src/components/Enroll/EnrollDate.vue
  73. 163
      src/components/Enroll/EnrollSearch.vue
  74. 140
      src/components/EntityApply/Detail.vue
  75. 439
      src/components/EntityApply/EntityApplyAdd.vue
  76. 184
      src/components/EntityApply/EntityApplyDate.vue
  77. 81
      src/components/EntityApply/EntityApplySearch.vue
  78. 186
      src/components/IndustryInfo/ActivityAdd.vue
  79. 174
      src/components/IndustryInfo/ActivityDate.vue
  80. 191
      src/components/IndustryInfo/ActivityEdit.vue
  81. 83
      src/components/IndustryInfo/ActivitySearch.vue
  82. 266
      src/components/Institute/InstituteAdd.vue
  83. 226
      src/components/Institute/InstituteDate.vue
  84. 287
      src/components/Institute/InstituteEdit.vue
  85. 70
      src/components/Institute/InstituteSearch.vue
  86. 122
      src/components/Manage/ManageAdd.vue
  87. 145
      src/components/Manage/ManageDate.vue
  88. 125
      src/components/Manage/ManageEdit.vue
  89. 82
      src/components/Manage/ManageSearch.vue
  90. 126
      src/components/Page/PageAdd.vue
  91. 175
      src/components/Page/PageDate.vue
  92. 131
      src/components/Page/PageEdit.vue
  93. 51
      src/components/Page/PageSearch.vue
  94. 167
      src/components/Partner/PartnerAdd.vue
  95. 206
      src/components/Partner/PartnerDate.vue
  96. 199
      src/components/Partner/PartnerEdit.vue
  97. 87
      src/components/Partner/PartnerSearch.vue
  98. 190
      src/components/Policy/PolicyAdd.vue
  99. 238
      src/components/Policy/PolicyDate.vue
  100. 219
      src/components/Policy/PolicyEdit.vue

3
.browserslistrc

@ -0,0 +1,3 @@
> 1%
last 2 versions
not dead

8
.editorconfig

@ -0,0 +1,8 @@
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 140
root = true

3
.env

@ -0,0 +1,3 @@
VUE_APP_MODE=production
VUE_APP_PREVIEW=false
VUE_APP_URL=https://www.sxgreenvalley.com/

10
.env.development

@ -0,0 +1,10 @@
VUE_APP_MODE=development
VUE_APP_NODE_ENV=development
VUE_APP_SCENE=wikiback
VUE_APP_BASE_URL=https://www.sxwikionline.com/
VUE_APP_API_URL=https://www.sxwikionline.com/gateway
VUE_APP_PROXY_URL=/gateway
VUE_APP_PUBLIC_PATH=/wikiback
VUE_APP_MSG_URL=wss://www.sxwikionline.com/websocket/message/v4.0/ws
VUE_APP_TITLE=维基在线
VUE_APP_DESCRIPTION=维基在线管理后台

10
.env.production

@ -0,0 +1,10 @@
VUE_APP_MODE=production
VUE_APP_NODE_ENV=production
VUE_APP_SCENE=wikiback
VUE_APP_BASE_URL=https://www.sxwikionline.com/
VUE_APP_API_URL=https://www.sxwikionline.com/gateway
VUE_APP_PROXY_URL=/gateway
VUE_APP_PUBLIC_PATH=/wikiback
VUE_APP_MSG_URL=wss://www.sxwikionline.com/websocket/message/v4.0/ws
VUE_APP_TITLE=维基在线
VUE_APP_DESCRIPTION=维基在线管理后台

45
.eslintrc.js

@ -0,0 +1,45 @@
/*
* Copyright (c) 2019.
* author: wally
* email: 18603454788@163.com
*/
module.exports = {
root: true,
env: { browser: true, node: true },
extends: ['plugin:vue/recommended', 'plugin:vue/essential'],
rules: {
'vue/html-self-closing': 'off',
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-param-reassign': ['error', { props: true, ignorePropertyModificationsFor: ['state'] }],
'max-len': ['error', { code: 140, tabWidth: 2 }],
'object-curly-newline': ['error', { multiline: true }],
'arrow-parens': ['error', 'as-needed'],
'linebreak-style': 'off',
'vue/attributes-order': 'off',
'no-param-reassign': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/max-attributes-per-line': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/html-indent': 'off',
},
parserOptions: { parser: 'babel-eslint' },
overrides: [
{
files: ['**/__tests__/*.{j,t}s?(x)'],
env: { jest: true },
},
],
globals: {
Vue: true,
VueRouter: true,
Vuex: true,
axios: true,
_: true,
},
};

23
.gitignore

@ -0,0 +1,23 @@
.DS_Store
node_modules
/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?

13
.prettierrc

@ -0,0 +1,13 @@
{
"printWidth": 140,
"singleQuote": true,
"semi": true,
"trailingComma": "all",
"arrowParens": "avoid",
"tabWidth": 2,
"useTabs": false,
"bracketSpacing": true,
"jsxBracketSameLine": false,
"proseWrap": "always",
"endOfLine": "lf"
}

24
README.md

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

13
babel.config.js

@ -0,0 +1,13 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
plugins: [
[
"import",
{
libraryName: "ant-design-vue",
libraryDirectory: "es",
style: true
}
]
]
};

1
commitlint.config.js

@ -0,0 +1 @@
module.exports = {extends: ['./node_modules/vue-cli-plugin-commitlint/lib/lint']};

13778
package-lock.json

File diff suppressed because it is too large

53
package.json

@ -0,0 +1,53 @@
{
"name": "green-valley",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"ant-design-vue": "^1.2.4",
"compression-webpack-plugin": "^6.1.1",
"core-js": "^3.6.5",
"moment": "^2.29.1",
"register-service-worker": "^1.7.1",
"stylus": "^0.54.8",
"vue": "^2.6.11",
"vue-dompurify-html": "^2.3.0",
"vue-quill-editor": "^3.0.6",
"vue-router": "^3.2.0",
"vuetify": "^2.4.6",
"vuex": "^3.4.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-pwa": "~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",
"axios": "^0.18.0",
"babel-eslint": "^10.1.0",
"babel-plugin-import": "^1.11.0",
"css-loader": "^5.0.1",
"deepmerge": "^4.2.2",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-vue": "^6.2.2",
"less": "^2.7.3",
"less-loader": "^4.1.0",
"material-design-icons-iconfont": "^6.1.0",
"prettier": "^1.19.1",
"sass": "^1.32.8",
"sass-loader": "^8.0.2",
"stylus": "^0.54.5",
"stylus-loader": "^3.0.2",
"svg-sprite-loader": "^5.0.0",
"vue-cli-plugin-ant-design": "^1.0.1",
"vue-cli-plugin-axios": "^0.0.4",
"vue-template-compiler": "^2.6.11"
}
}

BIN
public/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
public/img/icons/android-chrome-192x192.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
public/img/icons/android-chrome-512x512.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
public/img/icons/android-chrome-maskable-192x192.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
public/img/icons/android-chrome-maskable-512x512.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
public/img/icons/apple-touch-icon-120x120.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
public/img/icons/apple-touch-icon-152x152.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
public/img/icons/apple-touch-icon-180x180.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
public/img/icons/apple-touch-icon-60x60.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
public/img/icons/apple-touch-icon-76x76.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
public/img/icons/apple-touch-icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
public/img/icons/favicon-16x16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 799 B

BIN
public/img/icons/favicon-32x32.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
public/img/icons/msapplication-icon-144x144.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
public/img/icons/mstile-150x150.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

3
public/img/icons/safari-pinned-tab.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.00251 14.9297L0 1.07422H6.14651L8.00251 4.27503L9.84583 1.07422H16L8.00251 14.9297Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 215 B

18
public/index.html

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<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 -->
<script src="./sdk.js"></script>
</body>
</html>

2
public/robots.txt

@ -0,0 +1,2 @@
User-agent: *
Disallow:

82
public/sdk.js

@ -0,0 +1,82 @@
(function(window) {
var _instance = null;
window.TallPlugin = function(config) {
this.config = config;
this.props = null;
};
// 初始化并保证是单例
TallPlugin.init = function(config) {
if (!_instance) {
_instance = new TallPlugin(config);
}
return _instance;
};
function postMsg(message) {
let origin = '*';
window.postMessage(message, origin);
}
TallPlugin.prototype.created = function(callback) {
console.log('created begin');
var _this = this;
postMsg('created');
window.addEventListener(
'message',
function({ data, origin }) {
console.log('on created message, data, origin: ', data, origin);
try {
var target = JSON.parse(data);
if (target.success) {
_this.props = JSON.parse(data);
callback && typeof callback === 'function' && callback.call(_this, _this.props);
}
// else {
// _this.props = null;
// }
} catch (e) {
_this.props = null;
}
},
false,
);
// DOM加载完成
window.addEventListener('DOMContentLoaded', this.mounted, false);
// window onload
window.addEventListener('load', this.loaded, false);
// destroy
window.addEventListener('unload', this.destroy, false);
// error
window.addEventListener('error', this.error, false);
return this;
};
TallPlugin.prototype.mounted = function(callback) {
console.log('mounted');
postMsg('mounted');
callback && typeof callback === 'function' && callback.call(this);
return this;
};
TallPlugin.prototype.loaded = function(callback) {
console.log('loaded');
postMsg('loaded');
callback && typeof callback === 'function' && callback.call(this);
return this;
};
TallPlugin.prototype.destroy = function(callback) {
console.log('destroy');
postMsg('destroy');
callback && typeof callback === 'function' && callback.call(this);
return this;
};
TallPlugin.prototype.error = function(callback) {
console.log('error');
postMsg('error');
callback && typeof callback === 'function' && callback.call(this);
return this;
};
})(window);

15
rest/http-client.env.json

@ -0,0 +1,15 @@
{
"$shared": {
"version": "v1",
"identifier": "wally",
"credential": "111111"
},
"dev": {
"name": "dev",
"url": "http://192.168.0.99/gateway"
},
"local": {
"version": "v2",
"url": "http://192.168.0.99/gateway"
}
}

56
rest/project.http

@ -0,0 +1,56 @@
# @tall = {{url}}/tall/v1.0
@tall = https://www.sxgreenvalley.com/gateway/tall/v1.0
@greenvalley = https://www.sxgreenvalley.com/gateway/greenvalley
@type = content-type: application/json;charset=utf-8
### login
# @name login
POST {{tall}}/users/signin
{{type}}
{
"client": 1,
"type": 3,
"data": {
"identifier": "song",
"credential": "999999"
}
}
### send code
GET {{tall}}/users/smscode?phone=16603418748
### phone login
# @name phonelogin
POST {{tall}}/users/signin
{{type}}
{
"client": 1,
"type": 1,
"data": {
"identifier": "15235360226",
"credential": "1111"
}
}
### 根据团队id查看研发团队相关信息
POST {{greenvalley}}/researchTeam/selectTeam
{{type}}
Authorization: Bearer {{login.response.body.$.data.token}}
{
"param": {
"company": "",
"researchDirection": "",
"teamId": 0,
"teamIntroduce": "",
"teamLeaderName": "",
"teamName": ""
}
}

74
src/App.vue

@ -0,0 +1,74 @@
<template>
<a-config-provider :locale="zh_CN">
<div class="d-flex flex-row flex-nowrap" id="app">
<btn-con />
<router-view class="flex-1 bg pa-3"></router-view>
</div>
</a-config-provider>
</template>
<script>
import { mapState, mapActions, mapMutations } from 'vuex';
import zh_CN from 'ant-design-vue/lib/locale-provider/zh_CN';
import BtnCon from 'components/BtnCom/BtnCon.vue';
export default {
name: 'app',
components: { BtnCon },
data() {
return {
zh_CN,
};
},
computed: mapState(['anyringToken', 'ptProps']),
watch: {
ptProps(val) {
if (val.userId) {
const params = { userId: val.userId };
this.getUserId(params);
console.log('val.userId:' + val.userId);
}
},
},
created() {
//
const userId = '1218763410024566784';
const params = { userId };
this.getUserId(params);
const that = this;
window.plugin = window.TallPlugin.init();
// created created便
// created created
// PT ididididuserId
window.plugin.created(function(props) {
console.log('props: ', props);
that.setPtProps(props);
});
},
methods: {
...mapActions(['getUserId']),
...mapMutations('home', ['setPtProps']),
},
};
</script>
<style>
html {
overflow: hidden !important;
}
html,
body,
#app {
height: 100%;
}
#app {
background: transparent;
}
</style>

BIN
src/assets/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

312
src/common/portrait.styl

@ -0,0 +1,312 @@
// padding
.pa-3 {
padding: 12px;
}
.pl-1{
padding-left: 4px;
}
.pl-2{
padding-left: 8px;
}
.pl-3{
padding-left: 12px;
}
.pl-4{
padding-left: 16px;
}
.pl-5{
padding-left: 20px;
}
.px-1{
padding-left: 4px;
padding-right: 4px;
}
.px-2{
padding-left: 8px;
padding-right: 8px;
}
.px-3{
padding-left: 12px;
padding-right: 12px;
}
.px-10{
padding-left: 30px;
padding-right: 30px;
}
.pb-3 {
padding-bottom: 12px;
}
.pb-4 {
padding-bottom: 16px;
}
.pb-5 {
padding-bottom: 20px;
}
.pb-10 {
padding-bottom: 40px;
}
// margin
.ma-2 {
margin: 8px;
}
.ma-3 {
margin: 12px;
}
.mx-2{
margin-left: 8px;
margin-right: 8px;
}
.my-2{
margin-top: 8px;
margin-bottom: 8px;
}
.my-3{
margin-top: 12px;
margin-bottom: 12px;
}
.my-4{
margin-top: 16px;
margin-bottom: 16px;
}
.mt-1{
margin-top: 4px;
}
.mt-2{
margin-top: 8px;
}
.mt-3{
margin-top: 12px;
}
.mt-4{
margin-top: 16px;
}
.mb-1{
margin-bottom: 4px;
}
.mb-2{
margin-bottom: 8px;
}
.mb-3{
margin-bottom: 12px;
}
.mb-4{
margin-bottom: 16px;
}
.ml-2{
margin-left: 8px;
}
.ml-3{
margin-left: 12px;
}
.ml-4{
margin-left: 16px;
}
.ml-5{
margin-left: 20px;
}
.ml-6{
margin-left: 24px;
}
.ml-7{
margin-left: 28px;
}
.ml-8{
margin-left: 32px;
}
.mr-1{
margin-right: 4px;
}
.mr-2{
margin-right: 8px;
}
.mr-3{
margin-right: 12px;
}
.mr-4{
margin-right: 16px;
}
.mr-5{
margin-right: 20px;
}
.mr-6{
margin-right: 24px;
}
// background
.white {
background: white;
}
.green{
background: #4CAF50;
}
.white--text{
color: #fff;
}
// flex
.d-flex{
display: flex;
}
.flex-wrap{
flex-wrap: wrap;
}
.flex-nowrap{
flex-wrap: nowrap;
}
.flex-column{
flex-direction: column;
}
.flex-column-reverse{
flex-direction: column-reverse;
}
.flex-row{
flex-direction: row;
}
.flex-row-reverse{
flex-direction: row-reverse;
}
.justify-center{
justify-content: center;
}
.justify-space-between{
justify-content: space-between;
}
.align-center{
align-items: center;
}
.align-left{
align-items: start;
}
.flex-1{
display: flex;
flex: 1;
}
.flex-2{
display: flex;
flex: 2;
}
// other
.pointer{
cursor:pointer;
}
.fill-height{
height:100%;
}
// font
.font-bold{
font-weight: bold;
}
.font-bold-24{
font-size: 24px;
font-weight: bold;
}
.font-24{
font-size: 24px;
}
.font-bold-16{
font-size: 16px;
font-weight: bold;
}
.font-16{
font-size: 16px;
}
.font-bold-14{
font-size: 14px;
font-weight: bold;
}
.font-14{
font-size: 14px;
}
.icon-size{
font-size: 20px;
}
h2{
font-size: 24px;
font-weight: bold;
color: rgba(0,0,0,.85)
}
.textColor{
color: rgba(0,0,0,.65)
}
.baseColor{
color: #1890ff
}
.bg{
background: #F5F5F5
}
.fill-width{
width:100%;
}
.fill-height{
height:100%;
}

292
src/components/Activity/ActivityAdd.vue

@ -0,0 +1,292 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 添加 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="添加活动公告"
v-model="visible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 标题 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="标题"
>
<a-input
placeholder="标题"
v-decorator="[
'title',
{
rules: [
{ required: true, message: '标题不能为空' },
{ whitespace: true, message: '标题不能为空' },
{ max: 140, massage: '地点最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 地点 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="地点"
>
<a-input
placeholder="地点"
v-decorator="[
'address',
{
rules: [
{ required: true, message: '地点不能为空' },
{ whitespace: true, message: '地点不能为空' },
{ max: 140, massage: '地点最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 时间 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="时间"
required
>
<a-range-picker
@change="onChange"
format="YYYY-MM-DD HH:mm:ss"
show-time
style="width:100%"
/>
</a-form-item>
<!-- 活动类型 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="活动类型"
>
<a-select @change="changeType" placeholder="活动类型" style="width:100%">
<a-select-option
:key="index"
:value="category.id"
v-for="(category, index) in types"
>{{ category.name }}</a-select-option>
</a-select>
</a-form-item>
<!-- 主讲人 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="主讲人"
>
<a-input
placeholder="主讲人"
v-decorator="[
'name',
{
rules: [
{ required: true, message: '主讲人不能为空' },
{ whitespace: true, message: '主讲人不能为空' },
{ max: 140, massage: '主讲人最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 组织单位 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="组织单位"
>
<a-input
placeholder="组织单位"
v-decorator="[
'organization'
]"
/>
</a-form-item>
<!-- 其他事宜 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="其他事宜"
>
<a-input
placeholder="其他事宜"
v-decorator="[
'other'
]"
/>
</a-form-item>
<!-- 会议主题 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="会议主题"
>
<a-input
placeholder="会议主题"
v-decorator="[
'theme'
]"
/>
</a-form-item>
<!-- 培训对象 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="培训对象"
>
<a-input
placeholder="培训对象"
v-decorator="[
'trainees'
]"
/>
</a-form-item>
<!-- 报名方式 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="报名方式"
>
<a-input
placeholder="报名方式"
v-decorator="[
'way'
]"
/>
</a-form-item>
<!-- 活动结束内容 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="活动结束内容"
>
<a-textarea
placeholder="活动结束内容"
v-decorator="[
'endContent',
]"
/>
</a-form-item>
<!-- 详情 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="详情"
required
>
<quill-editor :max-size="maxSize" :placeholder="placeholder" @changeInput="changeInput" />
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { saveActivity } from 'config/api';
import QuillEditor from 'components/QuillEditor/QuillEditor.vue';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'ActivityAdd',
props: { visible: { type: Boolean, default: false } },
components: { QuillEditor },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'activity-add' }),
types: [
{ id: 0, name: '路演' },
{ id: 1, name: '沙龙' },
{ id: 2, name: '论坛' },
],
activityType: '',
maxSize: 2048,
content: '',
placeholder: '请输入...',
releaseTime: '', //
closeTime: '', //
};
},
methods: {
//
changeType(value) {
console.log('value: ', value);
this.activityType = value;
},
//
onChange(dates, dateStrings) {
console.log('From: ', dates[0], ', to: ', dates[1]);
console.log('From: ', dateStrings[0], ', to: ', dateStrings[1]);
this.releaseTime = dateStrings[0];
this.closeTime = dateStrings[1];
},
//
changeInput(value) {
this.content = value;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
console.log('values: ', values);
const { releaseTime, closeTime, content, activityType } = this;
const params = { param: values };
params.param.releaseTime = releaseTime;
params.param.closeTime = closeTime;
params.param.content = content;
params.param.activityType = activityType;
console.log('params: ', params);
const res = await saveActivity(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('添加成功');
this.$emit('closeModal');
} else {
this.$emit('closeModal');
throw msg;
}
} catch (error) {
this.$message.error(error || '添加失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

294
src/components/Activity/ActivityDate.vue

@ -0,0 +1,294 @@
<template>
<div class="main flex-1">
<a-spin :spinning="showEdit">
<div style="width:100%" v-if="lists && lists.length > 0">
<a-table
:columns="columns"
:data-source="lists"
:loading="loading"
:pagination="pagination"
:row-key="record => record.activityId"
:scroll="{ y: height }"
@change="handleTableChange"
@expand="getDetail"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<template slot="time" slot-scope="text, record">
<span v-if="record.releaseTime">{{ record.releaseTime}}</span>
<span v-if="record.closeTime">-{{record.closeTime}}</span>
</template>
<template slot="auditStatus" slot-scope="text, record">
<a-tag
:color="record.auditStatus === 2 ? 'green' : record.auditStatus === 1 ? 'red' : 'blue'"
>{{ record.auditStatus === 2 ? '已通过' : record.auditStatus === 1 ? '未通过' : '审核中' }}</a-tag>
</template>
<template slot="examine" slot-scope="text, record">
<div class="d-flex flex-column align-center">
<a-button
@click="handleApply(record, 2)"
size="small"
type="primary"
v-if="record.auditStatus !== 2"
>通过</a-button>
<a-button @click="handleApply(record, 1)" size="small" type="danger" v-else>不通过</a-button>
<a-textarea class="fill-width mt-3" placeholder="备注" v-model="record.remark" />
</div>
</template>
<template slot="edit" slot-scope="text, record">
<a-icon
@click="showEditModal(record)"
class="pointer mr-5"
theme="twoTone"
type="edit"
/>
<a-button @click="openEnroll(record.activityId)" size="small" type="primary">活动报名</a-button>
</template>
<div
class="d-flex flex-column"
slot="expandedRowRender"
slot-scope="record"
style="margin: 0"
>
<a-spin :spinning="spinning" tip="详情加载中...">
<div class="d-flex flex-nowrap justify-space-between mb-3">
<div class="d-flex flex-row">
<span class="font-bold-14">主讲人</span>
<span v-if="record.info && record.info.name">{{ record.info.name }}</span>
<span v-else>暂无</span>
</div>
<div class="d-flex flex-row">
<span class="font-bold-14">
活动类型
<a-tag
color="blue"
v-if="record.info && record.info.activityType !== null"
>{{ record.info.activityType === 0 ? '路演' : record.info.activityType === 1 ? '讲座' : record.info.activityType === 2 ? '沙龙' : '' }}</a-tag>
</span>
</div>
<div class="d-flex flex-row">
<span class="font-bold-14">培训对象</span>
<span v-if="record.info && record.info.trainees">{{ record.info.trainees }}</span>
<span v-else>暂无</span>
</div>
</div>
<div class="d-flex flex-nowrap justify-space-between mb-3">
<div class="d-flex flex-row">
<span class="font-bold-14">组织单位</span>
<span
v-if="record.info && record.info.organization"
>{{ record.info.organization }}</span>
<span v-else>暂无</span>
</div>
<div class="d-flex flex-row">
<span class="font-bold-14">
发布平台
<a-tag
color="green"
v-if="record.info && record.info.publishPlatform !== null"
>{{ record.info.publishPlatform === 0 ? '绿谷' : record.info.publishPlatform === 1 ? '创时代' : '' }}</a-tag>
</span>
</div>
</div>
<div class="mb-3">
<span class="font-bold-14">活动结束内容</span>
<br />
<span v-if="record.info && record.info.endContent">{{ record.info.endContent }}</span>
<span v-else>暂无内容</span>
</div>
<div class="mb-3">
<span class="font-bold-14">公告简介</span>
<br />
<span v-if="record.intro">{{ record.intro }}</span>
<span v-else>暂无内容</span>
</div>
<div>
<span class="font-bold-14">详情</span>
<span v-dompurify-html="record.info.content" v-if="record.info.content"></span>
<span v-else>暂无内容</span>
</div>
</a-spin>
</div>
</a-table>
</div>
<a-empty v-else />
<!-- 编辑 -->
<activity-edit
:editItem="editItem"
:editVisible="editVisible"
@closeModal="closeModal"
@getDetail="getDetail"
@getSelectTeam="getSelectTeam"
/>
</a-spin>
</div>
</template>
<script>
import ActivityEdit from 'components/Activity/ActivityEdit.vue';
import { getQueryDetail, auditApply } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: 80,
scopedSlots: { customRender: 'id' },
},
{
title: '标题',
align: 'center',
dataIndex: 'title',
key: 'title',
},
{
title: '地点',
align: 'center',
dataIndex: 'address',
key: 'address',
},
{
title: '活动时间',
align: 'center',
dataIndex: 'time',
key: 'time',
scopedSlots: { customRender: 'time' },
},
{
title: '审批状态',
align: 'center',
dataIndex: 'auditStatus',
key: 'auditStatus',
width: 100,
scopedSlots: { customRender: 'auditStatus' },
},
{
title: '审核',
align: 'center',
dataIndex: 'examine',
key: 'examine',
scopedSlots: { customRender: 'examine' },
},
{
title: '编辑',
align: 'center',
dataIndex: 'edit',
key: 'edit',
scopedSlots: { customRender: 'edit' },
},
];
export default {
name: 'ActivityDate',
components: {
ActivityEdit,
},
props: { lists: { type: Array, default: () => [] }, pagination: { type: Object, default: () => {} } },
data() {
return {
columns,
loading: false,
height: '',
editVisible: false,
editItem: null, //
spinning: false,
showEdit: false,
};
},
mounted() {
let th = 250;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
async showEditModal(record) {
this.showEdit = true;
await this.getDetail(true, record);
this.showEdit = false;
this.editItem = record;
this.editVisible = true;
},
closeModal() {
this.editVisible = false;
},
async getSelectTeam() {
await this.$emit('getSelectTeam');
},
//
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('getSelectTeam', condition);
},
//
async getDetail(expanded, record) {
if (!expanded) return;
try {
this.spinning = true;
const params = { param: { activityId: record.activityId } };
const res = await getQueryDetail(params);
const { data, msg, code } = res.data;
this.spinning = false;
if (code === 200) {
const item = this.lists.find(item => item.activityId === record.activityId);
item.info = data;
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '查询失败');
}
},
//
async handleApply(record, auditStatus) {
try {
const params = { param: { activityId: record.activityId, auditStatus, remark: record.remark } };
const res = await auditApply(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('审核成功');
this.$emit('getSelectTeam');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '审核失败');
}
},
//
openEnroll(id) {
const { query } = this.$route;
this.$router.push({ path: `/event-registration?activityId=${id}`, query });
},
},
};
</script>
<style scoped lang="stylus"></style>

337
src/components/Activity/ActivityEdit.vue

@ -0,0 +1,337 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 编辑 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="修改活动公告"
v-model="editVisible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit" v-if="editVisible && editItem">
<!-- 标题 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="标题"
>
<a-input
placeholder="标题"
v-decorator="[
'title',
{
initialValue: editItem.title || '',
rules: [
{ required: true, message: '标题不能为空' },
{ whitespace: true, message: '标题不能为空' },
{ max: 140, massage: '地点最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 地点 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="地点"
>
<a-input
placeholder="地点"
v-decorator="[
'address',
{
initialValue: editItem.address || '',
rules: [
{ required: true, message: '地点不能为空' },
{ whitespace: true, message: '地点不能为空' },
{ max: 140, massage: '地点最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 时间 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="时间"
required
>
<a-range-picker
:default-value="[editItem.releaseTime ? editItem.releaseTime : '',editItem.closeTime ? editItem.closeTime : '']"
@change="onChange"
format="YYYY-MM-DD HH:mm:ss"
show-time
style="width:100%"
/>
</a-form-item>
<!-- 活动类型 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="活动类型"
>
<a-select
@change="changeType"
placeholder="活动类型"
style="width:100%"
v-decorator="[
'activityType',
{
initialValue: editItem.info && editItem.info.activityType,
},
]"
>
<a-select-option
:key="index"
:value="category.id"
v-for="(category, index) in types"
>{{ category.name }}</a-select-option>
</a-select>
</a-form-item>
<!-- 主讲人 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="主讲人"
>
<a-input
placeholder="主讲人"
v-decorator="[
'name',
{
initialValue: (editItem.info && editItem.info.name) ? editItem.info.name : '',
rules: [
{ required: true, message: '主讲人不能为空' },
{ whitespace: true, message: '主讲人不能为空' },
{ max: 140, massage: '主讲人最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 组织单位 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="组织单位"
>
<a-input
placeholder="组织单位"
v-decorator="[
'organization',
{
initialValue: (editItem.info && editItem.info.organization) ? editItem.info.organization : '',
},
]"
/>
</a-form-item>
<!-- 其他事宜 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="其他事宜"
>
<a-input
placeholder="其他事宜"
v-decorator="[
'other',
{
initialValue: (editItem.info && editItem.info.other) ? editItem.info.other : '',
},
]"
/>
</a-form-item>
<!-- 会议主题 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="会议主题"
>
<a-input
placeholder="会议主题"
v-decorator="[
'theme',
{
initialValue: (editItem.info && editItem.info.theme) ? editItem.info.theme : '',
},
]"
/>
</a-form-item>
<!-- 培训对象 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="培训对象"
>
<a-input
placeholder="培训对象"
v-decorator="[
'trainees',
{
initialValue: (editItem.info && editItem.info.trainees) ? editItem.info.trainees : '',
},
]"
/>
</a-form-item>
<!-- 报名方式 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="报名方式"
>
<a-input
placeholder="报名方式"
v-decorator="[
'way',
{
initialValue: (editItem.info && editItem.info.way) ? editItem.info.way : '',
},
]"
/>
</a-form-item>
<!-- 活动结束内容 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="活动结束内容"
>
<a-textarea
placeholder="活动结束内容"
v-decorator="[
'endContent',
{
initialValue: (editItem.info && editItem.info.endContent) ? editItem.info.endContent : '',
},
]"
/>
</a-form-item>
<!-- 详情 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="详情"
required
>
<quill-editor
:max-size="maxSize"
:value="(editItem && editItem.info && editItem.info.content) ? editItem.info.content : content"
@changeInput="changeInput"
/>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { updateActivity } from 'config/api';
import QuillEditor from 'components/QuillEditor/QuillEditor.vue';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'ActivityEdit',
props: { editVisible: { type: Boolean, default: false }, editItem: { type: Object, default: () => {} } },
components: { QuillEditor },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'activity-edit' }),
types: [
{ id: 0, name: '路演' },
{ id: 1, name: '沙龙' },
{ id: 2, name: '论坛' },
],
activityType: null,
maxSize: 2048,
content: null,
releaseTime: null, //
closeTime: null, //
};
},
methods: {
//
changeInput(value) {
this.content = value;
},
//
changeType(value) {
this.activityType = value;
},
//
onChange(dates, dateStrings) {
this.releaseTime = dateStrings[0];
this.closeTime = dateStrings[1];
},
//
verificationTime() {
if (!this.releaseTime || !this.closeTime) {
this.$message.error('时间不能为空');
return false;
} else {
return true;
}
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
if (!this.verificationTime()) return;
console.log('values: ', values);
const { releaseTime, closeTime, content, activityType, editItem } = this;
const params = { param: values };
params.param.activityId = editItem.activityId;
params.param.releaseTime = releaseTime || editItem.releaseTime;
params.param.closeTime = closeTime || editItem.closeTime;
params.param.content = content || editItem.info.content;
params.param.activityType = activityType || editItem.activityType;
console.log('params: ', params);
const res = await updateActivity(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('修改成功');
this.$emit('getSelectTeam');
this.releaseTime = '';
this.closeTime = '';
this.content = '';
this.activityType = '';
} else {
throw msg;
}
this.$emit('closeModal');
} catch (error) {
this.$emit('closeModal');
this.$message.error(error || '修改失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

101
src/components/Activity/ActivitySearch.vue

@ -0,0 +1,101 @@
<template>
<div class="d-flex flex-wrap pb-3 align-center">
<!-- 活动类型 0路演 1讲座 2沙龙 不传参数则查询全部 -->
<div class="mb-3">
<span class="font-bold-14">活动类型</span>
<a-checkbox-group :options="items" @change="onChange" />
</div>
<!-- 发布平台 -->
<div class="mb-3">
<span class="font-bold-14 ml-8">发布平台</span>
<a-radio-group @change="getPlatform">
<a-radio :value="0">绿谷</a-radio>
<a-radio :value="1">创时代</a-radio>
</a-radio-group>
</div>
<!-- 活动标题 -->
<a-input class="ml-3 mb-3" placeholder="标题" style="width: 150px" v-model="titleKey" />
<!-- 发布时间 -->
<a-range-picker @change="onChangeTime" class="ml-3 mb-3" format="YYYY-MM-DD HH:mm:ss" show-time />
<a-button @click="handleTableChange" class="ml-3 mb-3" type="primary">搜索</a-button>
<div class="flex-1"></div>
<a-button @click="showModal" class="editable-add-btn mb-3" type="primary">增加</a-button>
<!-- 添加 -->
<activity-add :visible="visible" @closeModal="closeModal" />
</div>
</template>
<script>
import ActivityAdd from 'components/Activity/ActivityAdd.vue';
// import { selLikeTeam } from 'config/api';
export default {
name: 'ActivitySearch',
components: {
ActivityAdd,
},
data() {
return {
visible: false,
titleKey: '',
items: ['路演', '讲座', '沙龙'],
activityType: [],
checkedValues: [],
publishPlatform: '', //
startTime: '',
endTime: '',
};
},
methods: {
//
getPlatform(value) {
console.log('value: ', value.target.value);
this.publishPlatform = value.target.value;
},
//
onChangeTime(dates, dateStrings) {
this.startTime = dateStrings[0];
this.endTime = dateStrings[1];
},
showModal() {
this.visible = true;
},
closeModal() {
this.visible = false;
},
onChange(checkedValues) {
this.checkedValues = checkedValues;
},
async handleTableChange() {
const { activityType, titleKey, checkedValues, publishPlatform, startTime, endTime } = this;
for (let i = 0; i < checkedValues.length; i++) {
const item = checkedValues[i];
const currentIndex = this.items.indexOf(item);
const a = this.items.findIndex(a => a === item);
const index = this.activityType.findIndex(c => c === a.label);
if (index === -1) {
this.activityType.push(currentIndex);
}
}
//
const condition = {
activityType,
titleKey,
publishPlatform,
startTime,
endTime,
};
await this.$emit('getSelectTeam', condition);
this.activityType = [];
},
},
};
</script>
<style scoped lang="stylus"></style>

239
src/components/Banner/BannerAdd.vue

@ -0,0 +1,239 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 添加 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="添加轮播图"
v-model="visible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 跳转类型 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="跳转类型"
>
<a-select
@change="getUse($event, 'jumpType')"
class="ml-3"
default-value="正常"
style="width: 150px"
>
<a-select-option :key="item" :value="index" v-for="(item, index) in enable">{{ item }}</a-select-option>
</a-select>
</a-form-item>
<!-- 跳转路径 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="图片跳转路径"
>
<a-input class="ml-3" placeholder="图片跳转路径" />
</a-form-item>
<!-- 状态 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="状态"
>
<a-select
@change="getUse($event, 'recStatus')"
class="ml-3"
default-value="启用"
style="width: 150px"
>
<a-select-option :key="item" :value="index" v-for="(item, index) in enable">{{ item }}</a-select-option>
</a-select>
</a-form-item>
<!-- 页面显示位置 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="页面显示位置"
>
<a-select
@change="getUse($event, 'showPage')"
class="ml-3"
default-value="首页"
style="width: 100%"
>
<a-select-option
:key="item.page"
:value="item.page"
v-for="item in enable2"
>{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<!-- 图片 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="图片"
>
<a-upload
:action="upload"
:before-upload="beforeUpload"
@change="handleChange"
class="ml-3"
list-type="picture"
name="files"
>
<a-button v-show="fileList.length - 0 === 0">
<a-icon type="upload" />选择图片
</a-button>
</a-upload>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { upload, addCarousel } from 'config/api';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'BannerAdd',
props: { visible: { type: Boolean, default: false } },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'r-d-add' }),
enable: ['启用', '禁用'],
enable1: ['不跳转', 'H5'],
enable2: [
{
name: '首页',
page: 0,
},
{
name: '关于我们-公司介绍',
page: 11,
},
{
name: '关于我们-组织机构',
page: 12,
},
{
name: '创新平台-创新资源平台',
page: 32,
},
{
name: '创新平台-科技创新服务',
page: 33,
},
{
name: ':孵化平台-众创空间',
page: 41,
},
{
name: '孵化平台-公共实验室',
page: 42,
},
{
name: '孵化平台-中试基地',
page: 43,
},
{
name: '孵化平台-创业导师',
page: 44,
},
{
name: '孵化平台-孵化场所',
page: 45,
},
{
name: '孵化平台-创业服务',
page: 46,
},
{
name: '孵化平台-众创空间-虚拟众创空间',
page: 48,
},
{
name: '孵化平台-众创空间-实体众创空间',
page: 49,
},
{
name: '产业平台-产业服务',
page: 52,
},
],
upload: upload,
paramD: {
jumpType: 0,
jumpUrl: '',
param: '',
url: '',
recStatus: 0,
showPage: 0,
},
fileList: [],
//
beforeUpload: file => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('仅支持 JPG/PNG 格式的图片!');
}
return isJpgOrPng;
},
};
},
methods: {
//
getUse(value, str) {
this.paramD[str] = value;
console.log(this.paramD[str]);
},
handleChange(info) {
// this.fileList = fileList;
console.log(info);
if (info.file.status === 'done') {
this.fileList.push(info.file.response.data[0].visitUrl);
} else if (info.file.status === 'removed') {
this.fileList = info.fileList;
}
},
//
handleSubmit(e) {
e.preventDefault();
this.paramD.url = this.fileList[0];
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const params = { param: this.paramD };
const res = await addCarousel(params);
const { data, msg, code } = res.data;
this.$emit('closeModal');
this.$emit('handleTableChange');
if (code === 200) {
this.$message.success('添加成功');
// TODO:
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '添加失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

183
src/components/Banner/BannerDate.vue

@ -0,0 +1,183 @@
<template>
<div class="main flex-1">
<div style="width: 100%" v-if="lists && lists.list">
<a-table
:columns="columns"
:data-source="lists.list"
:loading="loading"
:row-key="record => record.id"
:pagination="pagination"
@change="handleTableChange"
bordered
class="white"
:scroll="{ y: height }"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<template slot="url" slot-scope="text, record">
<img :src="record.url" style="width: 300px; height: 80px" alt="" />
</template>
<template slot="jumpType" slot-scope="text, record">
<span v-if="record.jumpType - 0 === 0">不跳转</span>
<span v-if="record.jumpType - 0 === 1">H5</span>
</template>
<template slot="jumpUrl" slot-scope="text, record">
<span v-if="record.jumpUrl">{{ jumpUrl }}</span>
<span v-else></span>
</template>
<template slot="edit" slot-scope="text, record">
<a-icon @click="showEditModal(record)" class="pointer" theme="twoTone" type="edit" />
<a-popconfirm @confirm="() => onDelete(record.id)" title="确定要删除这一条?" v-if="lists.list">
<a-icon class="ml-4 pointer" theme="twoTone" two-tone-color="#ff0000" type="delete" />
</a-popconfirm>
<a-switch checked-children="启用" class="ml-4" default-checked un-checked-children="禁用" />
</template>
</a-table>
</div>
<a-empty v-else />
<!-- 编辑 -->
<banner-edit :edit-item="editItem" :edit-visible="editVisible" @editSearch="editSearch" @closeModal="closeModal" />
</div>
</template>
<script>
import BannerEdit from 'components/Banner/BannerEdit.vue';
import { deleteCarousel } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
scopedSlots: { customRender: 'id' },
},
{
title: '图片',
align: 'center',
dataIndex: 'url',
key: 'url',
width: 350,
scopedSlots: { customRender: 'url' },
},
{
title: '显示位置',
align: 'center',
dataIndex: 'showPage',
key: 'showPage',
scopedSlots: { customRender: 'showPage' },
},
{
title: '跳转类型',
align: 'center',
dataIndex: 'jumpType',
key: 'jumpType',
scopedSlots: { customRender: 'jumpType' },
},
{
title: '跳转路径',
align: 'center',
dataIndex: 'jumpUrl',
key: 'jumpUrl',
scopedSlots: { customRender: 'jumpUrl' },
},
{
title: '图片参数',
align: 'center',
dataIndex: 'param',
key: 'param',
scopedSlots: { customRender: 'param' },
},
{
title: '创建时间',
align: 'center',
dataIndex: 'updatedAt',
key: 'updatedAt',
scopedSlots: { customRender: 'updatedAt' },
},
{
title: '编辑',
align: 'center',
dataIndex: 'edit',
key: 'edit',
width: 200,
scopedSlots: { customRender: 'edit' },
},
];
export default {
name: 'BannerDate',
components: { BannerEdit },
props: {
lists: {
type: Object,
default: () => {},
},
pagination: {
type: Object,
default: () => {},
},
},
data() {
return {
columns,
loading: false,
editingKey: '',
height: '',
editVisible: false,
editItem: null, //
};
},
mounted() {
let th = 200;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
showEditModal(record) {
console.log('record: ', record);
this.editItem = record;
this.editVisible = true;
},
closeModal() {
this.editVisible = false;
},
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('getListData', condition);
},
editSearch() {
this.$emit('getListData');
},
//
async onDelete(id) {
try {
const params = { param: { id } };
const res = await deleteCarousel(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('删除成功');
this.$emit('getListData');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '删除失败');
}
},
},
};
</script>
<style scoped lang="stylus"></style>

260
src/components/Banner/BannerEdit.vue

@ -0,0 +1,260 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 编辑 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="修改轮播图"
v-model="editVisible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit" v-if="editItem">
<!-- 跳转类型 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="跳转类型">
<a-select
:value="jumpType"
@change="getUse($event, 'jumpType')"
class="ml-3"
placeholder="请选择想要修改的跳转类型"
style="width: 200px"
>
<a-select-option :key="item" :value="index" v-for="(item, index) in enable1">{{ item }}</a-select-option>
</a-select>
</a-form-item>
<!-- 跳转路径 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="图片跳转路径"
v-if="editData.jumpType === 1"
>
<a-input class="ml-3" placeholder="图片跳转路径" v-model="editData.jumpUrl" />
</a-form-item>
<!-- 状态 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="状态">
<a-select
:value="recStatus"
@change="getUse($event, 'recStatus')"
class="ml-3"
placeholder="请选择想要修改的状态"
style="width: 200px"
>
<a-select-option :key="item" :value="index" v-for="(item, index) in enable">{{ item }}</a-select-option>
</a-select>
</a-form-item>
<!-- 页面显示位置 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="页面显示位置">
<a-select
:value="showPage"
@change="getUse($event, 'showPage')"
class="ml-3"
placeholder="请选择想要修改的页面显示位置"
style="width: 100%"
>
<a-select-option :key="item.page" :value="item.page" v-for="item in enable2">{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<!-- 图片 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="图片">
<a-upload :action="upload" :before-upload="beforeUpload" @change="handleChange" class="ml-3" list-type="picture" name="files">
<a-button v-show="fileList.length - 0 === 0"> <a-icon type="upload" />更换图片 </a-button>
</a-upload>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { upload, updateCarousel } from 'config/api';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'BannerEdit',
props: { editVisible: { type: Boolean, default: false }, editItem: { type: Object, default: () => {} } },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'r-d-add' }),
enable: ['启用', '禁用'],
enable1: ['不跳转', 'H5'],
enable2: [
{
name: '首页',
page: 0,
},
{
name: '关于我们-公司介绍',
page: 11,
},
{
name: '关于我们-组织机构',
page: 12,
},
{
name: '创新平台-创新资源平台',
page: 32,
},
{
name: '创新平台-科技创新服务',
page: 33,
},
{
name: ':孵化平台-众创空间',
page: 41,
},
{
name: '孵化平台-公共实验室',
page: 42,
},
{
name: '孵化平台-中试基地',
page: 43,
},
{
name: '孵化平台-创业导师',
page: 44,
},
{
name: '孵化平台-孵化场所',
page: 45,
},
{
name: '孵化平台-创业服务',
page: 46,
},
{
name: '孵化平台-众创空间-虚拟众创空间',
page: 48,
},
{
name: '孵化平台-众创空间-实体众创空间',
page: 49,
},
{
name: '产业平台-产业服务',
page: 52,
},
],
upload: upload,
fileList: [],
//
beforeUpload: file => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('仅支持 JPG/PNG 格式的图片!');
}
return isJpgOrPng;
},
editData: {
jumpType: '',
jumpUrl: '',
recStatus: '',
showPage: '',
url: '',
},
jumpType: '',
recStatus: '',
showPage: '',
};
},
watch: {
editItem(val) {
this.editData.jumpType = this.editItem.jumpType;
this.editData.jumpUrl = this.editItem.jumpUrl;
this.editData.recStatus = this.editItem.recStatus;
this.editData.showPage = this.editItem.showPage;
this.editData.url = this.editItem.url;
this.jumpType = this.enable1[this.editItem.jumpType];
this.recStatus = this.enable[this.editItem.recStatus];
for (let i = 0; i < this.enable2.length; i++) {
if (this.enable.showPage === this.enable2[i].page) {
this.showPage = this.enable2[i].name;
}
}
},
},
methods: {
//
getUse(e, str) {
this.editData[str] = e;
if (str === 'jumpType' && e === 0) {
this.editData.jumpUrl = '';
for (let i = 0; i < this.enable2.length; i++) {
if (this.enable.showPage === this.enable2[i].page) {
this.showPage = this.enable2[i].name;
}
}
}
if (str === 'jumpType') {
this.jumpType = this.enable1[e];
}
if (str === 'recStatus') {
this.recStatus = this.enable[e];
}
},
//
handleChange(info) {
// this.fileList = fileList;
if (info.file.status === 'done') {
this.fileList.push(info.file.response.data[0].visitUrl);
} else if (info.file.status === 'removed') {
this.fileList = info.fileList;
}
},
//
handleSubmit(e) {
if (this.fileList.length) {
this.editData.url = this.fileList[0];
}
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const params = {
param: {
id: this.editItem.id,
jumpType: this.editData.jumpType,
jumpUrl: this.editData.jumpUrl,
recStatus: this.editData.recStatus,
showPage: this.editData.showPage,
url: this.editData.url,
},
};
const res = await updateCarousel(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$emit('closeModal');
this.$emit('editSearch');
this.$message.success('修改成功');
this.jumpType = '';
this.recStatus = '';
this.showPage = '';
// TODO:
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '修改失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

148
src/components/Banner/BannerSearch.vue

@ -0,0 +1,148 @@
<template>
<div class="d-flex flex-wrap pb-3">
<div>
<!-- 启用 -->
<a-select
@change="getUse($event, 'recStatus')"
allow-clear
class="ml-3"
default-value="启用"
style="width: 150px"
>
<a-select-option :key="item" :value="index" v-for="(item, index) in enable">{{ item }}</a-select-option>
</a-select>
<!-- 跳转类型 -->
<a-select
@change="getUse($event, 'jumpType')"
allow-clear
class="ml-3"
default-value="不跳转"
style="width: 150px"
>
<a-select-option :key="item" :value="index" v-for="(item, index) in enable1">{{ item }}</a-select-option>
</a-select>
<!-- 页面显示位置 -->
<a-select
@change="getUse($event, 'showPage')"
allow-clear
class="ml-3"
placeholder="查询全部"
style="width: 250px"
>
<a-select-option :key="item.name" :value="item.page" v-for="item in enable2">{{ item.name }}</a-select-option>
</a-select>
<a-button @click="handleTableChange" class="mx-2" type="primary">搜索</a-button>
</div>
<div class="flex-1"></div>
<a-button @click="showModal" class="editable-add-btn" type="primary">增加</a-button>
<!-- 添加 -->
<banner-add :visible="visible" @closeModal="closeModal" @handleTableChange="handleTableChange" />
</div>
</template>
<script>
import BannerAdd from 'components/Banner/BannerAdd.vue';
// import { selLikeTeam } from 'config/api';
export default {
name: 'BannerSearch',
components: { BannerAdd },
data() {
return {
visible: false,
enable: ['启用', '禁用'],
enable1: ['不跳转', 'H5'],
enable2: [
{
name: '首页',
page: 0,
},
{
name: '关于我们-公司介绍',
page: 11,
},
{
name: '关于我们-组织机构',
page: 12,
},
{
name: '创新平台-创新资源平台',
page: 32,
},
{
name: '创新平台-科技创新服务',
page: 33,
},
{
name: ':孵化平台-众创空间',
page: 41,
},
{
name: '孵化平台-公共实验室',
page: 42,
},
{
name: '孵化平台-中试基地',
page: 43,
},
{
name: '孵化平台-创业导师',
page: 44,
},
{
name: '孵化平台-孵化场所',
page: 45,
},
{
name: '孵化平台-创业服务',
page: 46,
},
{
name: '孵化平台-众创空间-虚拟众创空间',
page: 48,
},
{
name: '孵化平台-众创空间-实体众创空间',
page: 49,
},
{
name: '产业平台-产业服务',
page: 52,
},
],
paramData: {
jumpType: 0, //
recStatus: 0, //
showPage: '', //
},
};
},
methods: {
showModal() {
this.visible = true;
},
closeModal() {
this.visible = false;
},
//
getUse(value, str) {
this.paramData[str] = value;
console.log(this.paramData[str]);
},
handleTableChange() {
this.$emit('getListData', this.paramData);
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus"></style>

78
src/components/BtnCom/BtnCon.vue

@ -0,0 +1,78 @@
<template>
<div class="btn-box pa-3">
<div class="font-bold-24">运维</div>
<div @click="jump('/page-manage')" class="btn">内容管理</div>
<div @click="jump('/industry-info')" class="btn">行业资讯</div>
<div @click="jump('/user-manage')" class="btn">用户管理</div>
<div @click="jump('/banner-manage')" class="btn">轮播图管理</div>
<!-- <div @click="jump('/communication-community')" class="btn">交流社区</div> -->
<div @click="jump('/event-announcement')" class="btn">活动公告</div>
<div @click="jump('/innovation-policy')" class="btn">创新政策</div>
<div @click="jump('/')" class="btn">创新挑战</div>
<div @click="jump('/College')" class="btn">创业学院</div>
<!-- <div @click="jump('/talent-recruitment')" class="btn">人才招聘</div> -->
<div @click="jump('/cooperative-partner')" class="btn">合作伙伴</div>
<div @click="jump('/about-us-derivative-enterprise')" class="btn">衍生企业</div>
<div class="font-bold-24">创新研究院</div>
<!-- <div @click="jump('/cooperation-intention')" class="btn">合作意向</div> -->
<!-- <div @click="jump('/demand-filling')" class="btn">需求填报</div> -->
<div @click="jump('/innovative-service')" class="btn">服务</div>
<div @click="jump('/')" class="btn">合作伙伴</div>
<div @click="jump('/')" class="btn">衍生企业</div>
<!-- <div @click="jump('/innovative-lab')" class="btn">实验室</div> -->
<!-- <div @click="jump('/category-manage')" class="btn">分类管理</div> -->
<!-- <div @click="jump('/innovative-equipment')" class="btn">设备</div> -->
<!-- <div @click="jump('/innovative-achievements')" class="btn">成果</div> -->
<div class="font-bold-24">孵化平台</div>
<div @click="jump('/entity-application')" class="btn">入驻实体申请</div>
<div @click="jump('/virtual-application')" class="btn">入驻数智创时代 专业孵化器申请</div>
<div @click="jump('/virtual-application')" class="btn">入驻线上孵化器</div>
<div @click="jump('/incubation-services')" class="btn">服务</div>
<!-- <div @click="jump('/hatching-demand-filling')" class="btn">需求填报</div> -->
<div @click="jump('/')" class="btn">创业导师</div>
<div @click="jump('/hatch-cooperative-partner')" class="btn">合作伙伴</div>
<!-- <div class="font-bold-24">产业部</div>
<div @click="jump('/industrial-services')" class="btn">服务</div>
<div @click="jump('/industry-derivative-enterprise')" class="btn">衍生企业</div>
<div @click="jump('/industry-demand-report')" class="btn">需求填报</div> -->
</div>
</template>
<script>
export default {
name: 'BtnCom',
data() {
return {
str: '',
showVideo: false,
};
},
methods: {
jump(url) {
this.$router.push(url);
},
},
};
</script>
<style lang="stylus" scoped>
.btn-box {
width: 10%;
border-right: 1px solid #ccc;
overflow: auto;
.btn {
background: #1890ff;
border: 1px solid #1890ff;
padding: 4px;
border-radius: 5px;
color: #fff;
cursor: pointer;
margin-bottom: 8px;
}
}
</style>

221
src/components/CVideo/VideoAdd.vue

@ -0,0 +1,221 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 添加 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="添加课程"
v-model="visible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 课程 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="课程"
>
<a-input
placeholder="课程"
v-decorator="[
'course',
{
rules: [
{ required: true, message: '课程不能为空' },
{ whitespace: true, message: '课程不能为空' },
{ max: 140, massage: '课程最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 视频名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="视频名称"
>
<a-input
placeholder="视频名称"
v-decorator="[
'videoName',
{
rules: [
{ required: true, message: '视频名称不能为空' },
{ whitespace: true, message: '视频名称不能为空' },
{ max: 140, massage: '视频名称最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 封面 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="封面"
>
<a-upload
:before-upload="beforeUpload"
:show-upload-list="false"
@change="handleChange"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
class="avatar-uploader"
list-type="picture-card"
name="avatar"
>
<img :src="imageUrl" alt="avatar" v-if="imageUrl" />
<div v-else>
<a-icon :type="loading ? 'loading' : 'plus'" />
<div class="ant-upload-text">Upload</div>
</div>
</a-upload>
</a-form-item>
<!-- 第几集 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="第几集"
>
<a-input
placeholder="第几集"
v-decorator="[
'setNumber',
{
rules: [
{ required: true, message: '第几集不能为空' },
{ whitespace: true, message: '第几集不能为空' },
{ max: 140, massage: '第几集最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 主讲人 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="主讲人"
>
<a-input
placeholder="主讲人"
v-decorator="[
'speaker',
{
rules: [
{ required: true, message: '主讲人不能为空' },
{ whitespace: true, message: '主讲人不能为空' },
{ max: 140, massage: '主讲人最多140个字符' },
],
},
]"
/>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
function getBase64(img, callback) {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(img);
}
export default {
name: 'VideoAdd',
props: { visible: { type: Boolean, default: false } },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'video-add' }),
loading: false,
imageUrl: '',
};
},
methods: {
//
handleChange(info) {
if (info.file.status === 'uploading') {
this.loading = true;
return;
}
if (info.file.status === 'done') {
// Get this url from response in real world.
getBase64(info.file.originFileObj, imageUrl => {
this.imageUrl = imageUrl;
this.loading = false;
});
}
},
beforeUpload(file) {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('You can only upload JPG file!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
this.$message.error('Image must smaller than 2MB!');
}
return isJpgOrPng && isLt2M;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
console.log('values: ', values);
// const params = this.generateParams(values);
// const res = await createTask(params);
// const { data, msg, code } = res.data;
// //
// this.clearCreateTask();
// this.$emit('closeDialog');
// if (code === 200) {
// this.handleCreateSuccess(params.executorId);
// } else {
// throw msg;
// }
} catch (error) {
this.$message.error(error || '添加研发团队失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus">
.avatar-uploader > .ant-upload {
width: 128px;
height: 128px;
}
.ant-upload-select-picture-card i {
font-size: 32px;
color: #999;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
</style>

206
src/components/CVideo/VideoDate.vue

@ -0,0 +1,206 @@
<template>
<div class="main flex-1">
<div style="width:100%" v-if="lists && lists.length > 0">
<a-table
:columns="columns"
:data-source="lists"
:loading="loading"
:row-key="record => record.id"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<!-- 封面 -->
<template slot="cover" slot-scope="text, record">
<img :src="record.cover" class="img" />
<a-modal
:imgVisible="imgVisible"
:maskClosable="false"
@cancel="imgVisible = false"
destroyOnClose
footer
title="身份证明"
>
<img :src="record.idCardPromise" @click="imgVisible = true" style="width: 100%;" />
</a-modal>
</template>
<template slot="auditStatus" slot-scope="text, record">
<a-tag :color="record.auditStatus === '通过' ? 'green' : 'red'">{{ record.auditStatus }}</a-tag>
</template>
<template slot="edit" slot-scope="text, record">
<a-icon @click="showEditModal" class="pointer" theme="twoTone" type="edit" />
<a-popconfirm @confirm="() => onDelete(record.id)" title="确定要删除这一条?" v-if="lists.length">
<a-icon class="ml-4 pointer" theme="twoTone" two-tone-color="#ff0000" type="delete" />
</a-popconfirm>
<a-switch checked-children="上架" class="ml-4" default-checked un-checked-children="下架" />
</template>
<template slot="examine" slot-scope="text, record">
<a-button size="small" type="primary" v-if="record.auditStatus != '通过'">通过</a-button>
<a-button size="small" type="danger" v-else>不通过</a-button>
</template>
</a-table>
</div>
<a-empty v-else />
<!-- 编辑 -->
<video-edit :editVisible="editVisible" @closeModal="closeModal" />
</div>
</template>
<script>
import VideoEdit from 'components/CVideo/VideoEdit.vue';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: '7%',
scopedSlots: { customRender: 'id' },
},
{
title: '课程',
align: 'center',
dataIndex: 'course',
key: 'course',
},
{
title: '视频名称',
align: 'center',
dataIndex: 'videoName',
key: 'videoName',
},
{
title: '封面',
align: 'center',
dataIndex: 'cover',
key: 'cover',
scopedSlots: { customRender: 'cover' },
},
{
title: '第几集',
align: 'center',
dataIndex: 'setNumber',
key: 'setNumber',
scopedSlots: { customRender: 'setNumber' },
},
{
title: '主讲人',
align: 'center',
dataIndex: 'speaker',
key: 'speaker',
scopedSlots: { customRender: 'speaker' },
},
{
title: '审核状态',
align: 'center',
dataIndex: 'auditStatus',
key: 'auditStatus',
scopedSlots: { customRender: 'auditStatus' },
},
{
title: '编辑',
align: 'center',
dataIndex: 'edit',
key: 'edit',
width: 200,
scopedSlots: { customRender: 'edit' },
},
{
title: '审核',
align: 'center',
dataIndex: 'examine',
key: 'examine',
scopedSlots: { customRender: 'examine' },
},
];
const lists = [
{
id: '001',
course: '传控科技',
videoName: '传控科技宣传片',
cover: 'assets/logo.png',
setNumber: 5,
speaker: '张三',
auditStatus: '通过',
},
{
id: '002',
course: '中绿环保',
videoName: '传控科技宣传片',
cover: 'assets/logo.png',
setNumber: 6,
speaker: '张三',
auditStatus: '未通过',
},
];
export default {
name: 'VideoDate',
components: {
VideoEdit,
},
data() {
this.cacheData = lists.map(item => ({ ...item }));
return {
columns,
lists,
loading: false,
height: '',
editVisible: false,
imgVisible: false,
};
},
mounted() {
this.height = document.getElementsByClassName('main')[0].offsetHeight - 150;
},
methods: {
showEditModal() {
this.editVisible = true;
},
closeModal() {
this.editVisible = false;
},
//
async onDelete(teamId) {
try {
const params = { param: { teamId } };
// const res = await delTeam(params);
// const { data, msg, code } = res.data;
// if (code === 200) {
// this.$message.success('');
// const arr = [...this.lists];
// this.lists = arr.filter(item => item.id !== teamId);
// // TODO:
// } else {
// throw msg;
// }
} catch (error) {
this.$message.error(error || '删除失败');
}
},
},
};
</script>
<style lang="stylus" scoped>
.main .img {
height: 65px;
}
.main .big_img {
width: 200px;
}
</style>

221
src/components/CVideo/VideoEdit.vue

@ -0,0 +1,221 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 编辑 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="修改课程"
v-model="editVisible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 课程 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="课程"
>
<a-input
placeholder="课程"
v-decorator="[
'course',
{
rules: [
{ required: true, message: '课程不能为空' },
{ whitespace: true, message: '课程不能为空' },
{ max: 140, massage: '课程最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 视频名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="视频名称"
>
<a-input
placeholder="视频名称"
v-decorator="[
'videoName',
{
rules: [
{ required: true, message: '视频名称不能为空' },
{ whitespace: true, message: '视频名称不能为空' },
{ max: 140, massage: '视频名称最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 封面 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="封面"
>
<a-upload
:before-upload="beforeUpload"
:show-upload-list="false"
@change="handleChange"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
class="avatar-uploader"
list-type="picture-card"
name="avatar"
>
<img :src="imageUrl" alt="avatar" v-if="imageUrl" />
<div v-else>
<a-icon :type="loading ? 'loading' : 'plus'" />
<div class="ant-upload-text">Upload</div>
</div>
</a-upload>
</a-form-item>
<!-- 第几集 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="第几集"
>
<a-input
placeholder="第几集"
v-decorator="[
'setNumber',
{
rules: [
{ required: true, message: '第几集不能为空' },
{ whitespace: true, message: '第几集不能为空' },
{ max: 140, massage: '第几集最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 主讲人 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="主讲人"
>
<a-input
placeholder="主讲人"
v-decorator="[
'speaker',
{
rules: [
{ required: true, message: '主讲人不能为空' },
{ whitespace: true, message: '主讲人不能为空' },
{ max: 140, massage: '主讲人最多140个字符' },
],
},
]"
/>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
function getBase64(img, callback) {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(img);
}
export default {
name: 'VideoEdit',
props: { editVisible: { type: Boolean, default: false } },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'video-edit' }),
loading: false,
imageUrl: '',
};
},
methods: {
//
handleChange(info) {
if (info.file.status === 'uploading') {
this.loading = true;
return;
}
if (info.file.status === 'done') {
// Get this url from response in real world.
getBase64(info.file.originFileObj, imageUrl => {
this.imageUrl = imageUrl;
this.loading = false;
});
}
},
beforeUpload(file) {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('You can only upload JPG file!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
this.$message.error('Image must smaller than 2MB!');
}
return isJpgOrPng && isLt2M;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
console.log('values: ', values);
// const params = this.generateParams(values);
// const res = await createTask(params);
// const { data, msg, code } = res.data;
// //
// this.clearCreateTask();
// this.$emit('closeDialog');
// if (code === 200) {
// this.handleCreateSuccess(params.executorId);
// } else {
// throw msg;
// }
} catch (error) {
this.$message.error(error || '添加研发团队失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus">
.avatar-uploader > .ant-upload {
width: 128px;
height: 128px;
}
.ant-upload-select-picture-card i {
font-size: 32px;
color: #999;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
</style>

54
src/components/CVideo/VideoSearch.vue

@ -0,0 +1,54 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 课程 -->
<div>
<a-input @change="handleChangeCourse" placeholder="课程" style="width: 150px" v-model="course" />
<a-button @click="handleTableChange" class="ml-3" type="primary">搜索</a-button>
</div>
<div class="flex-1"></div>
<a-button @click="showModal" class="editable-add-btn" type="primary">增加</a-button>
<!-- 添加 -->
<video-add :visible="visible" @closeModal="closeModal" />
</div>
</template>
<script>
import VideoAdd from 'components/CVideo/VideoAdd.vue';
export default {
name: 'VideoSearch',
components: {
VideoAdd,
},
data() {
return {
visible: false,
course: '',
};
},
methods: {
showModal() {
this.visible = true;
},
closeModal() {
this.visible = false;
},
handleChangeCourse(value) {
console.log('value: ', value);
this.course = value;
},
handleTableChange() {
console.log('搜索');
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus"></style>

233
src/components/Challenge/ChallengeAdd.vue

@ -0,0 +1,233 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 添加 -->
<a-modal
:mask-closable="false"
@cancel="$emit('closeModal')"
destroy-on-close
footer
title="添加服务"
v-model="visible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 服务名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务名称"
>
<a-input
@change="changeIpt($event, 'serviceName')"
class="ml-3"
placeholder="服务名称"
v-decorator="[
'serviceName',
{
rules: [
{ required: true, message: '服务名称不能为空' },
{ whitespace: true, message: '服务名称不能为空' },
{ max: 140, massage: '服务名称最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 服务简介 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务简介"
>
<a-textarea
@change="changeIpt($event, 'intro')"
class="ml-3"
placeholder="服务简介"
v-decorator="[
'intro',
{
rules: [
{ required: true, message: '服务简介不能为空' },
{ whitespace: true, message: '服务简介不能为空' },
{ max: 140, massage: '服务简介最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 服务内容 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务内容"
>
<a-textarea
@change="changeIpt($event, 'content')"
class="ml-3"
placeholder="服务内容"
v-decorator="[
'content',
{
rules: [
{ required: true, message: '服务内容不能为空' },
{ whitespace: true, message: '服务内容不能为空' },
{ max: 140, massage: '服务内容最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 服务排序 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务排序"
>
<a-input-number class="ml-3" v-model="orders" />
</a-form-item>
<!-- 图片 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="图片"
>
<a-upload
:action="upload"
:before-upload="beforeUpload"
@change="handleChange"
class="ml-3"
list-type="picture"
name="files"
>
<a-button v-show="fileList.length - 0 === 0">
<a-icon type="upload" />选择图片
</a-button>
</a-upload>
</a-form-item>
<!-- 服务状态 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务状态"
>
<a-select
@change="getUse($event, 'recStatus')"
class="ml-3"
default-value="正常"
style="width: 100%"
>
<a-select-option
:key="index"
:value="index"
v-for="(item, index) in recStatusList"
>{{ item }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { upload, saveService } from 'config/api';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'ChallengeAdd',
props: { visible: { type: Boolean, default: false } },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'r-d-member-add' }),
upload: upload,
fileList: [],
//
beforeUpload: file => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('仅支持 JPG/PNG 格式的图片!');
}
return isJpgOrPng;
},
recStatusList: ['正常', '禁用'],
serviceTypeList: ['创新平台', '孵化平台', '产业平台'],
serviceName: '',
content: '',
intro: '',
orders: '',
picId: '',
recStatus: 0,
serviceType: 0,
};
},
methods: {
//
handleChange(info) {
// this.fileList = fileList;
console.log(info);
if (info.file.status === 'done') {
this.fileList.push(info.file.response.data[0].id);
} else if (info.file.status === 'removed') {
this.fileList = info.fileList;
}
},
changeIpt(e, str) {
this[str] = e.target.value;
},
getUse(e, str) {
this[str] = e;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
if (this.fileList.length > 0) {
try {
this.picId = this.fileList[0];
const params = {
param: {
name: this.serviceName,
content: this.content,
intro: this.intro,
orders: this.orders,
picId: this.picId,
recStatus: this.recStatus,
serviceType: 2,
},
};
const res = await saveService(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$emit('handleTableChange');
this.$emit('closeModal');
this.$message.success('添加成功');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '添加失败');
}
} else {
this.$message.error('请上传图片');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

192
src/components/Challenge/ChallengeDate.vue

@ -0,0 +1,192 @@
<template>
<div class="main flex-1">
<div style="width: 100%" v-if="lists.list && lists.list.length > 0">
<a-table
:columns="columns"
:data-source="lists.list"
:loading="loading"
:row-key="record => record.id"
:pagination="pagination"
:scroll="{ y: height }"
@change="handleTableChange"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<template slot="picUrl" slot-scope="text, record">
<img :src="record.picUrl" width="50" height="50" />
</template>
<template slot="serviceType" slot-scope="text, record">
<span v-if="record.serviceType === 1">创新平台</span>
<span v-if="record.serviceType === 2">孵化平台</span>
<span v-if="record.serviceType === 3">产业平台</span>
</template>
<template slot="edit" slot-scope="text, record">
<a-icon @click="showEditModal(record)" class="pointer" theme="twoTone" type="edit" />
<a-popconfirm @confirm="() => onDelete(record.id)" title="确定要删除这一条?" v-if="lists.list.length">
<a-icon class="ml-4 pointer" theme="twoTone" two-tone-color="#ff0000" type="delete" />
</a-popconfirm>
</template>
<div class="d-flex flex-nowrap justify-space-between" slot="expandedRowRender" slot-scope="record" style="margin: 0">
{{ getselContent(record.id) }}
</div>
</a-table>
</div>
<a-empty v-else />
<!-- 编辑 -->
<challenge-edit :edit-visible="editVisible" :edit-data="editData" @getData="getData" :contents="contents" @closeModal="closeModal" />
</div>
</template>
<script>
import ChallengeEdit from 'components/Challenge/ChallengeEdit.vue';
import { deleteService, selContent } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: '7%',
scopedSlots: { customRender: 'id' },
},
{
title: '服务名称',
align: 'center',
dataIndex: 'name',
key: 'name',
},
{
title: '服务简介',
align: 'center',
dataIndex: 'intro',
key: 'intro',
},
{
title: '服务图片',
align: 'center',
dataIndex: 'picUrl',
key: 'picUrl',
scopedSlots: { customRender: 'picUrl' },
},
{
title: '服务类型',
align: 'center',
dataIndex: 'serviceType',
key: 'serviceType',
scopedSlots: { customRender: 'serviceType' },
},
{
title: '服务排序',
align: 'center',
dataIndex: 'orders',
key: 'orders',
scopedSlots: { customRender: 'orders' },
},
{
title: '编辑',
align: 'center',
dataIndex: 'edit',
key: 'edit',
scopedSlots: { customRender: 'edit' },
},
];
export default {
name: 'ChallengeDate',
components: {
ChallengeEdit,
},
// props: { lists: { type: Array, default: () => {} } },
props: { lists: { type: Object, default: () => {} }, pagination: { type: Object, default: () => {} } },
data() {
return {
columns,
loading: false,
editingKey: '',
height: '',
editVisible: false,
editData: null,
contents: '',
};
},
mounted() {
let th = 250;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
showEditModal(data) {
this.editData = data;
this.contents = this.getselContent(data.id);
this.editVisible = true;
},
closeModal() {
this.editVisible = false;
},
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('getInnovativeServiceSearch', condition);
},
getData() {
this.$emit('getInnovativeServiceSearch');
},
//
async onDelete(id) {
try {
const params = { param: { id } };
const res = await deleteService(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$emit('getInnovativeServiceSearch');
this.$message.success('删除成功');
// TODO:
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '删除失败');
}
},
//
getselContent(id) {
try {
const parmas = {
param: {
id: +id,
serviceType: 2,
},
};
const res = selContent(params);
const { code, msg, data } = res.data;
if (code === 200) {
// console.log(data);
return data.content;
} else {
return '暂无内容';
}
} catch (error) {
return '暂无内容';
}
},
},
};
</script>
<style scoped lang="stylus"></style>

195
src/components/Challenge/ChallengeEdit.vue

@ -0,0 +1,195 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 编辑 -->
<a-modal
:mask-closable="false"
@cancel="$emit('closeModal')"
destroy-on-close
footer
title="修改服务"
v-model="editVisible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 服务名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务名称"
>
<a-input class="ml-3" placeholder="服务名称" v-model="serviceName" />
</a-form-item>
<!-- 服务简介 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务简介"
>
<a-textarea class="ml-3" placeholder="服务简介" v-model="intro" />
</a-form-item>
<!-- 服务内容 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务内容"
>
<a-textarea class="ml-3" placeholder="服务内容" v-model="content" />
</a-form-item>
<!-- 服务排序 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务排序"
>
<a-input-number class="ml-3" v-model="orders" />
</a-form-item>
<!-- 图片 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="图片"
>
<a-upload
:action="upload"
:before-upload="beforeUpload"
@change="handleChange"
class="ml-3"
list-type="picture"
name="files"
>
<a-button v-show="fileList.length - 0 === 0">
<a-icon type="upload" />选择图片
</a-button>
</a-upload>
</a-form-item>
<!-- 服务状态 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务状态"
>
<a-select
@change="getUse($event, 'recStatus')"
class="ml-3"
default-value="正常"
style="width: 100%"
>
<a-select-option
:key="index"
:value="index"
v-for="(item, index) in recStatusList"
>{{ item }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { upload, updateService } from 'config/api';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'ChallengeEdit',
props: {
editVisible: { type: Boolean, default: false },
editData: { type: Object, default: () => {} },
contents: { type: String, default: '' },
},
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'r-d-member-add' }),
upload: upload,
fileList: [],
//
beforeUpload: file => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('仅支持 JPG/PNG 格式的图片!');
}
return isJpgOrPng;
},
recStatusList: ['正常', '禁用'],
serviceTypeList: ['创新平台', '孵化平台', '产业平台'],
serviceName: '',
content: '',
intro: '',
orders: '',
picId: '',
recStatus: 0,
serviceType: 0,
};
},
watch: {
editData(val) {
console.log(val);
},
},
methods: {
//
handleChange(info) {
// this.fileList = fileList;
console.log(info);
if (info.file.status === 'done') {
this.fileList.push(info.file.response.data[0].id);
} else if (info.file.status === 'removed') {
this.fileList = info.fileList;
}
},
changeIpt(e, str) {
this[str] = e.target.value;
},
getUse(e, str) {
this[str] = e;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const params = {
param: {
id: this.editData.id,
name: this.serviceName ? this.serviceName : this.editData.name,
content: this.content ? this.content : this.contents === '暂无内容' ? '' : this.contents,
intro: this.intro ? this.intro : this.editData.intro,
orders: this.orders ? this.orders : this.editData.orders,
picId: this.picId ? this.picId : this.editData.picId,
recStatus: this.recStatus,
serviceType: 2,
},
};
const res = await updateService(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$emit('getData');
this.$emit('closeModal');
this.$message.success('修改成功');
} else {
this.$message.error('修改失败');
}
} catch (error) {
this.$message.error(error);
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

74
src/components/Challenge/ChallengeSearch.vue

@ -0,0 +1,74 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 团队名称 -->
<div>
<a-input placeholder="服务名称" style="width: 150px" v-model="name" allow-clear />
<span class="ml-3"> 服务状态:</span>
<a-select @change="handleChangeSelect" class="ml-3" style="width: 150px" placeholder="状态" allow-clear>
<a-select-option :key="item" :value="index" v-for="(item, index) in statusList">{{ item }}</a-select-option>
</a-select>
<a-button @click="handleTableChange" class="mx-2" type="primary">搜索</a-button>
</div>
<div class="flex-1"></div>
<a-button type="primary" @click="showModal" class="editable-add-btn">增加</a-button>
<!-- 添加 -->
<challenge-add :visible="visible" @closeModal="closeModal" @handleTableChange="handleTableChange" />
</div>
</template>
<script>
import ChallengeAdd from 'components/Challenge/ChallengeAdd.vue';
export default {
name: 'ChallengeSearch',
components: {
ChallengeAdd,
},
data() {
return {
visible: false,
name: '',
serviceTypes: [
{ id: 1, value: '创新平台' },
{ id: 2, value: '孵化平台' },
{ id: 3, value: '产业平台' },
],
statusList: ['正常', '禁用'],
status111: '',
};
},
methods: {
showModal() {
this.visible = true;
},
closeModal() {
this.visible = false;
},
handleChangeSelect(e) {
// this[type] = value;
this.status111 = e;
},
handleChangeName(value) {
console.log('value: ', value);
this.name = value;
},
async handleTableChange() {
const { name, status111 } = this;
//
const condition = { name, status111 };
await this.$emit('getInnovativeServiceSearch', condition);
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus"></style>

106
src/components/Comment/CommentDate.vue

@ -0,0 +1,106 @@
<template>
<div class="main flex-1">
<div style="width:100%" v-if="lists && lists.length > 0">
<a-table
:columns="columns"
:data-source="lists"
:loading="loading"
:row-key="record => record.id"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<div slot="expandedRowRender" slot-scope="record" style="margin: 0">
<div>评论内容{{ record.reviewersContent }}</div>
<div>被评论人内容{{ record.commentContent }}</div>
</div>
</a-table>
</div>
<a-empty v-else />
</div>
</template>
<script>
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: '7%',
scopedSlots: { customRender: 'id' },
},
{
title: '评论人',
align: 'center',
dataIndex: 'reviewers',
key: 'reviewers',
},
{
title: '内容',
align: 'center',
dataIndex: 'reviewersContent',
key: 'reviewersContent',
ellipsis: true,
},
{
title: '评论时间',
align: 'center',
dataIndex: 'reviewersTime',
key: 'reviewersTime',
scopedSlots: { customRender: 'reviewersTime' },
},
{
title: '被评论人',
align: 'center',
dataIndex: 'commentedBy',
key: 'commentedBy',
},
];
const lists = [
{
id:'001',
reviewers:'张三',
reviewersContent:'张三评论内容',
reviewersTime: '2020/11/18 18:00',
commentedBy:'传控科技',
commentContent:'被评论人内容',
},
{
id:'002',
reviewers:'赵柳',
reviewersContent:'赵柳评论内容',
reviewersTime: '2020/11/18 18:00',
commentedBy:'中绿环保',
commentContent:'被评论人内容',
}
];
export default {
name: "CommentDate",
data() {
return {
columns,
lists,
loading: false,
editingKey: '',
height: '',
editVisible: false
}
},
mounted() {
this.height = document.getElementsByClassName('main')[0].offsetHeight - 150;
},
methods: {
},
};
</script>
<style scoped lang="stylus"></style>

38
src/components/Comment/CommentSearch.vue

@ -0,0 +1,38 @@
<template>
<div class="d-flex flex-wrap pb-3">
<div>
<!-- 评论人 -->
<a-input
@change="handleChangeReviewers"
placeholder="评论人"
style="width: 150px"
v-model="reviewers"
/>
<a-button @click="handleTableChange" class="mx-2" type="primary">搜索</a-button>
</div>
</div>
</template>
<script>
export default {
name: "CommentSearch",
data() {
return {
reviewers: '',
}
},
methods: {
handleChangeReviewers(value) {
console.log('value: ', value);
this.reviewers = value;
},
handleTableChange() {
console.log('搜索');
},
},
};
</script>
<style scoped lang="stylus"></style>

181
src/components/Community/CommentDate.vue

@ -0,0 +1,181 @@
<template>
<div class="main flex-1">
<a-spin :spinning="spinning">
<div style="width:100%" v-if="lists && lists.length > 0">
<a-table
:columns="columns"
:data-source="lists"
:loading="loading"
:pagination="pagination"
:row-key="record => record.id"
:scroll="{ y: height }"
@change="handleTableChange"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<!-- 用户头像 -->
<template slot="avatarUrl" slot-scope="text, record">
<a-avatar :size="50" :src="record.avatarUrl" v-if="record.avatarUrl" />
</template>
<!-- 审核状态 -->
<template slot="comStatus" slot-scope="text, record">
<a-tag
:color="record.comStatus === 0 ? 'green' : 'red'"
>{{ record.comStatus === 0 ? '正常' : '禁用' }}</a-tag>
</template>
<template slot="examine" slot-scope="text, record">
<a-button
@click="handleUpTopping({id:record.id,comStatus:0})"
size="small"
type="primary"
v-if="record.comStatus != 0"
>正常</a-button>
<a-button
@click="handleUpTopping({id:record.id,comStatus:1})"
size="small"
type="danger"
v-else
>禁用</a-button>
</template>
<div
class="d-flex flex-column"
slot="expandedRowRender"
slot-scope="record"
style="margin: 0"
>
<div>
<span class="font-bold-14">帖子内容</span>
<span v-dompurify-html="record.content" v-if="record.content"></span>
<span v-else>暂无内容</span>
</div>
</div>
</a-table>
</div>
<a-empty v-else />
</a-spin>
</div>
</template>
<script>
import { upComment } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: '7%',
scopedSlots: { customRender: 'id' },
},
{
title: '跟帖人',
align: 'center',
dataIndex: 'userName',
key: 'userName',
},
{
title: '用户头像',
align: 'center',
dataIndex: 'avatarUrl',
key: 'avatarUrl',
scopedSlots: { customRender: 'avatarUrl' },
},
{
title: '跟帖时间',
align: 'center',
dataIndex: 'creatTime',
key: 'creatTime',
},
{
title: '跟帖状态',
align: 'center',
dataIndex: 'comStatus',
key: 'comStatus',
scopedSlots: { customRender: 'comStatus' },
},
{
title: '审核',
align: 'center',
dataIndex: 'examine',
key: 'examine',
scopedSlots: { customRender: 'examine' },
},
];
export default {
name: 'CommunityDate',
props: { lists: { type: Array, default: () => [] }, pagination: { type: Object, default: () => {} } },
data() {
return {
columns,
loading: false,
height: '',
spinning: false,
};
},
mounted() {
let th = 250;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
//
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('getSelectTeam', condition);
},
// /
async handleUpTopping(options) {
try {
this.spinning = true;
const params = { param: { id: options.id } };
if (options) {
if (options.comStatus !== null) {
params.param.comStatus = +options.comStatus;
}
}
const res = await upComment(params);
const { data, msg, code } = res.data;
this.spinning = false;
if (code === 200) {
this.$message.success('修改成功');
this.$emit('getSelectTeam');
} else {
throw msg;
}
} catch (error) {
this.spinning = false;
this.$message.error(error || '修改失败');
}
},
},
};
</script>
<style lang="stylus" scoped>
.main .img {
height: 65px;
}
.main .big_img {
width: 200px;
}
</style>

53
src/components/Community/CommentSearch.vue

@ -0,0 +1,53 @@
<template>
<div class="d-flex flex-wrap pb-3">
<div>
<!-- 帖子状态 -->
<a-select
@change="handleChangeSelect('comStatus',$event)"
allow-clear
placeholder="跟帖状态"
style="width: 150px"
>
<a-select-option
:key="index"
:value="state.id"
v-for="(state, index) in items"
>{{ state.value }}</a-select-option>
</a-select>
<a-button @click="handleTableChange" class="ml-3" type="primary">搜索</a-button>
</div>
</div>
</template>
<script>
export default {
name: 'ForumSearch',
data() {
return {
items: [
{ id: 0, value: '正常' },
{ id: 1, value: '禁用' },
],
category: '',
};
},
methods: {
handleChangeSelect(type, value) {
this[type] = value;
},
//
async handleTableChange() {
const { comStatus } = this;
//
const condition = {
comStatus,
};
await this.$emit('getSelectTeam', condition);
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus"></style>

255
src/components/Community/CommunityDate.vue

@ -0,0 +1,255 @@
<template>
<div class="main flex-1">
<a-spin :spinning="spinning">
<div style="width:100%" v-if="lists && lists.length > 0">
<a-table
:columns="columns"
:data-source="lists"
:loading="loading"
:pagination="pagination"
:row-key="record => record.id"
:scroll="{ y: height }"
@change="handleTableChange"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<!-- 标题图片 -->
<template slot="visitLocation" slot-scope="text, record">
<img :src="record.visitLocation" class="img" />
</template>
<!-- 用户头像 -->
<template slot="avatarUrl" slot-scope="text, record">
<a-avatar :size="50" :src="record.avatarUrl" v-if="record.avatarUrl" />
</template>
<!-- 审核状态 -->
<template slot="comStatus" slot-scope="text, record">
<a-tag
:color="record.comStatus === 0 ? 'green' : 'red'"
>{{ record.comStatus === 0 ? '正常' : '禁用' }}</a-tag>
</template>
<!-- 置顶 -->
<template slot="topping" slot-scope="text, record">
<a-switch
:checked="text === 1"
@change="onChange($event,record.id)"
checked-children="是"
class="ml-4"
un-checked-children="否"
/>
</template>
<template slot="examine" slot-scope="text, record">
<a-button
@click="handleUpTopping({id:record.id,comStatus:0})"
size="small"
type="primary"
v-if="record.comStatus != 0"
>正常</a-button>
<a-button
@click="handleUpTopping({id:record.id,comStatus:1})"
size="small"
type="danger"
v-else
>禁用</a-button>
</template>
<template slot="edit" slot-scope="text, record">
<a-button @click="openComment(record.id)" size="small" type="primary">查看跟帖</a-button>
</template>
<div
class="d-flex flex-column"
slot="expandedRowRender"
slot-scope="record"
style="margin: 0"
>
<div>
<span class="font-bold-14">帖子内容</span>
<span v-dompurify-html="record.content" v-if="record.content"></span>
<span v-else>暂无内容</span>
</div>
</div>
</a-table>
</div>
<a-empty v-else />
</a-spin>
</div>
</template>
<script>
import { upTopping } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: '7%',
scopedSlots: { customRender: 'id' },
},
{
title: '标题',
align: 'center',
dataIndex: 'title',
key: 'title',
},
{
title: '标题图片',
align: 'center',
dataIndex: 'visitLocation',
key: 'visitLocation',
scopedSlots: { customRender: 'visitLocation' },
},
{
title: '发帖人',
align: 'center',
dataIndex: 'userName',
key: 'userName',
},
{
title: '用户头像',
align: 'center',
dataIndex: 'avatarUrl',
key: 'avatarUrl',
scopedSlots: { customRender: 'avatarUrl' },
},
{
title: '发布时间',
align: 'center',
dataIndex: 'createdTime',
key: 'createdTime',
},
{
title: '评论数',
align: 'center',
dataIndex: 'commentNum',
key: 'commentNum',
},
{
title: '置顶',
align: 'center',
dataIndex: 'topping',
key: 'topping',
scopedSlots: { customRender: 'topping' },
},
{
title: '审核状态',
align: 'center',
dataIndex: 'comStatus',
key: 'comStatus',
scopedSlots: { customRender: 'comStatus' },
},
{
title: '审核',
align: 'center',
dataIndex: 'examine',
key: 'examine',
scopedSlots: { customRender: 'examine' },
},
{
title: '跟帖',
align: 'center',
dataIndex: 'edit',
key: 'edit',
scopedSlots: { customRender: 'edit' },
},
];
export default {
name: 'CommunityDate',
props: { lists: { type: Array, default: () => [] }, pagination: { type: Object, default: () => {} } },
data() {
return {
columns,
loading: false,
height: '',
imgVisible: false,
spinning: false,
};
},
mounted() {
let th = 250;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
onChange(checked, id) {
const index = this.lists.findIndex(item => item.id === id);
if (this.lists[index].topping === 1) {
const options = { id, topping: 0 };
this.handleUpTopping(options);
} else {
const options = { id, topping: 1 };
this.handleUpTopping(options);
}
},
//
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('getSelectTeam', condition);
},
// /
async handleUpTopping(options) {
try {
this.spinning = true;
const params = { param: { id: options.id } };
if (options) {
if (options.comStatus !== null) {
params.param.comStatus = +options.comStatus;
}
if (options.topping !== null) {
params.param.topping = +options.topping;
}
}
const res = await upTopping(params);
const { data, msg, code } = res.data;
this.spinning = false;
if (code === 200) {
this.$message.success('修改成功');
this.$emit('getSelectTeam');
} else {
throw msg;
}
} catch (error) {
this.spinning = false;
this.$message.error(error || '修改失败');
}
},
//
openComment(id) {
const { query } = this.$route;
this.$router.push({ path: `/comment?id=${id}`, query });
},
},
};
</script>
<style lang="stylus" scoped>
.main .img {
height: 65px;
}
.main .big_img {
width: 200px;
}
</style>

76
src/components/Community/CommunitySearch.vue

@ -0,0 +1,76 @@
<template>
<div class="d-flex flex-wrap pb-3">
<div>
<!-- 标题 -->
<a-input class="ml-3" placeholder="标题" style="width: 150px" v-model="title" />
<!-- 发帖类别 -->
<a-select
@change="handleChangeSelect('category',$event)"
allow-clear
class="ml-3"
placeholder="发帖类别"
style="width: 150px"
>
<a-select-option :key="state.id" :value="state.id" v-for="state in status">{{ state.value }}</a-select-option>
</a-select>
<!-- 帖子状态 -->
<a-select
@change="handleChangeSelect('comStatus',$event)"
allow-clear
class="ml-3"
placeholder="帖子状态"
style="width: 150px"
>
<a-select-option
:key="index"
:value="state.id"
v-for="(state, index) in items"
>{{ state.value }}</a-select-option>
</a-select>
<a-button @click="handleTableChange" class="ml-3" type="primary">搜索</a-button>
</div>
</div>
</template>
<script>
export default {
name: 'ForumSearch',
data() {
return {
title: '',
items: [
{ id: 0, value: '正常' },
{ id: 1, value: '禁用' },
],
comStatus: '',
status: [
{ id: 0, value: '主题论坛' },
{ id: 1, value: '创新社区' },
{ id: 2, value: '孵化社区' },
{ id: 3, value: '产业社区' },
],
category: '',
};
},
methods: {
handleChangeSelect(type, value) {
this[type] = value;
},
//
async handleTableChange() {
const { title, comStatus, category } = this;
//
const condition = {
title,
comStatus,
category,
};
await this.$emit('getSelectTeam', condition);
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus"></style>

233
src/components/Course/CourseAdd.vue

@ -0,0 +1,233 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 添加 -->
<a-modal
:mask-closable="false"
@cancel="$emit('closeModal')"
destroy-on-close
footer
title="添加服务"
v-model="visible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 服务名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务名称"
>
<a-input
@change="changeIpt($event, 'serviceName')"
class="ml-3"
placeholder="服务名称"
v-decorator="[
'serviceName',
{
rules: [
{ required: true, message: '服务名称不能为空' },
{ whitespace: true, message: '服务名称不能为空' },
{ max: 140, massage: '服务名称最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 服务简介 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务简介"
>
<a-textarea
@change="changeIpt($event, 'intro')"
class="ml-3"
placeholder="服务简介"
v-decorator="[
'intro',
{
rules: [
{ required: true, message: '服务简介不能为空' },
{ whitespace: true, message: '服务简介不能为空' },
{ max: 140, massage: '服务简介最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 服务内容 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务内容"
>
<a-textarea
@change="changeIpt($event, 'content')"
class="ml-3"
placeholder="服务内容"
v-decorator="[
'content',
{
rules: [
{ required: true, message: '服务内容不能为空' },
{ whitespace: true, message: '服务内容不能为空' },
{ max: 140, massage: '服务内容最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 服务排序 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务排序"
>
<a-input-number class="ml-3" v-model="orders" />
</a-form-item>
<!-- 图片 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="图片"
>
<a-upload
:action="upload"
:before-upload="beforeUpload"
@change="handleChange"
class="ml-3"
list-type="picture"
name="files"
>
<a-button v-show="fileList.length - 0 === 0">
<a-icon type="upload" />选择图片
</a-button>
</a-upload>
</a-form-item>
<!-- 服务状态 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务状态"
>
<a-select
@change="getUse($event, 'recStatus')"
class="ml-3"
default-value="正常"
style="width: 100%"
>
<a-select-option
:key="index"
:value="index"
v-for="(item, index) in recStatusList"
>{{ item }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { upload, saveService } from 'config/api';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'CourseAdd',
props: { visible: { type: Boolean, default: false } },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'r-d-member-add' }),
upload: upload,
fileList: [],
//
beforeUpload: file => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('仅支持 JPG/PNG 格式的图片!');
}
return isJpgOrPng;
},
recStatusList: ['正常', '禁用'],
serviceTypeList: ['创新平台', '孵化平台', '产业平台'],
serviceName: '',
content: '',
intro: '',
orders: '',
picId: '',
recStatus: 0,
serviceType: 0,
};
},
methods: {
//
handleChange(info) {
// this.fileList = fileList;
console.log(info);
if (info.file.status === 'done') {
this.fileList.push(info.file.response.data[0].id);
} else if (info.file.status === 'removed') {
this.fileList = info.fileList;
}
},
changeIpt(e, str) {
this[str] = e.target.value;
},
getUse(e, str) {
this[str] = e;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
if (this.fileList.length > 0) {
try {
this.picId = this.fileList[0];
const params = {
param: {
name: this.serviceName,
content: this.content,
intro: this.intro,
orders: this.orders,
picId: this.picId,
recStatus: this.recStatus,
serviceType: 3,
},
};
const res = await saveService(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$emit('handleTableChange');
this.$emit('closeModal');
this.$message.success('添加成功');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '添加失败');
}
} else {
this.$message.error('请上传图片');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

205
src/components/Course/CourseDate.vue

@ -0,0 +1,205 @@
<template>
<div class="main flex-1">
<div style="width: 100%" v-if="lists.list && lists.list.length > 0">
<a-table
:columns="columns"
:data-source="lists.list"
:loading="loading"
:pagination="pagination"
:row-key="record => record.id"
:scroll="{ y: height }"
@change="handleTableChange"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<template slot="picUrl" slot-scope="text, record">
<img :src="record.picUrl" height="50" width="50" />
</template>
<template slot="serviceType" slot-scope="text, record">
<span v-if="record.serviceType === 1">创新平台</span>
<span v-if="record.serviceType === 2">孵化平台</span>
<span v-if="record.serviceType === 3">产业平台</span>
</template>
<template slot="edit" slot-scope="text, record">
<a-icon @click="showEditModal(record)" class="pointer" theme="twoTone" type="edit" />
<a-popconfirm
@confirm="() => onDelete(record.id)"
title="确定要删除这一条?"
v-if="lists.list.length"
>
<a-icon class="ml-4 pointer" theme="twoTone" two-tone-color="#ff0000" type="delete" />
</a-popconfirm>
</template>
<div
class="d-flex flex-nowrap justify-space-between"
slot="expandedRowRender"
slot-scope="record"
style="margin: 0"
>{{ getselContent(record.id) }}</div>
</a-table>
</div>
<a-empty v-else />
<!-- 编辑 -->
<course-edit
:contents="contents"
:edit-data="editData"
:edit-visible="editVisible"
@closeModal="closeModal"
@getData="getData"
/>
</div>
</template>
<script>
import CourseEdit from 'components/Course/CourseEdit.vue';
import { deleteService, selContent } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: '7%',
scopedSlots: { customRender: 'id' },
},
{
title: '服务名称',
align: 'center',
dataIndex: 'name',
key: 'name',
},
{
title: '服务简介',
align: 'center',
dataIndex: 'intro',
key: 'intro',
},
{
title: '服务图片',
align: 'center',
dataIndex: 'picUrl',
key: 'picUrl',
scopedSlots: { customRender: 'picUrl' },
},
{
title: '服务类型',
align: 'center',
dataIndex: 'serviceType',
key: 'serviceType',
scopedSlots: { customRender: 'serviceType' },
},
{
title: '服务排序',
align: 'center',
dataIndex: 'orders',
key: 'orders',
scopedSlots: { customRender: 'orders' },
},
{
title: '编辑',
align: 'center',
dataIndex: 'edit',
key: 'edit',
scopedSlots: { customRender: 'edit' },
},
];
export default {
name: 'CourseDate',
components: {
CourseEdit,
},
// props: { lists: { type: Array, default: () => {} } },
props: { lists: { type: Object, default: () => {} }, pagination: { type: Object, default: () => {} } },
data() {
return {
columns,
loading: false,
editingKey: '',
height: '',
editVisible: false,
editData: null,
contents: '',
};
},
mounted() {
let th = 250;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
showEditModal(data) {
this.editData = data;
this.contents = this.getselContent(data.id);
this.editVisible = true;
},
closeModal() {
this.editVisible = false;
},
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('getInnovativeServiceSearch', condition);
},
getData() {
this.$emit('getInnovativeServiceSearch');
},
//
async onDelete(id) {
try {
const params = { param: { id } };
const res = await deleteService(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$emit('getInnovativeServiceSearch');
this.$message.success('删除成功');
// TODO:
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '删除失败');
}
},
//
getselContent(id) {
try {
const parmas = {
param: {
id: +id,
serviceType: 3,
},
};
const res = selContent(params);
const { code, msg, data } = res.data;
if (code === 200) {
// console.log(data);
return data.content;
} else {
return '暂无内容';
}
} catch (error) {
return '暂无内容';
}
},
},
};
</script>
<style scoped lang="stylus"></style>

195
src/components/Course/CourseEdit.vue

@ -0,0 +1,195 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 编辑 -->
<a-modal
:mask-closable="false"
@cancel="$emit('closeModal')"
destroy-on-close
footer
title="修改服务"
v-model="editVisible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 服务名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务名称"
>
<a-input class="ml-3" placeholder="服务名称" v-model="serviceName" />
</a-form-item>
<!-- 服务简介 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务简介"
>
<a-textarea class="ml-3" placeholder="服务简介" v-model="intro" />
</a-form-item>
<!-- 服务内容 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务内容"
>
<a-textarea class="ml-3" placeholder="服务内容" v-model="content" />
</a-form-item>
<!-- 服务排序 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务排序"
>
<a-input-number class="ml-3" v-model="orders" />
</a-form-item>
<!-- 图片 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="图片"
>
<a-upload
:action="upload"
:before-upload="beforeUpload"
@change="handleChange"
class="ml-3"
list-type="picture"
name="files"
>
<a-button v-show="fileList.length - 0 === 0">
<a-icon type="upload" />选择图片
</a-button>
</a-upload>
</a-form-item>
<!-- 服务状态 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="服务状态"
>
<a-select
@change="getUse($event, 'recStatus')"
class="ml-3"
default-value="正常"
style="width: 100%"
>
<a-select-option
:key="index"
:value="index"
v-for="(item, index) in recStatusList"
>{{ item }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { upload, updateService } from 'config/api';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'CourseEdit',
props: {
editVisible: { type: Boolean, default: false },
editData: { type: Object, default: () => {} },
contents: { type: String, default: '' },
},
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'r-d-member-add' }),
upload: upload,
fileList: [],
//
beforeUpload: file => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('仅支持 JPG/PNG 格式的图片!');
}
return isJpgOrPng;
},
recStatusList: ['正常', '禁用'],
serviceTypeList: ['创新平台', '孵化平台', '产业平台'],
serviceName: '',
content: '',
intro: '',
orders: '',
picId: '',
recStatus: 0,
serviceType: 0,
};
},
watch: {
editData(val) {
console.log(val);
},
},
methods: {
//
handleChange(info) {
// this.fileList = fileList;
console.log(info);
if (info.file.status === 'done') {
this.fileList.push(info.file.response.data[0].id);
} else if (info.file.status === 'removed') {
this.fileList = info.fileList;
}
},
changeIpt(e, str) {
this[str] = e.target.value;
},
getUse(e, str) {
this[str] = e;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const params = {
param: {
id: this.editData.id,
name: this.serviceName ? this.serviceName : this.editData.name,
content: this.content ? this.content : this.contents === '暂无内容' ? '' : this.contents,
intro: this.intro ? this.intro : this.editData.intro,
orders: this.orders ? this.orders : this.editData.orders,
picId: this.picId ? this.picId : this.editData.picId,
recStatus: this.recStatus,
serviceType: 3,
},
};
const res = await updateService(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$emit('getData');
this.$emit('closeModal');
this.$message.success('修改成功');
} else {
this.$message.error('修改失败');
}
} catch (error) {
this.$message.error(error);
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

74
src/components/Course/CourseSearch.vue

@ -0,0 +1,74 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 团队名称 -->
<div>
<a-input placeholder="服务名称" style="width: 150px" v-model="name" allow-clear />
<span class="ml-3"> 服务状态:</span>
<a-select @change="handleChangeSelect" class="ml-3" style="width: 150px" placeholder="状态" allow-clear>
<a-select-option :key="item" :value="index" v-for="(item, index) in statusList">{{ item }}</a-select-option>
</a-select>
<a-button @click="handleTableChange" class="mx-2" type="primary">搜索</a-button>
</div>
<div class="flex-1"></div>
<a-button type="primary" @click="showModal" class="editable-add-btn">增加</a-button>
<!-- 添加 -->
<course-add :visible="visible" @closeModal="closeModal" @handleTableChange="handleTableChange" />
</div>
</template>
<script>
import CourseAdd from 'components/Course/CourseAdd.vue';
export default {
name: 'CourseSearch',
components: {
CourseAdd,
},
data() {
return {
visible: false,
name: '',
serviceTypes: [
{ id: 1, value: '创新平台' },
{ id: 2, value: '孵化平台' },
{ id: 3, value: '产业平台' },
],
statusList: ['正常', '禁用'],
status111: '',
};
},
methods: {
showModal() {
this.visible = true;
},
closeModal() {
this.visible = false;
},
handleChangeSelect(e) {
// this[type] = value;
this.status111 = e;
},
handleChangeName(value) {
console.log('value: ', value);
this.name = value;
},
async handleTableChange() {
const { name, status111 } = this;
//
const condition = { name, status111 };
await this.$emit('getInnovativeServiceSearch', condition);
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus"></style>

158
src/components/Development/Detail.vue

@ -0,0 +1,158 @@
<template>
<div class="d-flex flex-column">
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">申请人</span>
{{ record.info.applicant }}
</div>
<div class="flex-1">
<span class="font-bold-14">已转让企业数</span>
{{ record.info.assignment }}
</div>
<div class="flex-1">
<span class="font-bold-14">学科分类</span>
{{ record.info.classification }}
</div>
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">所属领域</span>
{{ record.info.domainone }}
<span
v-if="record.info.domaintwo"
>/ {{ record.info.domaintwo }}</span>
</div>
<div class="flex-1">
<span class="font-bold-14">知识产权</span>
{{ record.info.finance }}
</div>
<div class="flex-1">
<span class="font-bold-14">转让收入</span>
{{ record.info.income }}万元
</div>
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">成果阶段</span>
{{ record.info.stage }}
</div>
<div class="flex-1">
<span class="font-bold-14">成果标准</span>
{{ record.info.standard }}
</div>
<div class="flex-1">
<span class="font-bold-14">成果水平</span>
{{ record.info.level }}
</div>
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">分类类型</span>
<span :key="a" v-for="(type,a) in record.info.names">
{{ type }}
<span v-if="a < record.info.names.length-1">/</span>
</span>
</div>
<div class="flex-1">
<span class="font-bold-14">关键词</span>
{{ record.info.keywordone }}
<span
v-if="record.info.keywordone"
>/ {{ record.info.keywordone }}</span>
<span v-if="record.info.keywordthree">/ {{ record.info.keywordthree }}</span>
</div>
<div class="flex-1">
<span class="font-bold-14">专利数</span>
{{ record.info.nums }}
</div>
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">专利名称</span>
{{ record.info.registerName }}
</div>
<div class="flex-1">
<span class="font-bold-14">专利情况</span>
{{ record.info.patent }}
</div>
<div class="flex-1">
<span class="font-bold-14">专利号</span>
{{ record.info.registerNum }}
</div>
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">专利类型</span>
{{ record.info.style }}
</div>
<div class="flex-1">
<span class="font-bold-14">成果表现形式</span>
{{ record.info.performance }}
</div>
<div class="flex-1">
<span class="font-bold-14">成果范围</span>
{{ record.info.ranges }}
</div>
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">转让形式</span>
{{ record.info.layout }}
</div>
<div class="flex-1">
<span class="font-bold-14">未应用原因1</span>
{{ record.info.reansonone }}
<span
v-if="record.info.reansontwo"
>/ {{ record.info.reansontwo }}</span>
</div>
<div class="flex-1">
<span class="font-bold-14">实验室名字</span>
{{ record.info.researchName }}
</div>
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">研究形式</span>
{{ record.info.shape }}
</div>
<div class="flex-1">
<span class="font-bold-14">应用状态</span>
{{ record.info.situation }}
</div>
<div class="flex-1">
<span class="font-bold-14">发明人</span>
{{ record.info.inventor }}
</div>
</div>
<div class="d-flex flex-column mb-3">
<span class="font-bold-14">简介</span>
<span v-dompurify-html="record.info.content" v-if="record.info.content"></span>
</div>
</div>
</template>
<script>
export default {
name: 'Detail',
props: {
record: { type: Object, default: () => {} },
},
data() {
return {};
},
methods: {},
};
</script>
<style lang="stylus" scoped></style>

639
src/components/Development/DevelopmentAdd.vue

@ -0,0 +1,639 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 添加 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="添加成果"
v-model="visible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 成果名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="成果名称"
>
<a-input
placeholder="请输入成果名称"
v-decorator="[
'name',
{
rules: [
{ required: true, message: '成果名称不能为空' },
{ whitespace: true, message: '成果名称不能为空' },
{ max: 140, massage: '成果名称最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 成果水平 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="成果水平"
>
<a-select
placeholder="请选择成果水平"
style="width:100%"
v-decorator="[
'level'
]"
>
<a-select-option :key="type.id" :value="type.id" v-for="type in levels">{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 成果范围 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="成果范围"
>
<a-select
placeholder="请选择成果范围"
style="width:100%"
v-decorator="[
'ranges'
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in assignments"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 成果阶段 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="成果阶段"
>
<a-select
placeholder="请选择成果阶段"
style="width:100%"
v-decorator="[
'stage'
]"
>
<a-select-option :key="type.id" :value="type.id" v-for="type in stages">{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 成果表现形式 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="成果表现形式"
>
<a-select
placeholder="请选择成果表现形式"
style="width:100%"
v-decorator="[
'performance'
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in performances"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 成果标准 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="成果标准"
>
<a-select
placeholder="请选择成果标准"
style="width:100%"
v-decorator="[
'standard'
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in standards"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 申请人 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="申请人"
>
<a-input
placeholder="请输入申请人"
v-decorator="[
'applicant'
]"
/>
</a-form-item>
<!-- 已转让企业数 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="已转让企业数"
>
<a-input
placeholder="请输入已转让企业数"
v-decorator="[
'assignment'
]"
/>
</a-form-item>
<!-- 学科分类 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="学科分类"
>
<a-input
placeholder="请输入学科分类"
v-decorator="[
'classification'
]"
/>
</a-form-item>
<!-- 所属领域 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="所属领域"
>
<a-checkbox-group @change="onChange($event,'domains','domain')">
<a-checkbox
:disabled="item.disabled"
:key="item.id"
:value="item.id"
class="my-2"
v-for="item in domains"
>{{ item.value }}</a-checkbox>
</a-checkbox-group>
</a-form-item>
<!-- 知识产权 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="知识产权"
>
<a-select
placeholder="请选择知识产权"
style="width:100%"
v-decorator="[
'finance'
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in finances"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 编号 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="编号"
>
<a-input
placeholder="请输入编号"
v-decorator="[
'identifier'
]"
/>
</a-form-item>
<!-- 转让收入 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="转让收入(万元)"
>
<a-input
placeholder="请输入转让收入(万元)"
v-decorator="[
'income'
]"
/>
</a-form-item>
<!-- 发明人 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="发明人"
>
<a-input
placeholder="请输入发明人"
v-decorator="[
'inventor'
]"
/>
</a-form-item>
<!-- 关键词 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="关键词"
>
<div class="d-flex flex-nowrap">
<a-input
class="mr-2"
placeholder="关键词1"
v-decorator="[
'keywordone'
]"
/>
<a-input
class="mr-2"
placeholder="关键词2"
v-decorator="[
'keywordtwo'
]"
/>
<a-input
placeholder="关键词3"
v-decorator="[
'keywordthree'
]"
/>
</div>
</a-form-item>
<!-- 转让形式 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="转让形式"
>
<a-select
placeholder="请选择转让形式"
style="width:100%"
v-decorator="[
'layout'
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in layouts"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 类型 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="类型"
>
<a-checkbox-group
v-decorator="[
'modelIds',
{
rules: [
{ required: true, message: '类型不能为空' },
],
},
]"
>
<a-checkbox :key="item.id" :value="item.id" v-for="item in typeLists">{{ item.name }}</a-checkbox>
</a-checkbox-group>
</a-form-item>
<!-- 专利数 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="专利数"
>
<a-input
placeholder="请输入专利数"
v-decorator="[
'nums'
]"
/>
</a-form-item>
<!-- 专利情况 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="专利情况"
>
<a-select
placeholder="请选择专利情况"
style="width:100%"
v-decorator="[
'patent'
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in patents"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 图片 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="图片"
>
<a-upload
:action="upload"
:before-upload="beforeUpload"
@change="handleChange"
list-type="picture"
name="files"
v-decorator="[
'pic',
{
rules: [
{ required: true, message: '图片不能为空' },
],
},
]"
>
<a-button v-show="fileList.length - 0 === 0">
<a-icon type="upload" />选择图片
</a-button>
</a-upload>
</a-form-item>
<!-- 未应用原因 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="未应用原因"
>
<a-checkbox-group @change="onChange($event,'reasons','reason')">
<a-checkbox
:disabled="item.disabled"
:key="item.id"
:value="item.id"
class="my-2"
v-for="item in reasons"
>{{ item.value }}</a-checkbox>
</a-checkbox-group>
</a-form-item>
<!-- 专利名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="专利名称"
>
<a-input
placeholder="请输入专利名称"
v-decorator="[
'registerName'
]"
/>
</a-form-item>
<!-- 专利号 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="专利号"
>
<a-input
placeholder="请输入专利号"
v-decorator="[
'registerNum'
]"
/>
</a-form-item>
<!-- 所属单位 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="所属单位"
>
<a-select
placeholder="请选择所属单位"
style="width:100%"
v-decorator="[
'research'
]"
>
<a-select-option
:key="index"
:value="type.id"
v-for="(type, index) in types"
>{{ type.name }}</a-select-option>
</a-select>
</a-form-item>
<!-- 研究形式 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="研究形式"
>
<a-select
placeholder="请选择研究形式"
style="width:100%"
v-decorator="[
'shape'
]"
>
<a-select-option :key="type.id" :value="type.id" v-for="type in shapes">{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 应用状态 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="应用状态"
>
<a-select
placeholder="请选择应用状态"
style="width:100%"
v-decorator="[
'situation'
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in situations"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 专利类型 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="专利类型"
>
<a-input
placeholder="请输入专利类型"
v-decorator="[
'style'
]"
/>
</a-form-item>
<!-- 简介 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="简介"
required
>
<quill-editor :max-size="maxSize" :placeholder="placeholder" @changeInput="changeInput" />
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { upload, selResAdd } from 'config/api';
import { mapActions } from 'vuex';
import QuillEditor from 'components/QuillEditor/QuillEditor.vue';
import addMixin from './mixins/addMixin.js';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'DevelopmentAdd',
props: { visible: { type: Boolean, default: false }, typeLists: { type: Array, default: () => [] } },
components: { QuillEditor },
mixins: [addMixin],
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'development-add' }),
upload: upload,
fileList: [],
//
beforeUpload: file => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('仅支持 JPG/PNG 格式的图片!');
}
return isJpgOrPng;
},
types: [],
maxSize: 2048,
content: '',
placeholder: '请输入...',
domain: [], //
reason: [], //
};
},
async created() {
const params = {
param: {
pageNum: 1,
pageSize: 10,
model: 2,
},
};
this.types = await this.getSelModelSearch(params);
},
methods: {
...mapActions(['getSelModelSearch']),
//
onChange(checkedValues, arr, type) {
this[type] = checkedValues;
this[arr][checkedValues[0]].disabled = false;
if (checkedValues.length < 2) {
for (let i = 0; i < this[arr].length; i++) {
const item = this[arr][i];
item.disabled = false;
}
}
if (checkedValues.length > 1) {
for (let i = 0; i < this[arr].length; i++) {
const item = this[arr][i];
item.disabled = true;
for (let j = 0; j < checkedValues.length; j++) {
const element = checkedValues[j];
if (item.id === element) {
item.disabled = false;
}
}
}
}
},
//
handleChange(info) {
if (info.file.status === 'done') {
this.fileList.push(info.file.response.data[0].id);
} else if (info.file.status === 'removed') {
this.fileList = info.fileList;
}
},
//
changeInput(value) {
this.content = value;
},
//
verificationContent() {
if (this.content === '') {
this.$message.error('请输入简介');
return false;
}
return true;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
if (!this.verificationContent()) return;
const { fileList, domain, reason, content } = this;
const params = { param: values };
params.param.pic = fileList[0];
params.param.content = content;
if (domain && domain.length > 0) {
params.param.domainone = domain[0];
params.param.domaintwo = domain[1] ? domain[1] : '';
}
if (reason && reason.length > 0) {
params.param.reansonone = reason[0];
params.param.reansontwo = reason[1] ? reason[1] : '';
}
const res = await selResAdd(params);
const { data, msg, code } = res.data;
//
if (code === 200) {
this.$message.success('添加成功');
this.$emit('handleTableChange');
} else {
throw msg;
}
this.$emit('closeModal');
} catch (error) {
this.$emit('closeModal');
this.$message.error(error || '添加成果失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

227
src/components/Development/DevelopmentDate.vue

@ -0,0 +1,227 @@
<template>
<div class="main flex-1">
<a-spin :spinning="showEdit">
<div style="width:100%" v-if="lists && lists.length > 0">
<a-table
:columns="columns"
:data-source="lists"
:loading="loading"
:pagination="pagination"
:row-key="record => record.id"
:scroll="{ y: height }"
@change="handleTableChange"
@expand="getDetail"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<!-- 图片 -->
<template slot="visitLocation" slot-scope="text, record">
<img :src="record.visitLocation" height="50" width="50" />
</template>
<!-- 说明图片 -->
<template slot="introductionPicture" slot-scope="text, record">
<img :src="record.introductionPicture" class="img" />
<a-modal
:imgVisible="imgVisible"
:maskClosable="false"
@cancel="imgVisible = false"
destroyOnClose
footer
title="身份证明"
>
<img :src="record.idCardPromise" @click="imgVisible = true" style="width: 100%;" />
</a-modal>
</template>
<template slot="edit" slot-scope="text, record">
<a-icon @click="showEditModal(record)" class="pointer" theme="twoTone" type="edit" />
<a-popconfirm
@confirm="() => onDelete(record.id)"
title="确定要删除这一条?"
v-if="lists.length"
>
<a-icon class="ml-4 pointer" theme="twoTone" two-tone-color="#ff0000" type="delete" />
</a-popconfirm>
</template>
<div slot="expandedRowRender" slot-scope="record" style="margin: 0">
<a-spin :spinning="spinning" tip="详情加载中...">
<div v-if="record.info">
<detail :record="record" />
</div>
</a-spin>
</div>
</a-table>
</div>
<a-empty v-else />
<!-- 编辑 -->
<development-edit
:editItem="editItem"
:editVisible="editVisible"
:typeLists="typeLists"
@closeModal="closeModal"
@selResSearch="selResSearch"
/>
</a-spin>
</div>
</template>
<script>
import DevelopmentEdit from 'components/Development/DevelopmentEdit.vue';
import Detail from './Detail.vue';
import { selResDelete, selResMesH } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: '7%',
scopedSlots: { customRender: 'id' },
},
{
title: '编号',
align: 'center',
dataIndex: 'identifier',
key: 'identifier',
},
{
title: '成果名称',
align: 'center',
dataIndex: 'name',
key: 'name',
},
{
title: '图片',
align: 'center',
dataIndex: 'visitLocation',
key: 'visitLocation',
scopedSlots: { customRender: 'visitLocation' },
},
{
title: '编辑',
align: 'center',
dataIndex: 'edit',
key: 'edit',
scopedSlots: { customRender: 'edit' },
},
];
export default {
name: 'DevelopmentDate',
components: {
DevelopmentEdit,
Detail,
},
props: {
lists: { type: Array, default: () => [] },
pagination: { type: Object, default: () => {} },
typeLists: { type: Array, default: () => [] },
},
data() {
return {
columns,
loading: false,
height: '',
editVisible: false,
imgVisible: false,
spinning: false,
editItem: null, //
showEdit: false,
};
},
mounted() {
let th = 250;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
async showEditModal(record) {
this.showEdit = true;
await this.getDetail(true, record);
this.showEdit = false;
this.editVisible = true;
this.editItem = record;
},
closeModal() {
this.editVisible = false;
},
async selResSearch() {
await this.$emit('selResSearch');
},
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('selResSearch', condition);
},
//
async getDetail(expanded, record) {
if (!expanded) return;
try {
this.spinning = true;
const params = { param: { id: record.id } };
const res = await selResMesH(params);
const { data, msg, code } = res.data;
this.spinning = false;
if (code === 200) {
const item = this.lists.find(item => item.id === record.id);
item.info = data;
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '查询失败');
}
},
//
async onDelete(id) {
console.log(id);
try {
const params = { param: { id } };
const res = await selResDelete(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('删除成功');
this.$emit('selResSearch');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '删除失败');
}
},
},
};
</script>
<style lang="stylus" scoped>
.main .img {
height: 65px;
}
.main .big_img {
width: 200px;
}
</style>

766
src/components/Development/DevelopmentEdit.vue

@ -0,0 +1,766 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 编辑 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="修改成果"
v-model="editVisible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit" v-if="editVisible && editItem && editItem.info">
<!-- 成果名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="成果名称"
>
<a-input
placeholder="请输入成果名称"
v-decorator="[
'name',
{
initialValue: editItem.info.name,
rules: [
{ required: true, message: '成果名称不能为空' },
{ whitespace: true, message: '成果名称不能为空' },
{ max: 140, massage: '成果名称最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 成果水平 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="成果水平"
>
<a-select
placeholder="请选择成果水平"
style="width:100%"
v-decorator="[
'level',{initialValue: editItem.info.level}
]"
>
<a-select-option :key="type.id" :value="type.id" v-for="type in levels">{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 成果范围 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="成果范围"
>
<a-select
placeholder="请选择成果范围"
style="width:100%"
v-decorator="[
'ranges',{initialValue: editItem.info.ranges}
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in assignments"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 成果阶段 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="成果阶段"
>
<a-select
placeholder="请选择成果阶段"
style="width:100%"
v-decorator="[
'stage',{initialValue: editItem.info.stage}
]"
>
<a-select-option :key="type.id" :value="type.id" v-for="type in stages">{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 成果表现形式 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="成果表现形式"
>
<a-select
placeholder="请选择成果表现形式"
style="width:100%"
v-decorator="[
'performance',{initialValue: editItem.info.performance}
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in performances"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 成果标准 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="成果标准"
>
<a-select
placeholder="请选择成果标准"
style="width:100%"
v-decorator="[
'standard',{initialValue: editItem.info.standard}
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in standards"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 申请人 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="申请人"
>
<a-input
placeholder="请输入申请人"
v-decorator="[
'applicant',{initialValue: editItem.info.applicant}
]"
/>
</a-form-item>
<!-- 已转让企业数 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="已转让企业数"
>
<a-input
placeholder="请输入已转让企业数"
v-decorator="[
'assignment',{initialValue: editItem.info.assignment}
]"
/>
</a-form-item>
<!-- 学科分类 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="学科分类"
>
<a-input
placeholder="请输入学科分类"
v-decorator="[
'classification',{initialValue: editItem.info.classification}
]"
/>
</a-form-item>
<!-- 所属领域 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="所属领域"
>
<a-checkbox-group
@change="onChange($event,'domains','domain')"
v-decorator="[
'domain',{initialValue: oldDomain}
]"
>
<a-checkbox
:disabled="item.disabled"
:key="item.id"
:value="item.id"
class="my-2"
v-for="item in domains"
>{{ item.value }}</a-checkbox>
</a-checkbox-group>
</a-form-item>
<!-- 知识产权 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="知识产权"
>
<a-select
placeholder="请选择知识产权"
style="width:100%"
v-decorator="[
'finance',{initialValue: editItem.info.finance}
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in finances"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 编号 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="编号"
>
<a-input
placeholder="请输入编号"
v-decorator="[
'identifier',{initialValue: editItem.info.identifier}
]"
/>
</a-form-item>
<!-- 转让收入 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="转让收入(万元)"
>
<a-input
placeholder="请输入转让收入(万元)"
v-decorator="[
'income',{initialValue: editItem.info.income}
]"
/>
</a-form-item>
<!-- 发明人 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="发明人"
>
<a-input
placeholder="请输入发明人"
v-decorator="[
'inventor',{initialValue: editItem.info.inventor}
]"
/>
</a-form-item>
<!-- 关键词 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="关键词"
>
<div class="d-flex flex-nowrap">
<a-input
class="mr-2"
placeholder="关键词1"
v-decorator="[
'keywordone',{initialValue: editItem.info.keywordone}
]"
/>
<a-input
class="mr-2"
placeholder="关键词2"
v-decorator="[
'keywordtwo',{initialValue: editItem.info.keywordtwo}
]"
/>
<a-input
placeholder="关键词3"
v-decorator="[
'keywordthree',{initialValue: editItem.info.keywordthree}
]"
/>
</div>
</a-form-item>
<!-- 转让形式 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="转让形式"
>
<a-select
placeholder="请选择转让形式"
style="width:100%"
v-decorator="[
'layout',{initialValue: editItem.info.layout}
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in layouts"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 类型 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="类型"
>
<a-checkbox-group
v-decorator="[
'modelIds',
{
initialValue: oldTypes ? oldTypes : [],
rules: [
{ required: true, message: '类型不能为空' },
],
},
]"
>
<a-checkbox :key="item.id" :value="item.id" v-for="item in typeLists">{{ item.name }}</a-checkbox>
</a-checkbox-group>
</a-form-item>
<!-- 专利数 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="专利数"
>
<a-input
placeholder="请输入专利数"
v-decorator="[
'nums',{initialValue: editItem.info.nums}
]"
/>
</a-form-item>
<!-- 专利情况 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="专利情况"
>
<a-select
placeholder="请选择专利情况"
style="width:100%"
v-decorator="[
'patent',{initialValue: editItem.info.patent}
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in patents"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 图片 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="图片"
required
>
<a-upload
:action="upload"
:before-upload="beforeUpload"
@change="handleChange"
list-type="picture"
name="files"
>
<a-button v-show="fileList.length - 0 === 0">
<a-icon type="upload" />选择图片
</a-button>
</a-upload>
</a-form-item>
<!-- 未应用原因 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="未应用原因"
>
<a-checkbox-group
@change="onChange($event,'reasons','reason')"
v-decorator="[
'reason',{initialValue: oldReason}
]"
>
<a-checkbox
:disabled="item.disabled"
:key="item.id"
:value="item.id"
class="my-2"
v-for="item in reasons"
>{{ item.value }}</a-checkbox>
</a-checkbox-group>
</a-form-item>
<!-- 专利名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="专利名称"
>
<a-input
placeholder="请输入专利名称"
v-decorator="[
'registerName',{initialValue: editItem.info.registerName}
]"
/>
</a-form-item>
<!-- 专利号 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="专利号"
>
<a-input
placeholder="请输入专利号"
v-decorator="[
'registerNum',{initialValue: editItem.info.registerNum}
]"
/>
</a-form-item>
<!-- 所属单位 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="所属单位"
>
<a-select
placeholder="请选择所属单位"
style="width:100%"
v-decorator="[
'research',{initialValue: editItem.info.research}
]"
>
<a-select-option
:key="index"
:value="type.id"
v-for="(type, index) in types"
>{{ type.name }}</a-select-option>
</a-select>
</a-form-item>
<!-- 研究形式 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="研究形式"
>
<a-select
placeholder="请选择研究形式"
style="width:100%"
v-decorator="[
'shape',{initialValue: editItem.info.shape}
]"
>
<a-select-option :key="type.id" :value="type.id" v-for="type in shapes">{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 应用状态 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="应用状态"
>
<a-select
placeholder="请选择应用状态"
style="width:100%"
v-decorator="[
'situation',{initialValue: editItem.info.situation}
]"
>
<a-select-option
:key="type.id"
:value="type.id"
v-for="type in situations"
>{{ type.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 专利类型 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="专利类型"
>
<a-input
placeholder="请输入专利类型"
v-decorator="[
'style',{initialValue: editItem.info.style}
]"
/>
</a-form-item>
<!-- 简介 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="简介"
required
>
<quill-editor
:max-size="maxSize"
:placeholder="placeholder"
:value="editItem.info.content"
@changeInput="changeInput"
/>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { upload, selResUpdate } from 'config/api';
import { mapActions } from 'vuex';
import QuillEditor from 'components/QuillEditor/QuillEditor.vue';
import addMixin from './mixins/addMixin.js';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'DevelopmentEdit',
props: {
editVisible: { type: Boolean, default: false },
editItem: { type: Object, default: () => {} },
typeLists: { type: Array, default: () => [] },
},
components: { QuillEditor },
mixins: [addMixin],
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'development-edit' }),
upload: upload,
fileList: [],
//
beforeUpload: file => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('仅支持 JPG/PNG 格式的图片!');
}
return isJpgOrPng;
},
types: [],
maxSize: 2048,
content: '',
placeholder: '请输入...',
domain: [], //
reason: [], //
};
},
computed: {
oldTypes() {
const { typeLists, editItem } = this;
let arr = [];
for (let i = 0; i < typeLists.length; i++) {
const item = typeLists[i];
const a = editItem.info.names.findIndex(a => a === item.name);
const index = arr.findIndex(c => c === a);
if (a !== -1 && index === -1) {
arr.push(item.id);
}
}
return arr;
},
oldDomain() {
let { domains, editItem } = this;
let arr = [];
for (let i = 0; i < domains.length; i++) {
const item = domains[i];
if (editItem.info.domainone && item.value === editItem.info.domainone) {
arr.push(item.id);
}
if (editItem.info.domaintwo && item.value === editItem.info.domaintwo) {
arr.push(item.id);
}
if (editItem.info.domainone && editItem.info.domaintwo) {
item.disabled = true;
const a = domains.find(a => a.value === editItem.info.domainone);
a.disabled = false;
const b = domains.find(b => b.value === editItem.info.domaintwo);
b.disabled = false;
}
}
this.domain = arr;
return arr;
},
oldReason() {
let { reasons, editItem } = this;
let arr = [];
for (let i = 0; i < reasons.length; i++) {
const item = reasons[i];
if (editItem.info.reansonone && item.value === editItem.info.reansonone) {
arr.push(item.id);
}
if (editItem.info.reansontwo && item.value === editItem.info.reansontwo) {
arr.push(item.id);
}
if (editItem.info.reansonone && editItem.info.reansontwo) {
item.disabled = true;
const a = reasons.find(a => a.value === editItem.info.reansonone);
a.disabled = false;
const b = reasons.find(b => b.value === editItem.info.reansontwo);
b.disabled = false;
}
}
this.reason = arr;
return arr;
},
},
async created() {
const params = {
param: {
pageNum: 1,
pageSize: 10,
model: 2,
},
};
this.types = await this.getSelModelSearch(params);
},
methods: {
...mapActions(['getSelModelSearch']),
//
onChange(checkedValues, arr, type) {
this[type] = checkedValues;
this[arr][checkedValues[0]].disabled = false;
if (checkedValues.length < 2) {
for (let i = 0; i < this[arr].length; i++) {
const item = this[arr][i];
item.disabled = false;
}
}
if (checkedValues.length > 1) {
for (let i = 0; i < this[arr].length; i++) {
const item = this[arr][i];
item.disabled = true;
for (let j = 0; j < checkedValues.length; j++) {
const element = checkedValues[j];
if (item.id === element) {
item.disabled = false;
}
}
}
}
},
//
handleChange(info) {
if (info.file.status === 'done') {
this.fileList.push(info.file.response.data[0].id);
} else if (info.file.status === 'removed') {
this.fileList = info.fileList;
}
},
//
changeInput(value) {
this.content = value;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const params = this.generateSaveParams(values);
const res = await selResUpdate(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('修改成功');
this.$emit('selResSearch');
} else {
throw msg;
}
this.$emit('closeModal');
} catch (error) {
this.$message.error(error || '修改成果失败');
this.$emit('closeModal');
}
}
});
},
//
generateSaveParams(values) {
const { performance, standard, stage, level, ranges, shape, finance, patent, situation, layout } = values;
const params = { param: values };
const { fileList, domain, reason, content, editItem } = this;
params.param.id = editItem.id;
params.param.pic = fileList[0] ? fileList[0] : editItem.info.picId;
params.param.content = content ? content : editItem.info.content;
params.param.domainone = domain && domain.length > 0 && domain[0] ? domain[0] : editItem.info.domainone;
params.param.domaintwo = domain && domain.length > 1 && domain[1] ? domain[1] : editItem.info.domaintwo;
params.param.reansonone = reason && reason.length > 0 && reason[0] ? reason[0] : editItem.info.reansonone;
params.param.reansontwo = reason && reason.length > 1 && reason[1] ? reason[1] : editItem.info.reansontwo;
if (!this.isNumber(performance)) {
params.param.performance = '';
}
if (!this.isNumber(standard)) {
params.param.standard = '';
}
if (!this.isNumber(stage)) {
params.param.stage = '';
}
if (!this.isNumber(level)) {
params.param.level = '';
}
if (!this.isNumber(ranges)) {
params.param.ranges = '';
}
if (!this.isNumber(shape)) {
params.param.shape = '';
}
if (!this.isNumber(finance)) {
params.param.finance = '';
}
if (!this.isNumber(patent)) {
params.param.patent = '';
}
if (!this.isNumber(situation)) {
params.param.situation = '';
}
if (!this.isNumber(layout)) {
params.param.layout = '';
}
return params;
},
//
isNumber(val) {
var regPos = /^\d+(\.\d+)?$/; //
var regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; //
if (regPos.test(val) || regNeg.test(val)) {
return true;
} else {
return false;
}
},
},
};
</script>
<style scoped lang="stylus">
.avatar-uploader > .ant-upload {
width: 128px;
height: 128px;
}
.ant-upload-select-picture-card i {
font-size: 32px;
color: #999;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
</style>

64
src/components/Development/DevelopmentSearch.vue

@ -0,0 +1,64 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 中文名称 -->
<div>
<a-input placeholder="成果名称" style="width: 150px" v-model="content" />
<!-- <a-checkbox-group @change="onChange" class="ml-3">
<a-checkbox :key="item.id" :value="item.id" v-for="item in typeLists">{{ item.name }}</a-checkbox>
</a-checkbox-group> -->
<a-button @click="handleTableChange" class="ml-3" type="primary">搜索</a-button>
</div>
<div class="flex-1"></div>
<a-button @click="showModal" class="editable-add-btn" type="primary">增加</a-button>
<!-- 添加 -->
<development-add :typeLists="typeLists" :visible="visible" @closeModal="closeModal" @handleTableChange="handleTableChange" />
</div>
</template>
<script>
import DevelopmentAdd from 'components/Development/DevelopmentAdd.vue';
export default {
name: 'DevelopmentSearch',
components: {
DevelopmentAdd,
},
props: { typeLists: { type: Array, default: () => [] } },
data() {
return {
visible: false,
content: '',
modelIds: [],
};
},
methods: {
showModal() {
this.visible = true;
},
closeModal() {
this.visible = false;
},
onChange(checkedValues) {
this.modelIds = checkedValues;
},
async handleTableChange() {
const { content, modelIds } = this;
//
const condition = {
content,
modelIds,
};
await this.$emit('selResSearch', condition);
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus"></style>

105
src/components/Development/mixins/addMixin.js

@ -0,0 +1,105 @@
const mixin = {
data() {
return {
// 成果体现形式
performances: [
{ id: 0, value: '新技术' },
{ id: 1, value: '新工艺' },
{ id: 2, value: '新产品' },
{ id: 3, value: '新材料' },
{ id: 4, value: '新装备' },
{ id: 5, value: '农业、生产新品种' },
{ id: 6, value: '矿产新品种' },
{ id: 7, value: '其他应用技术' },
],
// 成果标准
standards: [
{ id: 0, value: '国际标准' },
{ id: 1, value: '国家标准' },
{ id: 2, value: '行业标准' },
{ id: 3, value: '地方标准' },
{ id: 4, value: '企业标准' },
],
// 成果所属阶段
stages: [
{ id: 0, value: '初期阶段' },
{ id: 1, value: '中期阶段' },
{ id: 2, value: '成熟应用阶段' },
],
// 成果水平
levels: [
{ id: 0, value: '国际领先' },
{ id: 1, value: '国际先进' },
{ id: 2, value: '国内领先' },
{ id: 3, value: '国内先进' },
{ id: 4, value: '区内领先' },
{ id: 5, value: '区内先进' },
{ id: 6, value: '其他' },
],
// 转让范围
assignments: [
{ id: 0, value: '允许出口' },
{ id: 1, value: '限国内转让' },
],
// 研究形式
shapes: [
{ id: 0, value: '独立研究' },
{ id: 1, value: '与企业合作' },
{ id: 2, value: '与院校、院所合作' },
{ id: 3, value: '与国外合作' },
{ id: 4, value: '其他' },
],
// 所属领域 -- 多选(最多选2)
domains: [
{ id: 0, value: '电子信息', disabled: false },
{ id: 1, value: '先进制造', disabled: false },
{ id: 2, value: '航空航天', disabled: false },
{ id: 3, value: '现代交通', disabled: false },
{ id: 4, value: '生物医药', disabled: false },
{ id: 5, value: '新材料', disabled: false },
{ id: 6, value: '新能源', disabled: false },
{ id: 7, value: '环境保护', disabled: false },
{ id: 8, value: '地球、空间与海洋', disabled: false },
{ id: 9, value: '现代农业', disabled: false },
],
// 知识产权形式
finances: [
{ id: 0, value: '发明 专利' },
{ id: 1, value: '实用新型 专利' },
{ id: 2, value: '软件著作权' },
],
// 专利状况
patents: [
{ id: 0, value: '未申请专利' },
{ id: 1, value: '正在申请专利' },
{ id: 2, value: '已授权专利' },
],
// 成果应用状态
situations: [
{ id: 0, value: '稳定应用' },
{ id: 1, value: '应用后停用' },
{ id: 2, value: '未应用' },
],
// 成果转让形式
layouts: [
{ id: 0, value: '产权转让' },
{ id: 1, value: '资金入股' },
{ id: 2, value: '技术入股' },
{ id: 3, value: '合作开发' },
{ id: 4, value: '技术服务' },
{ id: 5, value: '其他' },
],
// 成果未应用或停用原因 -- 多选(最多选2)
reasons: [
{ id: 0, value: '资金问题', disabled: false },
{ id: 1, value: '技术问题', disabled: false },
{ id: 2, value: '市场问题', disabled: false },
{ id: 3, value: '管理问题', disabled: false },
{ id: 4, value: '政策因素', disabled: false },
{ id: 5, value: '其他', disabled: false },
],
};
},
};
export default mixin;

46
src/components/EditableCellSelect/EditableCellSelect.vue

@ -0,0 +1,46 @@
<template>
<div class="editable-cell">
<div class="editable-cell-input-wrapper d-flex flex-nowrap justify-center" v-if="editable">
<a-select :default-value="value" @change="handleChange" @pressEnter="check">
<a-select-option :key="item.id" :value="item.name" v-for="item in arr">{{ item.name }}</a-select-option>
</a-select>
<a-icon @click="check" class="editable-cell-icon-check ml-3" type="check" />
</div>
<div class="editable-cell-text-wrapper" v-else>
{{ value || ' ' }}
<a-icon @click="edit" class="editable-cell-icon" type="edit" />
</div>
</div>
</template>
<script>
export default {
props: { text: { type: String, default: '' }, arr: { type: Array, default: () => [] } },
data() {
return {
value: this.text,
editable: false,
};
},
watch: {
text(value) {
if (value) {
this.value = value;
}
},
},
methods: {
handleChange(value) {
console.log('value: ', value);
this.value = value;
},
check() {
this.editable = false;
this.$emit('change', this.value);
},
edit() {
this.editable = true;
},
},
};
</script>

174
src/components/Enroll/EnrollDate.vue

@ -0,0 +1,174 @@
<template>
<div class="main flex-1">
<div style="width:100%" v-if="lists && lists.length > 0">
<a-table
:columns="columns"
:data-source="lists"
:loading="loading"
:pagination="pagination"
:row-key="record => record.id"
:scroll="{ y: height }"
@change="handleTableChange"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<template slot="time" slot-scope="text, record">
<span v-if="record.releaseTime">{{ record.releaseTime}}</span>
<span v-if="record.closeTime">-{{record.closeTime}}</span>
</template>
<template slot="platforms" slot-scope="text, record">
<a-tag
:color="record.platforms === 0 ? 'green' : 'blue'"
>{{ record.platforms === 0 ? '绿谷' : '创时代' }}</a-tag>
</template>
<template slot="auditStatus" slot-scope="text, record">
<a-tag
:color="record.auditStatus === 2 ? 'green' : record.auditStatus === 1 ? 'red' : 'blue'"
>{{ record.auditStatus === 2 ? '已通过' : record.auditStatus === 1 ? '未通过' : '审核中' }}</a-tag>
</template>
<template slot="examine" slot-scope="text, record">
<div class="d-flex flex-column align-center">
<a-button
@click="handleApply(record, 2)"
size="small"
type="primary"
v-if="record.auditStatus !== 2"
>通过</a-button>
<a-button @click="handleApply(record, 1)" size="small" type="danger" v-else>不通过</a-button>
<a-textarea class="fill-width mt-3" placeholder="备注" v-model="record.applyRemark" />
</div>
</template>
</a-table>
</div>
<a-empty v-else />
</div>
</template>
<script>
import { getAuditApply } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: 80,
scopedSlots: { customRender: 'id' },
},
{
title: '企业名',
align: 'center',
dataIndex: 'companyName',
key: 'companyName',
},
{
title: '申请人姓名',
align: 'center',
dataIndex: 'contactName',
key: 'contactName',
},
{
title: '联系方式',
align: 'center',
dataIndex: 'contactPhone',
key: 'contactPhone',
},
{
title: '申请时间',
align: 'center',
dataIndex: 'time',
key: 'time',
},
{
title: '申请平台',
align: 'center',
dataIndex: 'platforms',
key: 'platforms',
scopedSlots: { customRender: 'platforms' },
},
{
title: '审核状态',
align: 'center',
dataIndex: 'auditStatus',
key: 'auditStatus',
scopedSlots: { customRender: 'auditStatus' },
},
{
title: '备注',
align: 'center',
dataIndex: 'remark',
key: 'remark',
scopedSlots: { customRender: 'remark' },
},
{
title: '审核',
align: 'center',
dataIndex: 'examine',
key: 'examine',
scopedSlots: { customRender: 'examine' },
},
];
export default {
name: 'ActivityDate',
props: { lists: { type: Array, default: () => [] }, pagination: { type: Object, default: () => {} } },
data() {
return {
columns,
loading: false,
height: '',
editVisible: false,
editItem: null, //
spinning: false,
};
},
mounted() {
let th = 250;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
//
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('getSelectTeam', condition);
},
//
async handleApply(record, auditStatus) {
try {
const params = { param: { applyId: record.applyActivityId, auditStatus, remark: record.applyRemark } };
const res = await getAuditApply(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('审核成功');
this.$emit('getSelectTeam');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '审核失败');
}
},
},
};
</script>
<style scoped lang="stylus"></style>

163
src/components/Enroll/EnrollSearch.vue

@ -0,0 +1,163 @@
<template>
<div class="d-flex flex-wrap pb-3 align-center">
<!-- 审核状态 -->
<div class="ml-3 mb-3">
<a-select @change="getAuditStatus" allow-clear placeholder="审核状态" style="width: 150px">
<a-select-option
:key="index"
:value="state.id"
v-for="(state, index) in status"
>{{ state.value }}</a-select-option>
</a-select>
</div>
<!-- 发布平台 -->
<div class="ml-3 mb-3">
<a-select @change="getPlatform" allow-clear placeholder="发布平台" style="width: 150px">
<a-select-option
:key="platform.id"
:value="platform.id"
v-for="platform in platforms"
>{{ platform.value }}</a-select-option>
</a-select>
</div>
<!-- 单位名称 -->
<a-input class="ml-3 mb-3" placeholder="单位名称" style="width: 150px" v-model="companyName" />
<!-- 申请人姓名 -->
<a-input class="ml-3 mb-3" placeholder="申请人姓名" style="width: 150px" v-model="contactName" />
<!-- 联系方式 -->
<a-input class="ml-3 mb-3" placeholder="联系方式" style="width: 150px" v-model="contactPhone" />
<a-button @click="handleTableChange" class="ml-3 mb-3" type="primary">搜索</a-button>
<div class="flex-1"></div>
<!-- 导出 -->
<a-popover placement="bottom" trigger="click">
<template slot="content">
<div class="d-flex flex-column">
<a-select
@change="exportAuditStatus"
class="mb-3"
placeholder="审核状态"
style="width: 150px"
>
<a-select-option value>全部</a-select-option>
<a-select-option
:key="index"
:value="state.id"
v-for="(state, index) in status"
>{{ state.value }}</a-select-option>
</a-select>
<a-select @change="exportPlatform" class="mb-3" placeholder="发布平台" style="width: 150px">
<a-select-option value>全部</a-select-option>
<a-select-option
:key="platform.id"
:value="platform.id"
v-for="platform in platforms"
>{{ platform.value }}</a-select-option>
</a-select>
<a-button @click="handleExport" type="primary">导出</a-button>
</div>
</template>
<a-button type="primary">导出</a-button>
</a-popover>
</div>
</template>
<script>
import { getExport } from 'config/api';
export default {
name: 'ActivitySearch',
data() {
return {
status: [
{
id: 0,
value: '待审核',
},
{
id: 1,
value: '未通过',
},
{
id: 2,
value: '已通过',
},
],
auditStatus: '', //
exportStatus: '', //
platforms: [
{
id: 0,
value: '绿谷',
},
{
id: 1,
value: '创时代',
},
],
publishPlatform: '', //
exportPublishPlatform: '', //
companyName: '', //
contactName: '', //
contactPhone: '', //
};
},
methods: {
//
getAuditStatus(value) {
this.auditStatus = value;
},
//
exportAuditStatus(value) {
this.exportStatus = value;
},
//
getPlatform(value) {
this.publishPlatform = value;
},
//
exportPlatform(value) {
this.exportPublishPlatform = value;
},
//
async handleTableChange() {
const { auditStatus, publishPlatform, companyName, contactName, contactPhone } = this;
//
const condition = {
auditStatus,
publishPlatform,
companyName,
contactName,
contactPhone,
};
await this.$emit('getSelectTeam', condition);
},
//
async handleExport() {
try {
const { query } = this.$route;
const params = { param: { activityId: query.activityId, auditStatus: this.exportStatus, platforms: this.exportPublishPlatform } };
const res = await getExport(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('导出成功');
window.location.href = data;
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '导出失败');
}
},
},
};
</script>
<style scoped lang="stylus"></style>

140
src/components/EntityApply/Detail.vue

@ -0,0 +1,140 @@
<template>
<div style="width:100%" v-if="record">
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">成立时间</span>
{{ record.buildTime }}
</div>
<div class="flex-1">
<span class="font-bold-14">营业收入</span>
{{ record.businessIncome }}
</div>
<div class="flex-1">
<span class="font-bold-14">集成电路布图设计</span>
{{ record.electricDesign }}
</div>
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">电子邮箱</span>
{{ record.email }}
</div>
<div class="flex-1">
<span class="font-bold-14">合作单位</span>
{{ record.friendCompany }}
</div>
<div class="flex-1">
<span class="font-bold-14">性别</span>
{{ record.gender }}
</div>
<!--性别0-1--->
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">身份证号</span>
{{ record.idCard }}
</div>
<div class="flex-1">
<span class="font-bold-14">大专以上人员</span>
{{ record.juniorCollege }}
</div>
<div class="flex-1">
<span class="font-bold-14">法人代码</span>
{{ record.legalPerson }}
</div>
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">主营业务</span>
{{ record.mainBusiness }}
</div>
<div class="flex-1">
<span class="font-bold-14">申请专利数</span>
{{ record.patentApply }}
</div>
<div class="flex-1">
<span class="font-bold-14">专利授权数</span>
{{ record.patentGrented }}
</div>
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">发明专利数</span>
{{ record.patentInvent }}
</div>
<div class="flex-1">
<span class="font-bold-14">申请入驻场地类型</span>
{{ record.placeType }}
</div>
<!--申请入驻场地类型 0-虚拟1-实体-->
<div class="flex-1">
<span class="font-bold-14">动植物新品种</span>
{{ record.plantKind }}
</div>
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">职务</span>
{{ record.position }}
</div>
<div class="flex-1">
<span class="font-bold-14">产品阶段</span>
{{ record.productTech }}
</div>
<!--产品阶段 0-创意阶段 1-研发阶段 2-转化阶段 3-原型样品 4-产业化开发-->
<div class="flex-1">
<span class="font-bold-14">注册资金</span>
{{ record.registerMoney }}
</div>
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">现注册地址</span>
{{ record.registerSite }}
</div>
<div class="flex-1">
<span class="font-bold-14">研发人员</span>
{{ record.resarchStaff }}
</div>
<div class="flex-1">
<span class="font-bold-14">软件著作权</span>
{{ record.softwareRegister }}
</div>
</div>
<div class="d-flex flex-nowrap mb-3">
<div class="flex-1">
<span class="font-bold-14">员工人数</span>
{{ record.staffCount }}
</div>
<div class="flex-2">
<span class="font-bold-14">文件</span>
<span v-if="record.list && record.list.length>0">{{ record.list }}</span>
<span v-else>暂无</span>
</div>
</div>
<div>
<span class="font-bold-14">公司介绍</span>
<span v-dompurify-html="record.introduce"></span>
</div>
</div>
</template>
<script>
export default {
name: 'Detail',
props: { record: { type: Object, default: () => {} } },
data() {
return {};
},
methods: {},
};
</script>
<style scoped lang="stylus"></style>

439
src/components/EntityApply/EntityApplyAdd.vue

@ -0,0 +1,439 @@
<template>
<div>
<a-button @click="showModal" type="primary">入驻增加</a-button>
<a-modal :confirm-loading="confirmLoading" :title="title" :visible="visible" @cancel="handleCancel" @ok="handleOk" width="50%">
<a-form :form="form" v-if="current === 0">
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="公司名称" required>
<a-input placeholder="请输入公司名称..." v-model.trim="platform.company" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="成立时间" required>
<!-- 时间选择器时间点 -->
<a-date-picker :default-value="$moment(platform.buildTime).format('YYYY-MM-DD HH:mm:ss')" @change="changeBirthday" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="法人代码" required>
<a-input placeholder="请输入法人代码..." v-model.trim="platform.legalPerson" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="现注册地址" required>
<a-input placeholder="请输入现注册地址..." v-model.trim="platform.registerSite" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="注册资金(单位:万)">
<a-input placeholder="请输入注册资金..." type="number" v-model.trim="platform.registerMoney" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="员工人数">
<a-input placeholder="请输入员工人数..." type="number" v-model.trim="platform.staffCount" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="其中研发人数">
<a-input placeholder="请输入研发人数..." type="number" v-model.trim="platform.resarchStaff" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="大专以上人员">
<a-input placeholder="请输入员工人数..." type="number" v-model.trim="platform.juniorCollege" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="主营业务">
<a-input placeholder="请输入主营业务..." v-model.trim="platform.mainBusiness" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="营业收入(单位:万)">
<a-input placeholder="请输入营业收入..." type="number" v-model.trim="platform.businessIncome" />
</a-form-item>
</a-form>
<a-form :form="form" v-if="current === 1">
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="产品/技术阶段" required>
<!-- 单选 -->
<a-radio-group v-model="platform.productTech">
<a-radio :value="0" style="margin-right: 20px">创意阶段</a-radio>
<a-radio :value="1" style="margin-right: 20px">研发阶段</a-radio>
<a-radio :value="2" style="margin-right: 20px">转化阶段</a-radio>
<a-radio :value="3" style="margin-right: 20px">原型样品</a-radio>
<a-radio :value="4">产业化开发</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="申请专利数">
<a-input placeholder="请输入申请专利数..." type="number" v-model.trim="platform.patentApply" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="授权专利数">
<a-input placeholder="请输入授权专利数..." type="number" v-model.trim="platform.patentGrented" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="发明专利数">
<a-input placeholder="请输入发明专利数..." type="number" v-model.trim="platform.patentInvent" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="软件著作权">
<a-input placeholder="请输入软件著作权..." v-model.trim="platform.softwareRegister" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="动植物新品种">
<a-input placeholder="请输入动植物新品种..." v-model.trim="platform.plantKind" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="集成电路布图设计">
<a-input placeholder="请输入集成电路布图设计..." v-model.trim="platform.electricDesign" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="合作单位">
<a-input placeholder="请输入合作单位..." v-model.trim="platform.friendCompany" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="上传附件">
<a-upload
:action="action"
:before-upload="beforeUpload"
:default-file-list="fileList"
@change="fileChange"
list-type="picture"
name="files"
>
<p>1.营业执照复印件尚无注册的无需梯控</p>
<p>2.法定代表或授权代表身份证复印件</p>
<p>3.主导产品或技术简介</p>
<a-button> <a-icon type="upload" />点击上传附件 </a-button>
</a-upload>
</a-form-item>
</a-form>
<a-form :form="form" v-if="current === 2">
<!-- <a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="公司名称">
<a-input v-model.trim="platform.companyName" placeholder="请输入公司名称..." />
</a-form-item>-->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="姓名" required>
<a-input placeholder="请输入申请人姓名..." v-model.trim="platform.manName" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="性别" required>
<!-- 单选 -->
<a-radio-group v-model="platform.sex">
<a-radio :value="1" style="margin-right: 100px"></a-radio>
<a-radio :value="0"></a-radio>
</a-radio-group>
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="职务" required>
<a-input placeholder="请输入申请人职务..." v-model.trim="platform.position" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="联系电话" required>
<a-input @change="changePhone" placeholder="请输入联系电话.." type="tel" v-decorator="['tel', { rules: phoneRules }]" />
</a-form-item>
<!-- <a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="图片验证码" required>
<div class="d-flex flex-nowrap">
<a-input placeholder="图片验证码" type="number" v-model="codeNum" />
<img :src="picCode.imageBase64" @click="changePicCode" class="code_img ml-2" v-if="picCode && picCode.imageBase64" />
<a-button @click="changePicCode" class="code_img ml-2" size="small" v-else>获取验证码</a-button>
</div>
</a-form-item> -->
<!-- <a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="短信验证码" required>
<div class="d-flex flex-nowrap">
<a-input placeholder="请输入验证码" type="number" v-model="platform.code" />
<a-button class="code_img ml-2" disabled type="primary" v-if="showInterval">重新发送 {{ interval }}</a-button>
<a-button :disabled="platform.isTel === false" @click="getCode" class="code_img ml-2" type="primary" v-else
>获取验证码</a-button
>
</div>
</a-form-item> -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="电子邮箱">
<!-- 电子邮箱 -->
<a-input @change="changeEamil" placeholder="请输入电子邮箱..." type="email" v-decorator="['email', { rules: emailRules }]" />
</a-form-item>
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="身份证号" required>
<!-- 身份证号 -->
<a-input @change="changeIdCard" placeholder="请输入身份证号..." v-decorator="['idCard', { rules: idCardRules }]" />
</a-form-item>
</a-form>
<a-steps :current="current">
<a-step @click="current = 0" style="cursor: pointer">
<template slot="title">
<span v-if="current === 0">Waiting...</span>
<span v-else>完成</span>
</template>
<span slot="description">企业基本信息</span>
</a-step>
<a-step :title="current > 1 ? '完成' : 'Waiting...'" @click="current = 1" description="企业详细信息" style="cursor: pointer" />
<a-step :title="current > 2 ? '完成' : 'Waiting...'" @click="current = 2" description="申请人基本信息" style="cursor: pointer" />
</a-steps>
</a-modal>
</div>
</template>
<script>
import { mapState, mapActions, mapMutations } from 'vuex';
import { applyBackend, upload } from 'config/api';
const formItemLayout = {
labelCol: { span: 5 },
wrapperCol: { span: 18 },
};
const formTailLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 18, offset: 6 },
};
export default {
name: 'EntityApplyAdd',
props: {
typeNum: {
type: Number,
default: 1,
},
},
data() {
return {
form: this.$form.createForm(this, { name: 'submit' }),
visible: false,
current: 0,
action: upload,
fileList: [],
title: '入驻企业注册',
str: '申请加入',
formItemLayout,
formTailLayout,
confirmLoading: false,
platform: {
manName: '', //
sex: 1, // 01
position: '', //
tel: '', //
isTel: false,
email: '', //
isEmail: false,
code: '', //
idCard: '', //
isIdCard: false,
company: '', //
buildTime: 0, //
legalPerson: '', //
registerMoney: 0, //
staffCount: 0, //
resarchStaff: 0, //
juniorCollege: 0, //
mainBusiness: '', //
businessIncome: 0, //
registerSite: '', //
productTech: 0, //
patentApply: 0, //
patentGrented: 0, //
patentInvent: 0, //
softwareRegister: '', //
plantKind: '', //
electricDesign: '', //
friendCompany: '', //
files: [], // id
},
phoneRules: [
{ required: true, pattern: new RegExp(/^[1][3,4,5,6,7,8,9][0-9]{9}$/), whitespace: true, message: '请输入正确的手机号' },
],
codeRules: [
{ required: true, message: '请输入验证码' },
{ min: 4, max: 4, message: '请输入4位短信验证码' },
],
emailRules: [
{
pattern: new RegExp(/^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/),
whitespace: true,
message: '请输入正确的邮箱格式',
},
],
idCardRules: [
{
required: true,
pattern: new RegExp(/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/),
whitespace: true,
message: '请输入身份证号',
},
],
codeNum: '',
showInterval: false,
codeTimer: null,
interval: 120, //
};
},
computed: mapState(['placeType']),
// async created() {
// this.sendPicCode();
// await this.getUserSer();
// if (this.userSer) {
// if (this.userSer.name) {
// this.platform.manName = this.userSer.name;
// }
// if (this.userSer.phone) {
// this.platform.tel = this.userSer.phone;
// }
// if (this.userSer.companyName) {
// this.platform.companyName = this.userSer.companyName;
// }
// }
// },
methods: {
// ...mapActions('user', ['sendCode', 'sendPicCode']),
// ...mapActions('home', ['getUserSer']),
// ...mapMutations('home', ['setPagePath']),
//
showModal() {
// const anyringToken = sessionStorage.getItem('anyringToken');
// if (!anyringToken) {
// this.setPagePath(this.$route.path);
// this.$router.push('/login');
// this.$message.warning('');
// } else {
this.visible = true;
// }
},
//
handleCancel(e) {
this.visible = false;
},
//
changePhone(e) {
this.platform.tel = e.target.value;
this.platform.isTel = /^[1][3,4,5,6,7,8,9][0-9]{9}$/.test(this.platform.tel);
},
//
changeEamil(e) {
this.platform.email = e.target.value;
this.platform.isEmail = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/.test(this.platform.email);
},
//
changeIdCard(e) {
this.platform.idCard = e.target.value;
this.platform.isIdCard = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/.test(this.platform.idCard);
},
//
// async getCode() {
// // console.log(111);
// try {
// const params = {
// phone: this.platform.tel,
// verificationCodeId: this.picCode.verificationCodeId,
// verificationCodeValue: this.codeNum,
// };
// await this.sendCode(params);
// this.getCodeInterval();
// } catch (error) {
// // throw new Error(`SignIn.vue method getCode: ${error}`);
// // console.log(error);
// }
// },
//
// getCodeInterval() {
// this.showInterval = true;
// this.codeTimer = setInterval(() => {
// if (this.interval === 0) {
// clearInterval(this.codeTimer);
// this.codeTimer = null;
// this.showInterval = false;
// this.interval = 120;
// return;
// }
// this.interval = this.interval - 1;
// }, 1000);
// },
//
// changePicCode() {
// this.sendPicCode();
// },
//
changeBirthday(date, dateString) {
this.platform.buildTime = this.$moment(date).unix() * 1000;
},
//
handleOk() {
if (this.current !== 2) {
this.current++;
} else {
if (this.platform.company === '') {
this.$message.error('请输入公司名称');
} else if (this.platform.buildTime === 0) {
this.$message.error('请选择成立时间');
} else if (this.platform.legalPerson === '') {
this.$message.error('请输入法人代码');
} else if (this.platform.registerSite === '') {
this.$message.error('请输入现注册地址');
} else if (this.platform.manName === '') {
this.$message.error('请输入姓名');
} else if (this.platform.position === '') {
this.$message.error('请输入职务');
} else if (this.platform.isTel === false) {
this.$message.error('请输入联系电话');
} else if (this.platform.idCard === '') {
this.$message.error('请输入身份证号');
} else {
for (var i = 0; i < this.fileList.length; i++) {
this.platform.files = this.platform.files.concat(this.fileList[i].response.data[0].id);
}
this.addSettled();
}
}
},
async addSettled() {
this.confirmLoading = true;
try {
const params = {
param: {
buildTime: this.platform.buildTime,
businessIncome: this.platform.businessIncome,
company: this.platform.company,
electricDesign: this.platform.electricDesign,
email: this.platform.email,
fileList: this.platform.files,
friendCompany: this.platform.friendCompany,
gender: this.platform.sex,
idCard: this.platform.idCard,
juniorCollege: this.platform.juniorCollege,
legalPerson: this.platform.legalPerson,
mainBusiness: this.platform.mainBusiness,
name: this.platform.manName,
patentApply: this.platform.patentApply,
patentGrented: this.platform.patentGrented,
patentInvent: this.platform.patentInvent,
phone: this.platform.tel,
placeType: this.placeType, // store 0:1:
plantKind: this.platform.plantKind,
position: this.platform.position,
productTech: this.platform.productTech,
registerMoney: this.platform.registerMoney,
registerSite: this.platform.registerSite,
resarchStaff: this.platform.resarchStaff,
softwareRegister: this.platform.softwareRegister,
staffCount: this.platform.staffCount,
},
};
// console.log(params);
const res = await applyBackend(params);
// console.log(res);
const { code, msg, data } = res.data;
if (code === 200) {
this.$message.success('申请成功');
this.visible = false;
this.confirmLoading = false;
for (let key in this.platform) {
this.platform[key] = '';
}
this.platform.isTel = false;
this.platform.isEmail = false;
this.platform.isIdCard = false;
} else {
throw msg;
// console.log('1');
this.confirmLoading = false;
}
} catch (error) {
// console.log('2');
this.$message.error(error);
this.confirmLoading = false;
}
},
beforeUpload(file) {
return new Promise((resolve, reject) => {
const isLt5M = file.size / 1024 / 1024 < 5;
if (!isLt5M) {
this.$message.warning('上传附件大小不能超过5m!');
return reject(false);
}
return resolve(true);
});
},
fileChange(info) {
this.fileList = info.fileList;
},
},
};
</script>
<style lang="stylus" scoped>
.must-color {
color: red;
}
.code_img {
height: 32px;
width: 120px;
}
</style>

184
src/components/EntityApply/EntityApplyDate.vue

@ -0,0 +1,184 @@
<template>
<div class="main flex-1 flex-column">
<div style="width: 100%" v-if="lists && lists.length > 0">
<a-table
:columns="columns"
:data-source="lists"
:loading="loading"
:pagination="pagination"
:row-key="record => record.id"
@change="handleTableChange"
:scroll="{ y: height }"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<!-- 需求类型 -->
<template slot="demandType" slot-scope="text, record">
<a-tag color="green">{{ record.demandType }}</a-tag>
</template>
<!-- 提交时间 -->
<template slot="submissionTime" slot-scope="text, record">{{ record.submissionTime }}</template>
<!-- 处理状态 -->
<template slot="processingStatus" slot-scope="text, record, index">
<div class="editable-cell d-flex flex-nowrap">
<a-badge status="success" />
<editable-cell-select :arr="status" :text="record.processingStatus" @change="onCellChange(index, 'processingStatus', $event)" />
</div>
</template>
<template slot="dealStatus" slot-scope="text, record">
<a-tag :color="record.dealStatus === 2 ? 'green' : record.dealStatus === 1 ? 'red' : 'blue'">{{
record.dealStatus === 2 ? '已通过' : record.dealStatus === 1 ? '未通过' : '审核中'
}}</a-tag>
</template>
<!-- 操作 -->
<template slot="edit" slot-scope="text, record">
<a-icon @click="showEditModal(record)" class="pointer" theme="twoTone" type="edit" />
<a-button @click="handleApply(record.id, 2)" class="ml-3" size="small" type="primary" v-if="record.dealStatus === 1"
>通过</a-button
>
<a-button @click="handleApply(record.id, 1)" class="ml-3" size="small" type="danger" v-if="record.dealStatus === 2"
>不通过</a-button
>
</template>
<div class="d-flex flex-nowrap justify-space-between" slot="expandedRowRender" slot-scope="record" style="margin: 0">
<detail :record="record" />
</div>
</a-table>
</div>
<a-empty v-else />
</div>
</template>
<script>
import EditableCellSelect from 'components/EditableCellSelect/EditableCellSelect.vue';
import Detail from 'components/EntityApply/Detail.vue';
import { changeStatus } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: '7%',
scopedSlots: { customRender: 'id' },
},
{
title: '企业名称',
align: 'center',
dataIndex: 'company',
key: 'company',
},
{
title: '主营业务',
align: 'center',
dataIndex: 'mainBusiness',
key: 'mainBusiness',
},
{
title: '联系人',
align: 'center',
dataIndex: 'name',
key: 'name',
},
{
title: '电话',
align: 'center',
dataIndex: 'phone',
key: 'phone',
},
{
title: '处理状态',
align: 'center',
dataIndex: 'dealStatus',
key: 'dealStatus',
scopedSlots: { customRender: 'dealStatus' },
},
{
title: '操作',
align: 'center',
dataIndex: 'edit',
key: 'edit',
scopedSlots: { customRender: 'edit' },
},
];
export default {
name: 'DemandDate',
components: {
EditableCellSelect,
Detail,
},
props: { lists: { type: Array, default: () => [] }, pagination: { type: Object, default: () => {} } },
data() {
return {
columns,
loading: false,
height: '',
editable: false,
};
},
mounted() {
let th = 250;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
showEditModal(data) {
console.log(data);
},
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('entityApplicationSearch', condition);
},
onCellChange(key, dataIndex, value) {
console.log('key, dataIndex, value: ', key, dataIndex, value);
const dataSource = [...this.dataSource];
const target = dataSource.find(item => item.key === key);
if (target) {
target[dataIndex] = value;
this.dataSource = dataSource;
}
},
//
async handleApply(id, dealStatus) {
try {
const params = { param: { id, dealStatus } };
const res = await changeStatus(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('审核成功');
this.$emit('entityApplicationSearch');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '审核失败');
}
},
},
};
</script>
<style scoped lang="stylus"></style>

81
src/components/EntityApply/EntityApplySearch.vue

@ -0,0 +1,81 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 企业名称 -->
<a-input class="mr-3" placeholder="姓名" style="width: 150px" v-model="name" />
<a-input class="mr-3" placeholder="职务" style="width: 150px" v-model="position" />
<a-input class="mr-3" placeholder="联系电话" style="width: 150px" v-model="phone" />
<a-input class="mr-3" placeholder="企业/团队" style="width: 150px" v-model="company" />
<a-select @change="handleChangeSelect('dealStatus', $event)" allow-clear class="ml-3" placeholder="处理状态" style="width: 150px">
<a-select-option :key="dealStatus.id" :value="dealStatus.id" v-for="dealStatus in dealStatuss">{{
dealStatus.value
}}</a-select-option>
</a-select>
<a-button @click="handleTableChange" class="mx-2" icon="search" type="primary">搜索</a-button>
<div class="flex-1"></div>
<!-- <a-button @click="showModal" class="editable-add-btn mb-3" type="primary">增加</a-button> -->
<!-- 添加 -->
<entity-apply-add :visible="visible" @closeModal="closeModal" />
</div>
</template>
<script>
import EntityApplyAdd from 'components/EntityApply/EntityApplyAdd.vue';
export default {
name: 'EntityApplySearch',
components: {
EntityApplyAdd,
},
data() {
return {
visible: false,
name: '',
position: '',
phone: '',
company: '',
dealStatuss: [
{ id: 1, value: '审核未通过' },
{ id: 2, value: '审核通过' },
],
};
},
methods: {
handleChangeName(value) {
console.log('value: ', value);
this.companyName = value;
},
handleChangeSelect(type, value) {
this[type] = value;
},
showModal() {
this.visible = true;
},
closeModal() {
this.visible = false;
},
async handleTableChange() {
const { name, position, phone, company, dealStatus } = this;
console.log(dealStatus);
//
const condition = {
name,
position,
phone,
company,
dealStatus,
};
await this.$emit('entityApplicationSearch', condition);
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus"></style>

186
src/components/IndustryInfo/ActivityAdd.vue

@ -0,0 +1,186 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 添加 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="添加行业资讯"
v-model="visible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 标题 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="标题"
>
<a-input
placeholder="标题"
v-decorator="[
'title',
{
rules: [
{ required: true, message: '标题不能为空' },
{ whitespace: true, message: '标题不能为空' },
{ max: 140, massage: '地点最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 地点 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="地点"
>
<a-input
placeholder="地点"
v-decorator="[
'site',
{
rules: [
{ required: true, message: '地点不能为空' },
{ whitespace: true, message: '地点不能为空' },
{ max: 140, massage: '地点最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 时间 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="时间"
required
>
<a-date-picker
@change="onChange"
format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择时间"
show-time
/>
</a-form-item>
<!-- 发布部门 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="发布部门"
>
<a-input
placeholder="发布部门"
v-decorator="[
'spreadDepartment',
{
rules: [
{ required: true, message: '发布部门不能为空' },
{ whitespace: true, message: '发布部门不能为空' },
{ max: 140, massage: '发布部门最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 简介 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="简介"
>
<a-textarea
placeholder="简介"
v-decorator="[
'description',
]"
/>
</a-form-item>
<!-- 详情 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="详情"
>
<quill-editor :max-size="maxSize" :placeholder="placeholder" @changeInput="changeInput" />
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { addIndustryInfo } from 'config/api';
import QuillEditor from 'components/QuillEditor/QuillEditor.vue';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'ActivityAdd',
props: { visible: { type: Boolean, default: false } },
components: { QuillEditor },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'activity-add' }),
maxSize: 2048,
content: '',
placeholder: '请输入...',
time: '',
};
},
methods: {
//
onChange(value, dateString) {
this.time = dateString;
},
//
changeInput(value) {
this.content = value;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const { content, time } = this;
const params = { param: values };
params.param.time = time;
params.param.content = content;
const res = await addIndustryInfo(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('添加成功');
this.$emit('getBackendSearch');
} else {
throw msg;
}
this.$emit('closeModal');
} catch (error) {
this.$emit('closeModal');
this.$message.error(error || '添加失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

174
src/components/IndustryInfo/ActivityDate.vue

@ -0,0 +1,174 @@
<template>
<div class="main flex-1">
<div style="width:100%" v-if="lists && lists.length > 0">
<a-table
:columns="columns"
:data-source="lists"
:loading="loading"
:pagination="pagination"
:row-key="record => record.id"
:scroll="{ y: height }"
@change="handleTableChange"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<template slot="time" slot-scope="text, record">
<span>{{ record.time}}</span>
</template>
<template slot="edit" slot-scope="text, record">
<a-icon @click="showEditModal(record)" class="pointer" theme="twoTone" type="edit" />
<a-popconfirm @confirm="() => onDelete(record.id)" title="确定要删除这一条?" v-if="lists.length">
<a-icon class="ml-4 pointer" theme="twoTone" two-tone-color="#ff0000" type="delete" />
</a-popconfirm>
</template>
<div slot="expandedRowRender" slot-scope="record" style="margin: 0">
<div>
详情
<span v-dompurify-html="record.content"></span>
</div>
</div>
</a-table>
</div>
<a-empty v-else />
<!-- 编辑 -->
<activity-edit
:editItem="editItem"
:editVisible="editVisible"
@closeModal="closeModal"
@getBackendSearch="getBackendSearch"
/>
</div>
</template>
<script>
import ActivityEdit from 'components/IndustryInfo/ActivityEdit.vue';
import { deleteIndustryInfo } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
scopedSlots: { customRender: 'id' },
},
{
title: '标题',
align: 'center',
dataIndex: 'title',
key: 'title',
},
{
title: '地点',
align: 'center',
dataIndex: 'site',
key: 'site',
},
{
title: '活动时间',
align: 'center',
dataIndex: 'time',
key: 'time',
scopedSlots: { customRender: 'time' },
},
{
title: '公告简介',
align: 'center',
dataIndex: 'description',
key: 'description',
},
{
title: '编辑',
align: 'center',
dataIndex: 'edit',
key: 'edit',
width: 200,
scopedSlots: { customRender: 'edit' },
},
];
export default {
name: 'ActivityDate',
components: {
ActivityEdit,
},
props: { lists: { type: Array, default: () => [] }, pagination: { type: Object, default: () => {} } },
data() {
return {
columns,
loading: false,
height: '',
editVisible: false,
editItem: null, //
};
},
mounted() {
let th = 250;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
showEditModal(record) {
console.log('record: ', record);
this.editItem = record;
this.editVisible = true;
},
closeModal() {
this.editVisible = false;
},
async getBackendSearch() {
await this.$emit('getBackendSearch');
},
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('getBackendSearch', condition);
},
//
async onDelete(id) {
try {
const params = { param: { id } };
const res = await deleteIndustryInfo(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('删除成功');
this.$emit('getBackendSearch');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '删除失败');
}
},
//
openSignUp() {
const { query } = this.$route;
this.$router.push({ path: '/sign-up', query });
},
},
};
</script>
<style scoped lang="stylus"></style>

191
src/components/IndustryInfo/ActivityEdit.vue

@ -0,0 +1,191 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 编辑 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="修改行业资讯"
v-model="editVisible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 标题 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="标题"
>
<a-input
placeholder="标题"
v-decorator="[
'title',
{
initialValue: editItem.title,
},
]"
/>
</a-form-item>
<!-- 地点 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="地点"
>
<a-input
placeholder="地点"
v-decorator="[
'site',
{
initialValue: editItem.site,
},
]"
/>
</a-form-item>
<!-- 时间 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="时间"
>
<a-date-picker
@change="onChange"
format="YYYY-MM-DD HH:mm:ss"
show-time
v-decorator="[
'time',
{
initialValue: editItem.time || '',
},
]"
/>
</a-form-item>
<!-- 发布部门 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="发布部门"
>
<a-input
placeholder="发布部门"
v-decorator="[
'spreadDepartment',
{
initialValue: editItem.spreadDepartment,
},
]"
/>
</a-form-item>
<!-- 简介 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="简介"
>
<a-textarea
placeholder="简介"
v-decorator="[
'description',
{
initialValue: editItem.description,
},
]"
/>
</a-form-item>
<!-- 详情 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="详情"
>
<quill-editor
:max-size="maxSize"
:value="editItem && (editItem.content ? editItem.content : '')"
@changeInput="changeInput"
/>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { updateIndustryInfo } from 'config/api';
import QuillEditor from 'components/QuillEditor/QuillEditor.vue';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'ActivityEdit',
props: { editVisible: { type: Boolean, default: false }, editItem: { type: Object, default: () => {} } },
components: { QuillEditor },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'r-d-add' }),
maxSize: 2048,
content: '',
titleCode: '',
edtiTitleCode: '',
time: '',
};
},
methods: {
//
changeInput(value) {
this.content = value;
},
//
onChange(value, dateString) {
console.log('dateString: ', dateString);
this.time = dateString;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const { time, content, editItem } = this;
const params = { param: values };
params.param.id = editItem.id;
params.param.time = time ? time : editItem.time;
params.param.content = content ? content : editItem.content;
const res = await updateIndustryInfo(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('修改成功');
this.$emit('getBackendSearch');
this.time = '';
this.content = '';
} else {
throw msg;
}
this.$emit('closeModal');
} catch (error) {
this.$emit('closeModal');
this.$message.error(error || '修改失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

83
src/components/IndustryInfo/ActivitySearch.vue

@ -0,0 +1,83 @@
<template>
<div class="d-flex flex-wrap pb-3">
<div>
<!-- 活动标题 -->
<a-input class="ml-3" placeholder="标题" style="width: 150px" v-model="title" />
<!-- 地点 -->
<a-input class="ml-3" placeholder="地点" style="width: 150px" v-model="site" />
<!-- 发布部门 -->
<a-input class="ml-3" placeholder="发布部门" style="width: 150px" v-model="spreadDepartment" />
<!-- 发布时间 -->
<a-range-picker @change="onChange" class="ml-3" format="YYYY-MM-DD HH:mm:ss" show-time />
<a-button @click="handleTableChange" class="mx-2" type="primary">搜索</a-button>
</div>
<div class="flex-1"></div>
<a-button @click="showModal" class="editable-add-btn" type="primary">增加</a-button>
<!-- 添加 -->
<activity-add :visible="visible" @closeModal="closeModal" @getBackendSearch="getBackendSearch" />
</div>
</template>
<script>
import ActivityAdd from 'components/IndustryInfo/ActivityAdd.vue';
export default {
name: 'ActivitySearch',
components: {
ActivityAdd,
},
data() {
return {
visible: false,
title: '',
site: '',
spreadDepartment: '',
startTime: '',
endTime: '',
};
},
methods: {
showModal() {
this.visible = true;
},
closeModal() {
this.visible = false;
},
async getBackendSearch() {
await this.$emit('getBackendSearch');
},
//
onChange(dates, dateStrings) {
this.startTime = dateStrings[0];
this.endTime = dateStrings[1];
},
async handleTableChange() {
const { title, site, spreadDepartment, startTime, endTime } = this;
//
const condition = {
title,
site,
spreadDepartment,
startTime,
endTime,
};
await this.$emit('getBackendSearch', condition);
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus"></style>

266
src/components/Institute/InstituteAdd.vue

@ -0,0 +1,266 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 添加 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="添加实验室"
v-model="visible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="名称"
>
<a-input
placeholder="名称"
v-decorator="[
'name',
{
rules: [
{ required: true, message: '名称不能为空' },
{ whitespace: true, message: '名称不能为空' },
{ max: 140, massage: '名称最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 可做实验 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="可做实验"
>
<a-input
placeholder="可做实验"
v-decorator="[
'experiments',
]"
/>
</a-form-item>
<!-- 研究院类型 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="研究院类型"
>
<a-checkbox-group
@change="onChange"
v-decorator="[
'moldIds',
{
rules: [
{ required: true, message: '研究院类型不能为空' },
],
},
]"
>
<a-checkbox :key="item.id" :value="item.id" v-for="item in typeLists">{{ item.name }}</a-checkbox>
</a-checkbox-group>
</a-form-item>
<!-- 项目分类 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="项目分类"
>
<a-input
placeholder="项目分类"
v-decorator="[
'projectKind',
]"
/>
</a-form-item>
<!-- 图片 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="图片"
>
<a-upload
:action="upload"
:before-upload="beforeUpload"
@change="handleChange"
list-type="picture"
name="files"
v-decorator="[
'picId',
{
rules: [
{ required: true, message: '图片不能为空' },
],
},
]"
>
<a-button v-show="fileList.length - 0 === 0">
<a-icon type="upload" />选择图片
</a-button>
</a-upload>
</a-form-item>
<!-- 校验 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="校验"
>
<a-input
placeholder="校验"
v-decorator="[
'vertify'
]"
/>
</a-form-item>
<!-- 研究方向 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="研究方向"
>
<quill-editor
:max-size="directionMaxSize"
:placeholder="directionPlaceholder"
@changeInput="changeDirection"
/>
</a-form-item>
<!-- 简介 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="简介"
required
>
<quill-editor :max-size="maxSize" :placeholder="placeholder" @changeInput="changeInput" />
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { upload, addInstitute } from 'config/api';
import QuillEditor from 'components/QuillEditor/QuillEditor.vue';
const formItemLayout = {
labelCol: { span: 8 },
wrapperCol: { span: 14 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'InstituteAdd',
components: { QuillEditor },
props: { visible: { type: Boolean, default: false }, typeLists: { type: Array, default: () => [] } },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'institute-add' }),
upload: upload,
fileList: [],
//
beforeUpload: file => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('仅支持 JPG/PNG 格式的图片!');
}
return isJpgOrPng;
},
moldIds: [], //
maxSize: 2048,
description: '',
placeholder: '请输入...',
directionMaxSize: 500,
direction: '',
directionPlaceholder: '请输入...',
};
},
methods: {
//
handleChange(info) {
if (info.file.status === 'done') {
this.fileList.push(info.file.response.data[0].id);
} else if (info.file.status === 'removed') {
this.fileList = info.fileList;
}
},
//
changeInput(value) {
this.description = value;
},
//
changeDirection(value) {
this.direction = value;
},
//
onChange(checkedValues) {
this.moldIds = checkedValues;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const { moldIds, fileList, description, direction } = this;
if (description === '') {
this.$message.error('请填写简介');
return;
}
const params = { param: values };
params.param.moldIds = moldIds;
params.param.picId = fileList[0];
params.param.direction = direction;
params.param.description = description;
const res = await addInstitute(params);
const { data, msg, code } = res.data;
//
if (code === 200) {
this.$message.success('添加成功');
this.$emit('handleTableChange');
} else {
throw msg;
}
this.$emit('closeModal');
} catch (error) {
this.$emit('closeModal');
this.$message.error(error || '添加实验室失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus">
.avatar-uploader > .ant-upload {
width: 128px;
height: 128px;
}
.ant-upload-select-picture-card i {
font-size: 32px;
color: #999;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
</style>

226
src/components/Institute/InstituteDate.vue

@ -0,0 +1,226 @@
<template>
<div class="main flex-1">
<div style="width:100%" v-if="lists && lists.length > 0">
<a-table
:columns="columns"
:data-source="lists"
:loading="loading"
:pagination="pagination"
:row-key="record => record.id"
:scroll="{ y: height }"
@change="handleTableChange"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<!-- 说明图片 -->
<template slot="researchDirection" slot-scope="text, record">
<img :src="record.researchDirection" class="img" />
<a-modal
:imgVisible="imgVisible"
:maskClosable="false"
@cancel="imgVisible = false"
destroyOnClose
footer
title="身份证明"
>
<img :src="record.idCardPromise" @click="imgVisible = true" style="width: 100%;" />
</a-modal>
</template>
<!-- 研究院类型 -->
<template slot="serviceType" slot-scope="text, record">
<span v-if=" record.serviceType === 1">创新平台</span>
<span v-if=" record.serviceType === 2">孵化平台</span>
<span v-if=" record.serviceType === 3">产业平台</span>
</template>
<template slot="edit" slot-scope="text, record">
<a-icon @click="showEditModal(record)" class="pointer" theme="twoTone" type="edit" />
<a-popconfirm @confirm="() => onDelete(record.id)" title="确定要删除这一条?" v-if="lists.length">
<a-icon class="ml-4 pointer" theme="twoTone" two-tone-color="#ff0000" type="delete" />
</a-popconfirm>
</template>
<div
class="d-flex flex-column"
slot="expandedRowRender"
slot-scope="record"
style="margin: 0"
>
<div class="mb-3">
<span class="font-bold-14">研究方向</span>
<span v-dompurify-html="record.direction"></span>
</div>
<div>
<span class="font-bold-14">简介</span>
<span v-dompurify-html="record.description" v-if="record.description"></span>
</div>
</div>
</a-table>
</div>
<a-empty v-else />
<!-- 编辑 -->
<institute-edit
:editItem="editItem"
:editVisible="editVisible"
:typeLists="typeLists"
@closeModal="closeModal"
@getInstituteSearchBack="getInstituteSearchBack"
/>
</div>
</template>
<script>
import InstituteEdit from 'components/Institute/InstituteEdit.vue';
import { deleteInstitute } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: '7%',
scopedSlots: { customRender: 'id' },
},
{
title: '名称',
align: 'center',
dataIndex: 'name',
key: 'name',
},
{
title: '电话',
align: 'center',
dataIndex: 'phone',
key: 'phone',
},
{
title: '可做实验',
align: 'center',
dataIndex: 'experiments',
key: 'experiments',
},
{
title: '图片',
align: 'center',
dataIndex: 'picId',
key: 'picId',
},
{
title: '项目分类',
align: 'center',
dataIndex: 'projectKind',
key: 'projectKind',
},
{
title: '研究院类型',
align: 'center',
dataIndex: 'mold',
key: 'mold',
},
{
title: '校验',
align: 'center',
dataIndex: 'vertify',
key: 'vertify',
},
{
title: '编辑',
align: 'center',
dataIndex: 'edit',
key: 'edit',
scopedSlots: { customRender: 'edit' },
},
];
export default {
name: 'InstituteDate',
components: {
InstituteEdit,
},
props: {
lists: { type: Array, default: () => [] },
pagination: { type: Object, default: () => {} },
typeLists: { type: Array, default: () => [] },
},
data() {
return {
columns,
loading: false,
editingKey: '',
height: '',
editVisible: false,
imgVisible: false,
editItem: null, //
};
},
mounted() {
let th = 250;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
showEditModal(record) {
this.editVisible = true;
this.editItem = record;
},
closeModal() {
this.editVisible = false;
},
async getInstituteSearchBack() {
await this.$emit('getInstituteSearchBack');
},
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('getInstituteSearchBack', condition);
},
//
async onDelete(id) {
try {
const params = { param: { id } };
const res = await deleteInstitute(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('删除成功');
this.$emit('getInstituteSearchBack');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '删除失败');
}
},
},
};
</script>
<style lang="stylus" scoped>
.main .img {
height: 65px;
}
.main .big_img {
width: 200px;
}
</style>

287
src/components/Institute/InstituteEdit.vue

@ -0,0 +1,287 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 编辑 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="修改实验室"
v-model="editVisible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit" v-if="editVisible && editItem">
<!-- 名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="名称"
>
<a-input
placeholder="名称"
v-decorator="[
'name',
{
initialValue: editItem.name,
rules: [
{ required: true, message: '名称不能为空' },
{ whitespace: true, message: '名称不能为空' },
{ max: 140, massage: '名称最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 可做实验 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="可做实验"
>
<a-input
placeholder="可做实验"
v-decorator="[
'experiments',
{initialValue: editItem.experiments,}
]"
/>
</a-form-item>
<!-- 研究院类型 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="研究院类型"
>
<a-checkbox-group
@change="onChange"
v-decorator="[
'moldIds',
{
initialValue: oldTypes ? oldTypes : [],
rules: [
{ required: true, message: '研究院类型不能为空' },
],
},
]"
>
<a-checkbox :key="item.id" :value="item.id" v-for="item in typeLists">{{ item.name }}</a-checkbox>
</a-checkbox-group>
</a-form-item>
<!-- 项目分类 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="项目分类"
>
<a-input
placeholder="项目分类"
v-decorator="[
'projectKind',
{initialValue: editItem.projectKind}
]"
/>
</a-form-item>
<!-- 图片 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="图片"
required
>
<a-upload
:action="upload"
:before-upload="beforeUpload"
@change="handleChange"
list-type="picture"
name="files"
>
<a-button v-show="fileList.length - 0 === 0">
<a-icon type="upload" />选择图片
</a-button>
</a-upload>
</a-form-item>
<!-- 校验 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="校验"
>
<a-input
placeholder="校验"
v-decorator="[
'vertify',
{initialValue: editItem.vertify}
]"
/>
</a-form-item>
<!-- 研究方向 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="研究方向"
>
<quill-editor
:max-size="directionMaxSize"
:placeholder="directionPlaceholder"
:value="(editItem && editItem.direction) ? editItem.direction : ''"
@changeInput="changeDirection"
/>
</a-form-item>
<!-- 简介 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="简介"
required
>
<quill-editor
:max-size="maxSize"
:placeholder="placeholder"
:value="(editItem && editItem.description) ? editItem.description : ''"
@changeInput="changeInput"
/>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { upload, updateInstitute } from 'config/api';
import QuillEditor from 'components/QuillEditor/QuillEditor.vue';
const formItemLayout = {
labelCol: { span: 8 },
wrapperCol: { span: 14 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'InstituteEdit',
components: { QuillEditor },
props: {
editVisible: { type: Boolean, default: false },
typeLists: { type: Array, default: () => [] },
editItem: { type: Object, default: () => {} },
},
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'institute-add' }),
upload: upload,
fileList: [],
//
beforeUpload: file => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('仅支持 JPG/PNG 格式的图片!');
}
return isJpgOrPng;
},
moldIds: [], //
maxSize: 2048,
description: '',
placeholder: '请输入...',
directionMaxSize: 500,
direction: '',
directionPlaceholder: '请输入...',
};
},
computed: {
oldTypes() {
const { typeLists, editItem } = this;
const molds = editItem.mold.split(',');
let arr = [];
for (let i = 0; i < typeLists.length; i++) {
const item = typeLists[i];
const a = molds.findIndex(a => a === item.name);
const index = arr.findIndex(c => c === a);
if (a !== -1 && index === -1) {
arr.push(item.id);
}
}
return arr;
},
},
methods: {
//
handleChange(info) {
if (info.file.status === 'done') {
this.fileList.push(info.file.response.data[0].id);
} else if (info.file.status === 'removed') {
this.fileList = info.fileList;
}
},
//
changeInput(value) {
this.description = value;
},
//
changeDirection(value) {
this.direction = value;
},
//
onChange(checkedValues) {
this.moldIds = checkedValues;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const { moldIds, fileList, direction, description, editItem } = this;
const params = { param: values };
params.param.id = editItem.id;
params.param.moldIds = moldIds || editItem.moldIds;
params.param.picId = fileList[0] || editItem.picId;
params.param.direction = direction || editItem.direction;
params.param.description = description || editItem.description;
const res = await updateInstitute(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('修改成功');
this.$emit('getInstituteSearchBack');
} else {
throw msg;
this.$message.error('修改失败');
}
this.$emit('closeModal');
} catch (error) {
this.$message.error(error || '修改失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus">
.avatar-uploader > .ant-upload {
width: 128px;
height: 128px;
}
.ant-upload-select-picture-card i {
font-size: 32px;
color: #999;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
</style>

70
src/components/Institute/InstituteSearch.vue

@ -0,0 +1,70 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 名称 -->
<div>
<a-input placeholder="名称" style="width: 150px" v-model="name" />
<a-checkbox-group @change="onChange" class="ml-3">
<a-checkbox :key="item.id" :value="item.id" v-for="item in typeLists">{{ item.name }}</a-checkbox>
</a-checkbox-group>
<a-button @click="handleTableChange" class="ml-3" type="primary">搜索</a-button>
</div>
<div class="flex-1"></div>
<a-button @click="showModal" class="editable-add-btn" type="primary">增加</a-button>
<!-- 添加 -->
<institute-add
:typeLists="typeLists"
:visible="visible"
@closeModal="closeModal"
@handleTableChange="handleTableChange"
/>
</div>
</template>
<script>
import InstituteAdd from 'components/Institute/InstituteAdd.vue';
export default {
name: 'InstituteSearch',
components: {
InstituteAdd,
},
props: { typeLists: { type: Array, default: () => [] } },
data() {
return {
visible: false,
name: '',
moldIds: [],
};
},
methods: {
showModal() {
this.visible = true;
},
closeModal() {
this.visible = false;
},
onChange(checkedValues) {
this.moldIds = checkedValues;
console.log('this.moldIds: ', this.moldIds);
},
async handleTableChange() {
const { name, moldIds } = this;
//
const condition = {
name,
moldIds,
};
await this.$emit('getInstituteSearchBack', condition);
},
},
};
</script>
<style scoped lang="stylus"></style>

122
src/components/Manage/ManageAdd.vue

@ -0,0 +1,122 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 添加 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="添加分类管理"
v-model="visible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 类型 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="类型"
>
<a-select
placeholder="类型"
style="width:100%"
v-decorator="[
'model',
{
rules: [
{ required: true, message: '类型不能为空' },
],
},
]"
>
<a-select-option
:key="index"
:value="item.id"
v-for="(item, index) in types"
>{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<!-- 分类名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="分类名称"
>
<a-input
placeholder="分类名称"
v-decorator="[
'name',
{
rules: [
{ required: true, message: '分类名称不能为空' },
{ whitespace: true, message: '分类名称不能为空' },
{ max: 140, massage: '分类名称最多140个字符' },
],
},
]"
/>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { selModelAdd } from 'config/api';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'ManageAdd',
props: { visible: { type: Boolean, default: false } },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'manage-add' }),
types: [
{ id: 0, name: '成果' },
{ id: 1, name: '仪器' },
{ id: 2, name: '实验室' },
],
};
},
methods: {
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const params = { param: values };
const res = await selModelAdd(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('添加成功');
this.$emit('closeModal');
this.$emit('handleTableChange');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '添加失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

145
src/components/Manage/ManageDate.vue

@ -0,0 +1,145 @@
<template>
<div class="main flex-1">
<div style="width: 100%" v-if="lists.list && lists.list.length > 0">
<a-table
:columns="columns"
:data-source="lists.list"
:loading="loading"
:pagination="pagination"
:row-key="record => record.id"
@change="handleTableChange"
:scroll="{ y: height }"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<template slot="model" slot-scope="text, record">
<span v-if="record.model === 0">成果</span>
<span v-if="record.model === 1">仪器</span>
<span v-if="record.model === 2">实验室</span>
</template>
<template slot="edit" slot-scope="text, record">
<a-icon @click="showEditModal(record)" class="pointer" theme="twoTone" type="edit" />
<a-popconfirm @confirm="() => onDelete(record.id)" title="确定要删除这一条?" v-if="lists.list.length">
<a-icon class="ml-4 pointer" theme="twoTone" two-tone-color="#ff0000" type="delete" />
</a-popconfirm>
</template>
</a-table>
</div>
<a-empty v-else />
<!-- 编辑 -->
<manage-edit :editItem="editItem" :editVisible="editVisible" @closeModal="closeModal" @selModelSearch="selModelSearch" />
</div>
</template>
<script>
import ManageEdit from 'components/Manage/ManageEdit.vue';
import { selModelDelete } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: '7%',
scopedSlots: { customRender: 'id' },
},
{
title: '类型',
align: 'center',
dataIndex: 'model',
key: 'model',
scopedSlots: { customRender: 'model' },
},
{
title: '分类名称',
align: 'center',
dataIndex: 'name',
key: 'name',
},
{
title: '编辑',
align: 'center',
dataIndex: 'edit',
key: 'edit',
scopedSlots: { customRender: 'edit' },
},
];
export default {
name: 'ManageDate',
components: {
ManageEdit,
},
props: { lists: { type: Object, default: () => {} }, pagination: { type: Object, default: () => {} } },
data() {
return {
columns,
loading: false,
editingKey: '',
height: '',
editItem: null, //
editVisible: false,
};
},
mounted() {
let th = 150;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
showEditModal(record) {
this.editItem = record;
this.editVisible = true;
},
closeModal() {
this.editVisible = false;
},
async selModelSearch() {
await this.$emit('selModelSearch');
},
//
async onDelete(id) {
try {
const params = { param: { id } };
const res = await selModelDelete(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('删除成功');
this.$emit('selModelSearch');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '删除失败');
}
},
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('selModelSearch', condition);
},
},
};
</script>
<style scoped lang="stylus"></style>

125
src/components/Manage/ManageEdit.vue

@ -0,0 +1,125 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 编辑 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="修改分类管理"
v-model="editVisible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit" v-if="editVisible && editItem">
<!-- 类型 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="类型"
>
<a-select
placeholder="类型"
style="width:100%"
v-decorator="[
'model',
{
initialValue: editItem.model,
rules: [
{ required: true, message: '类型不能为空' },
],
},
]"
>
<a-select-option
:key="index"
:value="item.id"
v-for="(item, index) in types"
>{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<!-- 分类名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="分类名称"
>
<a-input
placeholder="分类名称"
v-decorator="[
'name',
{
initialValue: editItem.name,
rules: [
{ required: true, message: '分类名称不能为空' },
{ whitespace: true, message: '分类名称不能为空' },
{ max: 140, massage: '分类名称最多140个字符' },
],
},
]"
/>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { selModelUpdate } from 'config/api';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'ManageEdit',
props: { editVisible: { type: Boolean, default: false }, editItem: { type: Object, default: () => {} } },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'manage-add' }),
types: [
{ id: 0, name: '成果' },
{ id: 1, name: '仪器' },
{ id: 2, name: '实验室' },
],
};
},
methods: {
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const params = { param: values };
params.param.id = this.editItem.id;
const res = await selModelUpdate(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('修改成功');
this.$emit('selModelSearch');
} else {
throw msg;
}
this.$emit('closeModal');
} catch (error) {
this.$emit('closeModal');
this.$message.error(error || '修改失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

82
src/components/Manage/ManageSearch.vue

@ -0,0 +1,82 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 团队名称 -->
<div>
<a-input @change="handleChangeName" placeholder="分类名称" style="width: 150px" v-model="name" />
<a-select
@change="handleChangeSelect('model',$event)"
allow-clear
class="ml-3"
placeholder="类型"
style="width: 150px"
>
<a-select-option :key="model.id" :value="model.id" v-for="model in models">{{ model.value }}</a-select-option>
</a-select>
<a-button @click="handleTableChange" class="ml-3" type="primary">搜索</a-button>
</div>
<div class="flex-1"></div>
<a-button @click="showModal" class="editable-add-btn" type="primary">增加</a-button>
<!-- 添加 -->
<manage-add :visible="visible" @closeModal="closeModal" @handleTableChange="handleTableChange" />
</div>
</template>
<script>
import ManageAdd from 'components/Manage/ManageAdd.vue';
export default {
name: 'ManageSearch',
components: {
ManageAdd,
},
data() {
return {
visible: false,
name: '',
models: [
{ id: 0, value: '成果' },
{ id: 1, value: '仪器' },
{ id: 2, value: '实验室' },
],
};
},
methods: {
showModal() {
this.visible = true;
},
closeModal() {
this.visible = false;
},
handleChangeSelect(type, value) {
this[type] = value;
},
handleChangeName(value) {
console.log('value: ', value);
this.teamName = value;
},
async handleTableChange() {
console.log('搜索');
const { name, model } = this;
//
const condition = {
name,
model,
};
console.log(condition);
await this.$emit('selModelSearch', condition);
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus"></style>

126
src/components/Page/PageAdd.vue

@ -0,0 +1,126 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 添加 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="添加页面"
v-model="visible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 标题code -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="标题"
>
<a-cascader
:options="titles"
placeholder="标题"
v-decorator="['titleCode',{
rules: [
{ required: true, message: '标题不能为空' },
],
}]"
/>
</a-form-item>
<!-- 内容 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="内容"
>
<quill-editor
:options="editorOption"
class="editor"
placeholder="请在此输入文本..."
v-model="content"
></quill-editor>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { mapState } from 'vuex';
import { addPage } from 'config/api';
import { quillEditor } from 'vue-quill-editor';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'PageAdd',
props: { visible: { type: Boolean, default: false } },
components: {
quillEditor, //
},
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'page-add' }),
editorOption: {
placeholder: '请在此输入文本...',
modules: {
toolbar: [
['bold', 'italic', 'underline', 'strike'], // toggled buttons
[{ header: 1 }, { header: 2 }],
[{ list: 'ordered' }, { list: 'bullet' }],
[{ indent: '-1' }, { indent: '+1' }],
['image'],
],
},
},
content: '',
};
},
computed: mapState(['titles']),
methods: {
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
if (values.titleCode.length > 1) {
values.titleCode = `${values.titleCode[0]}-${values.titleCode[1]}`;
} else {
values.titleCode = `${values.titleCode[0]}`;
}
const param = values;
param.content = this.content;
const params = { param };
console.log('params: ', params);
const res = await addPage(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('添加成功');
this.$emit('closeModal');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '添加失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

175
src/components/Page/PageDate.vue

@ -0,0 +1,175 @@
<template>
<div class="main flex-1">
<a-spin :spinning="showEdit">
<div style="width: 100%" v-if="lists && lists.length > 0">
<a-table
:columns="columns"
:data-source="lists"
:loading="loading"
:pagination="pagination"
:row-key="record => record.id"
:scroll="{ y: height }"
@change="handleTableChange"
@expand="getDetail"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<template slot="edit" slot-scope="text, record">
<a-icon @click="showEditModal(record)" class="pointer" theme="twoTone" type="edit" />
<a-popconfirm @confirm="() => onDelete(record.id)" title="确定要删除这一条?" v-if="lists.length">
<a-icon class="ml-4 pointer" theme="twoTone" two-tone-color="#ff0000" type="delete" />
</a-popconfirm>
</template>
<div class="d-flex flex-nowrap justify-space-between" slot="expandedRowRender" slot-scope="record" style="margin: 0">
<div>
<a-spin :spinning="spinning" tip="详情加载中...">
内容
<span v-dompurify-html="record.content" v-if="record.content"></span>
<span v-else>暂无内容</span>
</a-spin>
</div>
</div>
</a-table>
</div>
<a-empty v-else />
<!-- 编辑 -->
<page-edit :editItem="editItem" :editVisible="editVisible" @closeModal="closeModal" @getPageList="getPageList" />
</a-spin>
</div>
</template>
<script>
import PageEdit from 'components/Page/PageEdit.vue';
import { deletePage, getPage } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: 80,
scopedSlots: { customRender: 'id' },
},
{
title: '标题',
align: 'center',
dataIndex: 'titleCode',
key: 'titleCode',
},
{
title: '编辑',
align: 'center',
dataIndex: 'edit',
key: 'edit',
width: 150,
scopedSlots: { customRender: 'edit' },
},
];
export default {
name: 'PageDate',
components: {
PageEdit,
},
props: { lists: { type: Array, default: () => [] }, pagination: { type: Object, default: () => {} } },
data() {
return {
columns,
loading: false,
height: '',
editVisible: false,
editItem: {}, //
spinning: false,
showEdit: false,
};
},
mounted() {
let th = 250;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
async showEditModal(record) {
this.showEdit = true;
await this.getDetail(true, record);
this.showEdit = false;
this.editItem = record;
this.editVisible = true;
},
closeModal() {
this.editVisible = false;
},
async getPageList() {
await this.$emit('getPageList');
},
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('getPageList', condition);
},
//
async onDelete(id) {
try {
const params = { param: { id } };
const res = await deletePage(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('删除成功');
await this.$emit('getPageList');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '删除失败');
}
},
//
async getDetail(expanded, record) {
if (!expanded) return;
try {
this.spinning = true;
const params = { param: { id: record.id } };
const res = await getPage(params);
const { data, msg, code } = res.data;
this.spinning = false;
if (code === 200) {
const item = this.lists.find(item => item.id === record.id);
item.content = data.content;
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '查询失败');
}
},
//
openSignUp() {
const { query } = this.$route;
this.$router.push({ path: '/sign-up', query });
},
},
};
</script>
<style scoped lang="stylus"></style>

131
src/components/Page/PageEdit.vue

@ -0,0 +1,131 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 编辑 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="修改页面"
v-model="editVisible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 标题code -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="标题"
v-model="edtiTitleCode"
>
<a-cascader :options="titles" :placeholder="titleCode" @change="onChange" />
</a-form-item>
<!-- 内容 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="内容"
>
<quill-editor
:max-size="maxSize"
:value="editItem && (editItem.content ? editItem.content : '')"
@changeInput="changeInput"
/>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="closeModal" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { mapState } from 'vuex';
import { updatePage } from 'config/api';
import QuillEditor from 'components/QuillEditor/QuillEditor.vue';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'PageEdit',
props: { editVisible: { type: Boolean, default: false }, editItem: { type: Object, default: () => {} } },
components: { QuillEditor },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'r-d-add' }),
maxSize: 2048,
content: '',
titleCode: '',
edtiTitleCode: '',
};
},
computed: {
...mapState(['titles']),
},
watch: {
editVisible(value) {
if (value === true && this.editItem && this.editItem.titleCode) {
this.titleCode = this.editItem.titleCode.replace(/-/g, ' / ');
}
},
},
methods: {
//
changeInput(value) {
this.content = value;
},
onChange(value) {
if (value.length > 1) {
this.edtiTitleCode = `${value[0]}-${value[1]}`;
} else {
this.edtiTitleCode = `${value[0]}`;
}
},
closeModal() {
this.$emit('closeModal');
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const { content, editItem, edtiTitleCode } = this;
const params = { param: { content, id: editItem.id, titleCode: edtiTitleCode || editItem.titleCode } };
const res = await updatePage(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('修改成功');
this.$emit('getPageList');
} else {
throw msg;
}
this.$emit('closeModal');
} catch (error) {
this.$emit('closeModal');
this.$message.error(error || '修改失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

51
src/components/Page/PageSearch.vue

@ -0,0 +1,51 @@
<template>
<div class="d-flex flex-wrap pb-3">
<div class="d-flex flex-row">
<!-- 模块 -->
<a-input placeholder="标题code" v-model="titleCode" />
<a-button @click="handleTableChange" class="mx-2" type="primary">搜索</a-button>
</div>
<div class="flex-1"></div>
<a-button @click="showModal" class="editable-add-btn" type="primary">增加</a-button>
<!-- 添加 -->
<page-add :visible="visible" @closeModal="closeModal" />
</div>
</template>
<script>
import PageAdd from 'components/Page/PageAdd.vue';
export default {
name: 'PageSearch',
components: {
PageAdd,
},
data() {
return {
visible: false,
titleCode: '',
};
},
methods: {
showModal() {
this.visible = true;
},
closeModal() {
this.visible = false;
},
handleTableChange() {
const condition = { titleCode: this.titleCode };
this.$emit('getPageList', condition);
},
},
};
</script>
<style scoped lang="stylus"></style>

167
src/components/Partner/PartnerAdd.vue

@ -0,0 +1,167 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 添加 -->
<a-modal
:maskClosable="false"
:title="`添加${partnerOptions.type === 1 ? '合作伙伴' : '衍生企业'} `"
@cancel="$emit('closeModal')"
destroyOnClose
footer
v-model="visible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit">
<!-- 公司名称 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="公司名称">
<a-input
placeholder="公司名称"
v-decorator="[
'name',
{
rules: [
{ required: true, message: '公司名称不能为空' },
{ whitespace: true, message: '公司名称不能为空' },
{ max: 140, massage: '公司名称最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- logo -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="公司logo" required>
<a-upload :action="upload" :before-upload="beforeUpload" @change="handleChange" list-type="picture" name="files">
<a-button v-show="fileList.length - 0 === 0"> <a-icon type="upload" />选择图片 </a-button>
</a-upload>
</a-form-item>
<!-- 公司类型 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="公司类型" required>
<a-select @change="getStatus" placeholder="公司类型" style="width: 100%">
<a-select-option :key="index" :value="item.id" v-for="(item, index) in policyStatus">{{ item.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 公司简介 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="公司简介">
<quill-editor :max-size="maxSize" :placeholder="placeholder" @changeInput="changeInput" />
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { mapState } from 'vuex';
import { upload, backendAdd } from 'config/api';
import QuillEditor from 'components/QuillEditor/QuillEditor.vue';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'PartnerAdd',
props: { visible: { type: Boolean, default: false } },
components: { QuillEditor },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'activity-add' }),
maxSize: 2048,
description: '',
placeholder: '请输入...',
policyStatus: [
{ id: 0, value: '高校' },
{ id: 1, value: '院所' },
{ id: 2, value: '企业' },
],
typeOfTech: '',
upload: upload,
fileList: [],
//
beforeUpload: file => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('仅支持 JPG/PNG 格式的图片!');
}
return isJpgOrPng;
},
};
},
computed: mapState(['partnerOptions']),
methods: {
//
getStatus(value) {
this.typeOfTech = value;
},
//
handleChange(info) {
if (info.file.status === 'done') {
this.fileList.push(info.file.response.data[0].id);
} else if (info.file.status === 'removed') {
this.fileList = info.fileList;
}
},
//
changeInput(value) {
this.description = value;
},
//
verification() {
const { typeOfTech, fileList } = this;
if (fileList.length < 1) {
this.$message.error('请选择公司logo');
return false;
}
if (typeOfTech === '') {
this.$message.error('请选择公司类型');
return false;
}
return true;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
if (!this.verification()) return;
const { name } = values;
const { description, typeOfTech, fileList, partnerOptions } = this;
const params = { param: { name, type: partnerOptions.type, typeOfPlatform: partnerOptions.typeOfPlatform } };
params.param.description = description;
params.param.typeOfTech = typeOfTech;
params.param.logo = fileList[0];
const res = await backendAdd(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('添加成功');
this.fileList = [];
this.$emit('getBackendSearch');
} else {
throw msg;
}
this.$emit('closeModal');
} catch (error) {
this.$emit('closeModal');
this.$message.error(error || '添加失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

206
src/components/Partner/PartnerDate.vue

@ -0,0 +1,206 @@
<template>
<div class="main flex-1">
<div style="width:100%" v-if="lists && lists.length > 0">
<a-table
:columns="columns"
:data-source="lists"
:loading="loading"
:pagination="pagination"
:row-key="record => record.id"
:scroll="{ y: height }"
@change="handleTableChange"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<!-- logo地址 -->
<template slot="logoUrl" slot-scope="text, record">
<img :src="record.logoUrl" height="50" width="50" />
</template>
<!-- 合作关系 -->
<template slot="type" slot-scope="text">
<span>{{ text === 1 ? '合作伙伴' : text === 2 ? '衍生企业' : '' }}</span>
</template>
<!-- 展示位置 -->
<template slot="typeOfPlatform" slot-scope="text">
<span>{{ text === 1 ? '产业平台' : text === 2 ? '关于我们' : text === 3 ? '孵化平台' : '' }}</span>
</template>
<!-- 公司类型 -->
<template slot="typeOfTech" slot-scope="text">
<span>{{ text === 0 ? '高校' : text === 1 ? '院所' : text === 2 ? '企业' : '' }}</span>
</template>
<template slot="edit" slot-scope="text, record">
<a-icon @click="showEditModal(record)" class="pointer" theme="twoTone" type="edit" />
<a-popconfirm @confirm="() => onDelete(record.id)" title="确定要删除这一条?" v-if="lists.length">
<a-icon class="ml-4 pointer" theme="twoTone" two-tone-color="#ff0000" type="delete" />
</a-popconfirm>
</template>
<div slot="expandedRowRender" slot-scope="record" style="margin: 0">
<div>
<span class="font-bold-14">简介</span>
<span v-dompurify-html="record.description"></span>
</div>
</div>
</a-table>
</div>
<a-empty v-else />
<!-- 编辑 -->
<partner-edit
:editItem="editItem"
:editVisible="editVisible"
@closeModal="closeModal"
@getBackendSearch="getBackendSearch"
/>
</div>
</template>
<script>
import PartnerEdit from 'components/Partner/PartnerEdit.vue';
import { backendDelete } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
scopedSlots: { customRender: 'id' },
},
{
title: 'logo',
align: 'center',
dataIndex: 'logoUrl',
key: 'logoUrl',
scopedSlots: { customRender: 'logoUrl' },
},
{
title: '公司名',
align: 'center',
dataIndex: 'name',
key: 'name',
},
{
title: '合作关系',
align: 'center',
dataIndex: 'type',
key: 'type',
scopedSlots: { customRender: 'type' },
},
{
title: '展示位置',
align: 'center',
dataIndex: 'typeOfPlatform',
key: 'typeOfPlatform',
scopedSlots: { customRender: 'typeOfPlatform' },
},
{
title: '公司类型',
align: 'center',
dataIndex: 'typeOfTech',
key: 'typeOfTech',
scopedSlots: { customRender: 'typeOfTech' },
},
{
title: '编辑',
align: 'center',
dataIndex: 'edit',
key: 'edit',
width: 200,
scopedSlots: { customRender: 'edit' },
},
];
export default {
name: 'PartnerDate',
components: {
PartnerEdit,
},
props: { lists: { type: Array, default: () => [] }, pagination: { type: Object, default: () => {} } },
data() {
return {
columns,
loading: false,
height: '',
editVisible: false,
editItem: null, //
};
},
mounted() {
let th = 250;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
showEditModal(record) {
this.editItem = record;
this.editVisible = true;
},
closeModal() {
this.editVisible = false;
},
async getBackendSearch() {
await this.$emit('getBackendSearch');
},
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('getBackendSearch', condition);
},
//
async onDelete(id) {
try {
const params = { param: { id } };
const res = await backendDelete(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('删除成功');
this.$emit('getBackendSearch');
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '删除失败');
}
},
//
openSignUp() {
const { query } = this.$route;
this.$router.push({ path: '/sign-up', query });
},
},
};
</script>
<style lang="stylus" scoped>
.main .img {
height: 65px;
}
.main .big_img {
width: 200px;
}
</style>

199
src/components/Partner/PartnerEdit.vue

@ -0,0 +1,199 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 编辑 -->
<a-modal
:maskClosable="false"
:title="`修改${partnerOptions.type === 1 ? '合作伙伴' : '衍生企业'} `"
@cancel="$emit('closeModal')"
destroyOnClose
footer
v-model="editVisible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit" v-if="editItem">
<!-- 公司名称 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="公司名称"
>
<a-input
placeholder="公司名称"
v-decorator="[
'name',
{
initialValue: editItem.name,
rules: [
{ required: true, message: '公司名称不能为空' },
{ whitespace: true, message: '公司名称不能为空' },
{ max: 140, massage: '公司名称最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- logo -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="公司logo"
required
>
<a-upload
:action="upload"
:before-upload="beforeUpload"
@change="handleChange"
list-type="picture"
name="files"
>
<a-button v-show="fileList.length - 0 === 0">
<a-icon type="upload" />选择图片
</a-button>
</a-upload>
</a-form-item>
<!-- 公司类型 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="公司类型"
required
>
<a-select
@change="getStatus"
placeholder="公司类型"
style="width: 100%"
v-decorator="[
'typeOfTech',
{
initialValue: editItem.typeOfTech,
},
]"
>
<a-select-option
:key="index"
:value="item.id"
v-for="(item, index) in policyStatus"
>{{ item.value }}</a-select-option>
</a-select>
</a-form-item>
<!-- 公司简介 -->
<a-form-item
:label-col="formItemLayout.labelCol"
:wrapper-col="formItemLayout.wrapperCol"
label="公司简介"
>
<quill-editor
:max-size="maxSize"
:value="editItem && (editItem.description ? editItem.description : '')"
@changeInput="changeInput"
/>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { mapState } from 'vuex';
import { upload, backendUpdate } from 'config/api';
import QuillEditor from 'components/QuillEditor/QuillEditor.vue';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'PartnerEdit',
props: { editVisible: { type: Boolean, default: false }, editItem: { type: Object, default: () => {} } },
components: { QuillEditor },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'r-d-add' }),
maxSize: 2048,
description: '',
placeholder: '请输入...',
policyStatus: [
{ id: 0, value: '高校' },
{ id: 1, value: '院所' },
{ id: 2, value: '企业' },
],
typeOfTech: '',
upload: upload,
fileList: [],
//
beforeUpload: file => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('仅支持 JPG/PNG 格式的图片!');
}
return isJpgOrPng;
},
};
},
computed: mapState(['partnerOptions']),
methods: {
//
getStatus(value) {
this.typeOfTech = value;
},
//
handleChange(info) {
if (info.file.status === 'done') {
this.fileList.push(info.file.response.data[0].id);
} else if (info.file.status === 'removed') {
this.fileList = info.fileList;
}
},
//
changeInput(value) {
this.description = value;
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const { name } = values;
const { description, typeOfTech, fileList, editItem } = this;
const params = { param: { name } };
params.param.id = editItem.id;
params.param.description = description ? description : editItem.description;
params.param.typeOfTech = typeOfTech ? typeOfTech : editItem.typeOfTech;
params.param.logo = fileList && fileList.length > 0 ? fileList[0] : editItem.logo;
const res = await backendUpdate(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('修改成功');
this.$emit('getBackendSearch');
} else {
throw msg;
}
this.$emit('closeModal');
} catch (error) {
this.$emit('closeModal');
this.$message.error(error || '修改失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

87
src/components/Partner/PartnerSearch.vue

@ -0,0 +1,87 @@
<template>
<div class="d-flex flex-wrap pb-3">
<div>
<!-- 活动标题 -->
<a-input class="ml-3" placeholder="标题" style="width: 150px" v-model="name" />
<!-- 公司类型 -->
<a-select
@change="changeState"
allow-clear
class="ml-3 mb-3"
placeholder="公司类型"
style="width: 150px"
>
<a-select-option
:key="index"
:value="state.id"
v-for="(state, index) in policyStatus"
>{{ state.value }}</a-select-option>
</a-select>
<a-button @click="handleTableChange" class="mx-2" type="primary">搜索</a-button>
</div>
<div class="flex-1"></div>
<a-button @click="showModal" class="editable-add-btn" type="primary">增加</a-button>
<!-- 添加 -->
<partner-add :visible="visible" @closeModal="closeModal" @getBackendSearch="getBackendSearch" />
</div>
</template>
<script>
import PartnerAdd from 'components/Partner/PartnerAdd.vue';
export default {
name: 'PartnerSearch',
components: {
PartnerAdd,
},
data() {
return {
visible: false,
name: '',
policyStatus: [
{ id: 0, value: '高校' },
{ id: 1, value: '院所' },
{ id: 2, value: '企业' },
],
typeOfTech: '',
};
},
methods: {
//
changeState(value) {
this.typeOfTech = value;
},
showModal() {
this.visible = true;
},
closeModal() {
this.visible = false;
},
async getBackendSearch() {
await this.$emit('getBackendSearch');
},
async handleTableChange() {
const { name, typeOfTech } = this;
//
const condition = {
name,
typeOfTech,
};
await this.$emit('getBackendSearch', condition);
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus"></style>

190
src/components/Policy/PolicyAdd.vue

@ -0,0 +1,190 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 添加 -->
<a-modal :maskClosable="false" @cancel="$emit('closeModal')" destroyOnClose footer title="添加创新政策" v-model="visible" width="700px">
<a-form :form="form" @submit="handleSubmit">
<!-- 标题 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="标题">
<a-input
placeholder="标题"
v-decorator="[
'title',
{
rules: [
{ required: true, message: '标题不能为空' },
{ whitespace: true, message: '标题不能为空' },
{ max: 140, massage: '标题最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 发布部门 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="发布部门">
<a-cascader
style="width: 200px"
:field-names="{ label: 'areaName', value: 'id', children: 'next' }"
:options="options"
:display-render="displayRender"
expand-trigger="hover"
placeholder="请选择发布部门"
@change="changeQues"
/>
</a-form-item>
<!-- 发布时间 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="发布时间" required>
<a-date-picker @change="onChange" format="YYYY-MM-DD" show-time style="width: 100%" />
</a-form-item>
<!-- 审核状态 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="审核状态" required>
<a-select @change="getStatus" placeholder="审核状态" style="width: 200px">
<a-select-option :key="index" :value="item.id" v-for="(item, index) in applyStatus">{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<!-- 原文链接 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="原文链接">
<a-input placeholder="原文链接" v-decorator="['url']" />
</a-form-item>
<!-- 政策内容 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="政策内容" required>
<quill-editor :max-size="maxSize" :placeholder="placeholder" @changeInput="changeInput" />
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { addPolicy, getAreaBranch } from 'config/api';
import QuillEditor from 'components/QuillEditor/QuillEditor.vue';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'PolicyAdd',
props: { visible: { type: Boolean, default: false } },
components: { QuillEditor },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'policy-edit' }),
applyStatus: [
{ id: 0, name: '审核中' },
{ id: 1, name: '未通过' },
{ id: 2, name: '已通过' },
],
status: null,
maxSize: 2048,
content: '',
placeholder: '请输入...',
pushTime: '', //
options: [],
areaId: '',
};
},
async created() {
await this.getArea();
},
methods: {
//
getStatus(value) {
console.log('value: ', value);
this.status = value;
},
//
changeInput(value) {
this.content = value;
},
//
onChange(date, dateString) {
console.log(date, dateString);
this.pushTime = dateString;
},
//
verification() {
if (!this.pushTime) {
this.$message.error('发布时间不能为空');
return false;
}
if (this.status === null) {
this.$message.error('审核状态不能为空');
return false;
}
if (!this.content) {
this.$message.error('政策内容不能为空');
return false;
}
return true;
},
//
async getArea() {
try {
const res = await getAreaBranch();
const { code, msg, data } = res.data;
if (code === 200) {
// console.log(data);
this.options = data;
} else {
this.$message.error(msg);
}
} catch (error) {
this.$message.error(error);
}
},
//
changeQues(value) {
this.areaId = value[value.length - 1];
// console.log(value[value.length - 1]);
},
displayRender({ labels }) {
return labels[labels.length - 1];
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
if (!this.verification()) return;
const { pushTime, status, content, areaId } = this;
const params = { param: values };
params.param.pushTime = pushTime;
params.param.status = status;
params.param.content = content;
params.param.pushDep = areaId;
console.log('params: ', params);
const res = await addPolicy(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('添加成功');
this.$emit('getSelectTeam');
} else {
throw msg;
}
this.$emit('closeModal');
} catch (error) {
this.$emit('closeModal');
this.$message.error(error || '添加失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

238
src/components/Policy/PolicyDate.vue

@ -0,0 +1,238 @@
<template>
<div class="main flex-1">
<div style="width:100%" v-if="lists && lists.length > 0">
<div class="mb-4">
<a-button :disabled="!hasSelected" :loading="loading" @click="start(2)" type="primary">审核通过</a-button>
<a-button
:disabled="!hasSelected"
:loading="loading"
@click="start(1)"
class="ml-3"
type="danger"
>审核不通过</a-button>
<span class="ml-2">
<template v-if="hasSelected">{{ `选中 ${selectedRowKeys.length} ` }}</template>
</span>
</div>
<a-table
:columns="columns"
:data-source="lists"
:loading="loading"
:pagination="pagination"
:row-key="record => record.id"
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
:scroll="{ y: height }"
@change="handleTableChange"
bordered
class="white"
>
<template slot="id" slot-scope="text, record, index">
<span>{{ index + 1 }}</span>
</template>
<template slot="type" slot-scope="text, record">
<a-tag
color="blue"
>{{ record.type === 0 ? '申报通知' : record.type === 1 ? '公告公示' : record.type === 2 ? '政策动态' : record.type === 3 ? '申报指南' : '' }}</a-tag>
</template>
<template slot="status" slot-scope="text, record">
<a-tag
:color="record.status === 2 ? 'green' : record.status === 1 ? 'red' : 'blue'"
>{{ record.status === 2 ? '已通过' : record.status === 1 ? '未通过' : '审核中' }}</a-tag>
</template>
<template slot="edit" slot-scope="text, record">
<a-icon @click="showEditModal(record)" class="pointer" theme="twoTone" type="edit" />
</template>
<div
class="d-flex flex-column"
slot="expandedRowRender"
slot-scope="record"
style="margin: 0"
>
<div class="mb-3">
<span class="font-bold-14">原文链接</span>
{{ record.titleUrl }}
</div>
<div class="mb-3">
<span class="font-bold-14">简介</span>
<br />
<span v-if="record.intro">{{ record.intro }}</span>
<span v-else>暂无内容</span>
</div>
<div>
<span class="font-bold-14">详情</span>
<span v-dompurify-html="record.content" v-if="record.content"></span>
<span v-else>暂无内容</span>
</div>
</div>
</a-table>
</div>
<a-empty v-else />
<!-- 编辑 -->
<policy-edit
:editItem="editItem"
:editVisible="editVisible"
@closeModal="closeModal"
@getSelectTeam="getSelectTeam"
/>
</div>
</template>
<script>
import PolicyEdit from 'components/Policy/PolicyEdit.vue';
import { upPolicy } from 'config/api';
const columns = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
width: 80,
scopedSlots: { customRender: 'id' },
},
{
title: '标题',
align: 'center',
dataIndex: 'title',
key: 'title',
},
{
title: '发布部门',
align: 'center',
dataIndex: 'publishDepartName',
key: 'publishDepartName',
},
{
title: '政策类型',
align: 'center',
dataIndex: 'type',
key: 'type',
width: 100,
scopedSlots: { customRender: 'type' },
},
{
title: '状态',
align: 'center',
dataIndex: 'status',
key: 'status',
width: 100,
scopedSlots: { customRender: 'status' },
},
{
title: '发布时间',
align: 'center',
dataIndex: 'publishTime',
key: 'publishTime',
},
{
title: '编辑',
align: 'center',
dataIndex: 'edit',
key: 'edit',
width: 80,
scopedSlots: { customRender: 'edit' },
},
];
export default {
name: 'PolicyDate',
props: { lists: { type: Array, default: () => [] }, pagination: { type: Object, default: () => {} } },
components: {
PolicyEdit,
},
data() {
return {
columns,
loading: false,
selectedRowKeys: [],
editingKey: '',
height: '',
editVisible: false,
editItem: null, //
};
},
computed: {
hasSelected() {
return this.selectedRowKeys.length > 0;
},
},
mounted() {
let th = 300;
let wh = window.innerHeight;
this.height = wh - th;
window.onresize = () => {
return (() => {
wh = window.innerHeight;
this.height = wh - th;
})();
};
},
methods: {
//
onSelectChange(selectedRowKeys) {
console.log('selectedRowKeys changed: ', selectedRowKeys);
this.selectedRowKeys = selectedRowKeys;
},
//
handleTableChange(pagination) {
const { current, pageSize } = pagination;
const condition = { current, pageSize };
this.$emit('getSelectTeam', condition);
},
//
async start(state) {
try {
this.loading = true;
const params = { param: { ids: this.selectedRowKeys, status: state } };
const res = await upPolicy(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('审批成功');
this.$emit('getSelectTeam');
setTimeout(() => {
this.loading = false;
this.selectedRowKeys = [];
}, 1000);
} else {
throw msg;
}
} catch (error) {
this.$message.error(error || '审批失败');
}
},
showEditModal(record) {
console.log('record: ', record);
this.editItem = record;
this.editVisible = true;
},
closeModal() {
this.editVisible = false;
},
async getSelectTeam() {
await this.$emit('getSelectTeam');
},
//
openSignUp() {
const { query } = this.$route;
this.$router.push({ path: '/sign-up', query });
},
},
};
</script>
<style scoped lang="stylus"></style>

219
src/components/Policy/PolicyEdit.vue

@ -0,0 +1,219 @@
<template>
<div class="d-flex flex-wrap pb-3">
<!-- 编辑 -->
<a-modal
:maskClosable="false"
@cancel="$emit('closeModal')"
destroyOnClose
footer
title="修改创新政策"
v-model="editVisible"
width="700px"
>
<a-form :form="form" @submit="handleSubmit" v-if="editVisible && editItem">
<!-- 标题 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="标题">
<a-input
placeholder="标题"
v-decorator="[
'title',
{
initialValue: editItem.title,
rules: [
{ required: true, message: '标题不能为空' },
{ whitespace: true, message: '标题不能为空' },
{ max: 140, massage: '标题最多140个字符' },
],
},
]"
/>
</a-form-item>
<!-- 发布部门 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="发布部门">
<a-cascader
style="width: 200px"
:field-names="{ label: 'areaName', value: 'id', children: 'next' }"
:options="options"
:display-render="displayRender"
expand-trigger="hover"
placeholder="请选择发布部门"
@change="changeQues"
/>
</a-form-item>
<!-- 发布时间 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="发布时间" required>
<a-date-picker
@change="onChange"
format="YYYY-MM-DD"
show-time
style="width: 100%"
v-decorator="[
'pushTime',
{
initialValue: editItem.publishTime,
rules: [{ required: true, message: '发布时间不能为空' }],
},
]"
/>
</a-form-item>
<!-- 审核状态 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="审核状态">
<a-select
@change="getStatus"
placeholder="审核状态"
style="width: 200px"
v-decorator="[
'status',
{
initialValue: editItem.status,
rules: [{ required: true, message: '审核状态不能为空' }],
},
]"
>
<a-select-option :key="index" :value="item.id" v-for="(item, index) in applyStatus">{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<!-- 原文链接 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="原文链接">
<a-input
placeholder="原文链接"
v-decorator="[
'url',
{
initialValue: editItem.titleUrl,
},
]"
/>
</a-form-item>
<!-- 政策内容 -->
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="政策内容" required>
<quill-editor
:max-size="maxSize"
:placeholder="placeholder"
:value="editItem && editItem.content ? editItem.content : content"
@changeInput="changeInput"
/>
</a-form-item>
<a-form-item class="d-flex flex-row-reverse">
<a-button @click="$emit('closeModal')" class="mr-3">取消</a-button>
<a-button class="white--text" html-type="submit" type="primary">保存</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import { addPolicy, getAreaBranch } from 'config/api';
import QuillEditor from 'components/QuillEditor/QuillEditor.vue';
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const tailItemLayout = { wrapperCol: { span: 16, offset: 6 } };
export default {
name: 'PolicyEdit',
props: { editVisible: { type: Boolean, default: false }, editItem: { type: Object, default: () => {} } },
components: { QuillEditor },
data() {
return {
formItemLayout,
tailItemLayout,
form: this.$form.createForm(this, { name: 'policy-edit' }),
applyStatus: [
{ id: 0, name: '审核中' },
{ id: 1, name: '未通过' },
{ id: 2, name: '已通过' },
],
status: null,
maxSize: 2048,
content: '',
placeholder: '请输入...',
pushTime: '', //
options: [],
areaId: '',
};
},
async created() {
await this.getArea();
},
methods: {
//
getStatus(value) {
this.status = value;
},
//
changeInput(value) {
this.content = value;
},
//
onChange(date, dateString) {
console.log(date, dateString);
this.pushTime = dateString;
},
//
async getArea() {
try {
const res = await getAreaBranch();
const { code, msg, data } = res.data;
if (code === 200) {
// console.log(data);
this.options = data;
} else {
this.$message.error(msg);
}
} catch (error) {
this.$message.error(error);
}
},
//
changeQues(value) {
this.areaId = value[value.length - 1];
// console.log(value[value.length - 1]);
},
displayRender({ labels }) {
return labels[labels.length - 1];
},
//
handleSubmit(e) {
e.preventDefault();
this.form.validateFieldsAndScroll(async (err, values) => {
if (!err) {
try {
const { pushTime, status, content, editItem, areaId } = this;
const params = { param: values };
params.param.id = editItem.id;
params.param.pushTime = pushTime || editItem.publishTime;
params.param.status = status || editItem.status;
params.param.content = content || editItem.content;
params.param.pushDep = areaId || editItem.publishDepartId;
const res = await addPolicy(params);
const { data, msg, code } = res.data;
if (code === 200) {
this.$message.success('修改成功');
this.$emit('getSelectTeam');
} else {
throw msg;
}
this.$emit('closeModal');
} catch (error) {
this.$emit('closeModal');
this.$message.error(error || '修改失败');
}
}
});
},
},
};
</script>
<style scoped lang="stylus"></style>

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

Loading…
Cancel
Save