vue2-client 1.6.5 → 1.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,7 +1,10 @@
1
1
  # Change Log
2
2
  > 所有关于本项目的变化都在该文档里。
3
3
 
4
- **1.6.5 -2022-12-28 @江超**
4
+ **1.6.7 -2023-01-06 @江超**
5
+ - 解决单页面是最后一个页面的情况下点击关闭出现白屏的问题
6
+
7
+ **1.6.5 - 1.6.6 -2022-12-28 @江超**
5
8
  - 解决树型选择框不兼容主子表结构数据源的问题
6
9
 
7
10
  **1.6.4 -2022-12-28 @江超**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue2-client",
3
- "version": "1.6.5",
3
+ "version": "1.6.7",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -1,246 +1,247 @@
1
- <template>
2
- <div>
3
- <a-cascader
4
- v-if="type === 'cascader'"
5
- :options="tagData.divisionsForTree"
6
- :placeholder="placeholder"
7
- style="width: 100%;"
8
- :size="size"
9
- />
10
- <a-select
11
- ref="select"
12
- :size="size"
13
- :value="valueView"
14
- style="width: 100%;"
15
- :dropdownMatchSelectWidth="false"
16
- :dropdownStyle="dropdownStyle"
17
- :placeholder="placeholder"
18
- @blur="selectBlurHandle"
19
- :getPopupContainer=" triggerNode => { return triggerNode.parentNode } "
20
- :style="inputStyle">
21
- <div slot="dropdownRender" @mousedown.prevent>
22
- <a-tabs v-model="activeKey" :size="size">
23
- <a-tab-pane
24
- :tab="view.key"
25
- v-for="(view,index) in viewArr"
26
- :key="view.key"
27
- v-if="contexts > index"
28
- :disabled="tagData[view.value].length === 0">
29
-
30
- <a-checkable-tag
31
- :style="tagStyle"
32
- v-for="item of tagData[view.value]"
33
- :key="item.code"
34
- @change="tagClick(view.key,item)">
35
- <a-tooltip
36
- placement="top"
37
- :mouseEnterDelay="0.5"
38
- :title="item.name"
39
- :getPopupContainer=" triggerNode => { return triggerNode.parentElement } "
40
- >
41
- {{ item.name.length > 8 ?`${item.name.slice(0, 8)}...`:item.name }}
42
- </a-tooltip>
43
- </a-checkable-tag>
44
- </a-tab-pane>
45
- </a-tabs>
46
- </div>
47
- </a-select>
48
- </div>
49
- </template>
50
-
51
- <script>
52
- const viewArr = [
53
- {
54
- key: '省/直辖市',
55
- value: 'divisionsForTree',
56
- }, {
57
- key: '市',
58
- value: 'cityData',
59
- }, {
60
- key: '区',
61
- value: 'areaData',
62
- }, {
63
- key: '街道',
64
- value: 'streetData',
65
- }
66
- ]
67
- export default {
68
- name: 'CitySelect',
69
- data () {
70
- return {
71
- open: false,
72
- tagData: {
73
- divisionsForTree: [],
74
- //
75
- cityData: [],
76
- //
77
- areaData: [],
78
- // 街道
79
- streetData: [],
80
- },
81
- // model: {
82
- // provinceModel: { name: '', code: '' },
83
- // cityModel: { name: '', code: '' },
84
- // areaModel: { name: '', code: '' },
85
- // streetModel: { name: '', code: '' }
86
- // },
87
- model: [
88
- { name: '', code: '' },
89
- { name: '', code: '' },
90
- { name: '', code: '' },
91
- { name: '', code: '' }
92
- ],
93
- // 控制标签
94
- activeKey: '省/直辖市',
95
- // 遍历以渲染页面
96
- viewArr,
97
- // 框内显示值 valueView
98
- valueView: undefined
99
- }
100
- },
101
- mounted () {
102
- this.$appdata.getDivisionsOhChinaForTree().then(res => {
103
- this.tagData.divisionsForTree = res
104
- })
105
- },
106
- model: {
107
- prop: 'value',
108
- event: 'onChange'
109
- },
110
- computed: {},
111
- props: {
112
- // 页面渲染内容 默认 省市区街道 四个 所以是4
113
- contexts: {
114
- type: Number,
115
- default: 3
116
- },
117
- placeholder: {
118
- type: String,
119
- default: '请选择省市区'
120
- },
121
- // small lage 输入框大小
122
- size: {
123
- type: String,
124
- default: undefined
125
- },
126
- // 类型 simple / undefined
127
- // simple 就是用的 cascader 不穿就是用的 自己封装的
128
- type: {
129
- type: String,
130
- default: undefined
131
- },
132
- // 框的样式
133
- inputStyle: {
134
- type: Object,
135
- default: () => {
136
- }
137
- },
138
- // 下拉框的样式
139
- dropdownStyle: {
140
- type: Object,
141
- default: () => {
142
- return {
143
- width: '35rem',
144
- padding: '1%'
145
- }
146
- }
147
- },
148
- // 标签的样式
149
- tagStyle: {
150
- type: Object,
151
- default: () => {
152
- return {
153
- fontSize: '0.88rem',
154
- width: '23%',
155
- textAlign: 'left',
156
- margin: '0.5%',
157
- cursor: 'pointer'
158
- }
159
- }
160
- },
161
- // 用于v-model 绑定
162
- value: {
163
- type: String,
164
- default: undefined
165
- },
166
- // 用于v-model 绑定 code :最后一级的code address: 所有级拼接的地址
167
- valueType: {
168
- type: String,
169
- default: 'address'
170
- }
171
- },
172
- watch: {},
173
- methods: {
174
- tagClick (e, item) {
175
- if (e === '省/直辖市') {
176
- // 如果是同一个标签
177
- if (this.model[0].name !== item.name) {
178
- this.tagData.cityData = item.children
179
- this.tagData.areaData = []
180
- this.tagData.streetData = []
181
- this.model[0].name = item.name
182
- this.model[0].code = item.code
183
- this.model[1] = { name: '', code: '' }
184
- this.model[2] = { name: '', code: '' }
185
- this.model[3] = { name: '', code: '' }
186
- }
187
- if (this.contexts !== 1) {
188
- this.activeKey = '市'
189
- }
190
- this.getResultText(1)
191
- } else if (e === '市') {
192
- if (this.model[1].name !== item.name) {
193
- this.tagData.areaData = item.children
194
- this.tagData.streetData = []
195
- this.model[1].name = item.name
196
- this.model[1].code = item.code
197
- this.model[2] = { name: '', code: '' }
198
- this.model[3] = { name: '', code: '' }
199
- }
200
- if (this.contexts !== 2) {
201
- this.activeKey = '区'
202
- }
203
- this.getResultText(2)
204
- } else if (e === '区') {
205
- if (this.model[2].name !== item.name) {
206
- this.tagData.streetData = item.children
207
- this.model[2].name = item.name
208
- this.model[2].code = item.code
209
- this.model[3] = { name: '', code: '' }
210
- }
211
- if (this.contexts !== 3) {
212
- this.activeKey = '街道'
213
- }
214
- this.getResultText(3)
215
- } else if (e === '街道') {
216
- if (this.model[3].name !== item.name) {
217
- this.model[3].name = item.name
218
- this.model[3].code = item.code
219
- }
220
- this.getResultText(4)
221
- }
222
- },
223
- getResultText (tag) {
224
- const address = []
225
- let code = ''
226
- for (let i = 0; i < this.contexts; i++) {
227
- if (this.model[i].name && this.model[i].name !== '') {
228
- address.push(this.model[i].name)
229
- }
230
- code = this.model[i].code ?? ''
231
- }
232
- this.valueView = this.valueType === 'address' ? address.join('/') : code
233
- if (tag === this.contexts) {
234
- this.$refs.select.blur()
235
- this.$emit('onChange', this.valueType === 'address' ? address.join('') : code)
236
- }
237
- },
238
- // 失去焦点回调
239
- selectBlurHandle () {
240
- if (!this.model[this.contexts - 1].code || this.model[this.contexts - 1].code === '') {
241
- this.valueView = undefined
242
- }
243
- }
244
- }
245
- }
246
- </script>
1
+ <template>
2
+ <div>
3
+ <a-cascader
4
+ v-if="type === 'cascader'"
5
+ :options="tagData.divisionsForTree"
6
+ :placeholder="placeholder"
7
+ style="width: 100%;"
8
+ :size="size"
9
+ />
10
+ <a-select
11
+ ref="select"
12
+ :size="size"
13
+ v-model="valueView"
14
+ style="width: 100%;"
15
+ :dropdownMatchSelectWidth="false"
16
+ :dropdownStyle="dropdownStyle"
17
+ :placeholder="placeholder"
18
+ @blur="selectBlurHandle"
19
+ allow-clear
20
+ :getPopupContainer=" triggerNode => { return triggerNode.parentNode } "
21
+ :style="inputStyle">
22
+ <div slot="dropdownRender" @mousedown.prevent>
23
+ <a-tabs v-model="activeKey" :size="size">
24
+ <a-tab-pane
25
+ :tab="view.key"
26
+ v-for="(view,index) in viewArr"
27
+ :key="view.key"
28
+ v-if="contexts > index"
29
+ :disabled="tagData[view.value].length === 0">
30
+
31
+ <a-checkable-tag
32
+ :style="tagStyle"
33
+ v-for="item of tagData[view.value]"
34
+ :key="item.code"
35
+ @change="tagClick(view.key,item)">
36
+ <a-tooltip
37
+ placement="top"
38
+ :mouseEnterDelay="0.5"
39
+ :title="item.name"
40
+ :getPopupContainer=" triggerNode => { return triggerNode.parentElement } "
41
+ >
42
+ {{ item.name.length > 8 ?`${item.name.slice(0, 8)}...`:item.name }}
43
+ </a-tooltip>
44
+ </a-checkable-tag>
45
+ </a-tab-pane>
46
+ </a-tabs>
47
+ </div>
48
+ </a-select>
49
+ </div>
50
+ </template>
51
+
52
+ <script>
53
+ const viewArr = [
54
+ {
55
+ key: '省/直辖市',
56
+ value: 'divisionsForTree',
57
+ }, {
58
+ key: '',
59
+ value: 'cityData',
60
+ }, {
61
+ key: '',
62
+ value: 'areaData',
63
+ }, {
64
+ key: '街道',
65
+ value: 'streetData',
66
+ }
67
+ ]
68
+ export default {
69
+ name: 'CitySelect',
70
+ data () {
71
+ return {
72
+ open: false,
73
+ tagData: {
74
+ divisionsForTree: [],
75
+ //
76
+ cityData: [],
77
+ //
78
+ areaData: [],
79
+ // 街道
80
+ streetData: [],
81
+ },
82
+ // model: {
83
+ // provinceModel: { name: '', code: '' },
84
+ // cityModel: { name: '', code: '' },
85
+ // areaModel: { name: '', code: '' },
86
+ // streetModel: { name: '', code: '' }
87
+ // },
88
+ model: [
89
+ { name: '', code: '' },
90
+ { name: '', code: '' },
91
+ { name: '', code: '' },
92
+ { name: '', code: '' }
93
+ ],
94
+ // 控制标签
95
+ activeKey: '省/直辖市',
96
+ // 遍历以渲染页面
97
+ viewArr,
98
+ // 框内显示值 valueView
99
+ valueView: undefined
100
+ }
101
+ },
102
+ mounted () {
103
+ this.$appdata.getDivisionsOhChinaForTree().then(res => {
104
+ this.tagData.divisionsForTree = res
105
+ })
106
+ },
107
+ model: {
108
+ prop: 'value',
109
+ event: 'onChange'
110
+ },
111
+ computed: {},
112
+ props: {
113
+ // 页面渲染内容 默认 省市区街道 四个 所以是4
114
+ contexts: {
115
+ type: Number,
116
+ default: 3
117
+ },
118
+ placeholder: {
119
+ type: String,
120
+ default: '请选择省市区'
121
+ },
122
+ // small lage 输入框大小
123
+ size: {
124
+ type: String,
125
+ default: undefined
126
+ },
127
+ // 类型 simple / undefined
128
+ // simple 就是用的 cascader 不穿就是用的 自己封装的
129
+ type: {
130
+ type: String,
131
+ default: undefined
132
+ },
133
+ // 框的样式
134
+ inputStyle: {
135
+ type: Object,
136
+ default: () => {
137
+ }
138
+ },
139
+ // 下拉框的样式
140
+ dropdownStyle: {
141
+ type: Object,
142
+ default: () => {
143
+ return {
144
+ width: '35rem',
145
+ padding: '1%'
146
+ }
147
+ }
148
+ },
149
+ // 标签的样式
150
+ tagStyle: {
151
+ type: Object,
152
+ default: () => {
153
+ return {
154
+ fontSize: '0.88rem',
155
+ width: '23%',
156
+ textAlign: 'left',
157
+ margin: '0.5%',
158
+ cursor: 'pointer'
159
+ }
160
+ }
161
+ },
162
+ // 用于v-model 绑定
163
+ value: {
164
+ type: String,
165
+ default: undefined
166
+ },
167
+ // 用于v-model 绑定 code :最后一级的code address: 所有级拼接的地址
168
+ valueType: {
169
+ type: String,
170
+ default: 'address'
171
+ }
172
+ },
173
+ watch: {},
174
+ methods: {
175
+ tagClick (e, item) {
176
+ if (e === '省/直辖市') {
177
+ // 如果是同一个标签
178
+ if (this.model[0].name !== item.name) {
179
+ this.tagData.cityData = item.children
180
+ this.tagData.areaData = []
181
+ this.tagData.streetData = []
182
+ this.model[0].name = item.name
183
+ this.model[0].code = item.code
184
+ this.model[1] = { name: '', code: '' }
185
+ this.model[2] = { name: '', code: '' }
186
+ this.model[3] = { name: '', code: '' }
187
+ }
188
+ if (this.contexts !== 1) {
189
+ this.activeKey = '市'
190
+ }
191
+ this.getResultText(1)
192
+ } else if (e === '市') {
193
+ if (this.model[1].name !== item.name) {
194
+ this.tagData.areaData = item.children
195
+ this.tagData.streetData = []
196
+ this.model[1].name = item.name
197
+ this.model[1].code = item.code
198
+ this.model[2] = { name: '', code: '' }
199
+ this.model[3] = { name: '', code: '' }
200
+ }
201
+ if (this.contexts !== 2) {
202
+ this.activeKey = '区'
203
+ }
204
+ this.getResultText(2)
205
+ } else if (e === '区') {
206
+ if (this.model[2].name !== item.name) {
207
+ this.tagData.streetData = item.children
208
+ this.model[2].name = item.name
209
+ this.model[2].code = item.code
210
+ this.model[3] = { name: '', code: '' }
211
+ }
212
+ if (this.contexts !== 3) {
213
+ this.activeKey = '街道'
214
+ }
215
+ this.getResultText(3)
216
+ } else if (e === '街道') {
217
+ if (this.model[3].name !== item.name) {
218
+ this.model[3].name = item.name
219
+ this.model[3].code = item.code
220
+ }
221
+ this.getResultText(4)
222
+ }
223
+ },
224
+ getResultText (tag) {
225
+ const address = []
226
+ let code = ''
227
+ for (let i = 0; i < this.contexts; i++) {
228
+ if (this.model[i].name && this.model[i].name !== '') {
229
+ address.push(this.model[i].name)
230
+ }
231
+ code = this.model[i].code ?? ''
232
+ }
233
+ this.valueView = this.valueType === 'address' ? address.join('/') : code
234
+ if (tag === this.contexts) {
235
+ this.$refs.select.blur()
236
+ this.$emit('onChange', this.valueType === 'address' ? address.join('') : code)
237
+ }
238
+ },
239
+ // 失去焦点回调
240
+ selectBlurHandle () {
241
+ if (!this.model[this.contexts - 1].code || this.model[this.contexts - 1].code === '') {
242
+ this.valueView = undefined
243
+ }
244
+ }
245
+ }
246
+ }
247
+ </script>
@@ -563,8 +563,8 @@ export default {
563
563
  */
564
564
  setNodeData (data, node) {
565
565
  if (node.value) {
566
- const columnsName = node.dataRef['columns_name']
567
566
  const value = node.value
567
+ const columnsName = value.substring(0, value.indexOf('-'))
568
568
  data[columnsName] = value.substring(value.lastIndexOf('-') + 1)
569
569
  if (node.$parent) {
570
570
  this.setNodeData(data, node.$parent)
@@ -575,7 +575,8 @@ export default {
575
575
  if (node.children && node.children.length > 0) {
576
576
  return this.getNodeDataProps(node.children[0])
577
577
  }
578
- return node.node.data.props.columns_name
578
+ const value = node.node.key
579
+ return value.substring(0, value.indexOf('-'))
579
580
  }
580
581
  }
581
582
  }
@@ -584,7 +585,7 @@ export default {
584
585
  <style lang="less" scoped>
585
586
  .tree-select {
586
587
  /deep/ .ant-select-selection.ant-select-selection--multiple {
587
- max-height: 48px;
588
+ max-height: 32px;
588
589
  overflow-y: auto;
589
590
  }
590
591
  }
@@ -133,10 +133,10 @@ export default {
133
133
  this.$router.push(page.fullPath)
134
134
  },
135
135
  remove (key, next) {
136
- this.setSingle({ path: key, delete: true })
137
136
  if (this.pageList.length === 1) {
138
137
  return this.$message.warning(this.$t('warn'))
139
138
  }
139
+ this.setSingle({ path: key, delete: true })
140
140
  // 清除缓存
141
141
  let index = this.pageList.findIndex(item => item.path === key)
142
142
  this.clearCaches = this.pageList.splice(index, 1).map(page => page.cachedKey)
@@ -1,301 +1,311 @@
1
- import axios from 'axios'
2
- import Cookie from 'js-cookie'
3
- import { ACCESS_TOKEN, SYSTEM_VERSION, V4_ACCESS_TOKEN } from '@vue2-client/store/mutation-types'
4
- import notification from 'ant-design-vue/es/notification'
5
- import errorCode from '@vue2-client/utils/errorCode'
6
- import qs from 'qs'
7
- import { logout } from '@vue2-client/services/user'
8
-
9
- // 是否显示重新登录
10
- let isReloginShow
11
-
12
- axios.defaults.timeout = 5000
13
- axios.defaults.withCredentials = true
14
-
15
- // 认证类型
16
- const AUTH_TYPE = {
17
- BEARER: 'Bearer',
18
- BASIC: 'basic',
19
- AUTH1: 'auth1',
20
- AUTH2: 'auth2'
21
- }
22
-
23
- // http method
24
- const METHOD = {
25
- GET: 'get',
26
- POST: 'post',
27
- PUT: 'put',
28
- DELETE: 'delete'
29
- }
30
-
31
- /**
32
- * axios请求
33
- * @param url 请求地址
34
- * @param method {METHOD} http method
35
- * @param params 请求参数
36
- * @param config
37
- * @returns {Promise<AxiosResponse<T>>}
38
- */
39
- async function request (url, method, params, config) {
40
- switch (method) {
41
- case METHOD.GET:
42
- return axios.get(url, { params, ...config })
43
- case METHOD.POST:
44
- return axios.post(url, params, config)
45
- case METHOD.PUT:
46
- return axios.put(url, params, config)
47
- case METHOD.DELETE:
48
- return axios.delete(url, config)
49
- default:
50
- return axios.get(url, { params, ...config })
51
- }
52
- }
53
-
54
- /**
55
- * 设置认证信息
56
- * @param auth {Object}
57
- * @param authType {AUTH_TYPE} 认证类型,默认:{AUTH_TYPE.BEARER}
58
- */
59
- function setAuthorization (auth, authType = AUTH_TYPE.BEARER) {
60
- switch (authType) {
61
- case AUTH_TYPE.BEARER:
62
- Cookie.set(V4_ACCESS_TOKEN, 'Bearer ' + auth.token, { expires: auth.expireAt })
63
- break
64
- case AUTH_TYPE.BASIC:
65
- case AUTH_TYPE.AUTH1:
66
- case AUTH_TYPE.AUTH2:
67
- default:
68
- break
69
- }
70
- }
71
-
72
- /**
73
- * 设置系统版本
74
- * @param value 系统版本
75
- */
76
- export function setSystemVersion (value) {
77
- Cookie.set(SYSTEM_VERSION, value)
78
- }
79
-
80
- /**
81
- * 获取系统版本
82
- */
83
- export function getSystemVersion () {
84
- return Cookie.get(SYSTEM_VERSION)
85
- }
86
-
87
- /**
88
- * 移出认证信息
89
- * @param authType {AUTH_TYPE} 认证类型
90
- */
91
- function removeAuthorization (authType = AUTH_TYPE.BEARER) {
92
- switch (authType) {
93
- case AUTH_TYPE.BEARER:
94
- Cookie.remove(V4_ACCESS_TOKEN)
95
- break
96
- case AUTH_TYPE.BASIC:
97
- case AUTH_TYPE.AUTH1:
98
- case AUTH_TYPE.AUTH2:
99
- default:
100
- break
101
- }
102
- }
103
-
104
- /**
105
- * 检查认证信息
106
- * @param authType
107
- * @returns {boolean}
108
- */
109
- function checkAuthorization (authType = AUTH_TYPE.BEARER) {
110
- switch (authType) {
111
- case AUTH_TYPE.BEARER:
112
- if (Cookie.get(V4_ACCESS_TOKEN)) {
113
- return true
114
- }
115
- break
116
- case AUTH_TYPE.BASIC:
117
- case AUTH_TYPE.AUTH1:
118
- case AUTH_TYPE.AUTH2:
119
- default:
120
- break
121
- }
122
- return false
123
- }
124
-
125
- /**
126
- * 加载 axios 拦截器
127
- * @param interceptors
128
- * @param options
129
- */
130
- function loadInterceptors () {
131
- // 加载请求拦截器
132
- axios.interceptors.request.use(config => {
133
- const token = localStorage.getItem(ACCESS_TOKEN)
134
- // 如果 token 存在
135
- // 让每个请求携带自定义 token 请根据实际情况自行修改
136
- if (token) {
137
- if (config.url !== '/auth/login') {
138
- // 判断是否为V4环境
139
- const compatible = getSystemVersion()
140
- if (compatible === 'V4') {
141
- // V4 环境则添加 V4请求头
142
- config.headers[V4_ACCESS_TOKEN] = token
143
- } else {
144
- config.headers[ACCESS_TOKEN] = token
145
- }
146
- }
147
- }
148
- if (!config.headers['Content-Type']) {
149
- config.headers['Content-Type'] = 'application/json;charset=UTF-8'
150
- }
151
- // 处理params参数
152
- if (config.params) {
153
- const url = config.url + '?' + qs.stringify(config.params, { indices: false })
154
- config.params = {}
155
- config.url = url
156
- }
157
- return config
158
- }, errorHandler)
159
- // 加载响应拦截器
160
- axios.interceptors.response.use((res) => {
161
- // 判断是否为V4环境,不为compatible赋初始值
162
- // 其有可能是undefined未定义,或第一次使用本系统LocalStorage在初始化,获得的值为null
163
- const compatible = getSystemVersion()
164
- if (compatible === 'V4') {
165
- // 请求rul
166
- const requestUrl = res.config.url
167
- if (res.data.data) {
168
- res.data = res.data.data
169
- }
170
- // 未设置状态码则默认成功状态
171
- const code = res.data.code || 200
172
- // 获取错误信息
173
- const msg = errorCode[code] || res.data.msg || errorCode['default']
174
- // 二进制数据则直接返回
175
- if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
176
- return res.data
177
- }
178
- if (code === 401) {
179
- if (!isReloginShow) {
180
- isReloginShow = true
181
- notification.open({
182
- message: '系统提示',
183
- description: '登录状态已过期,请重新登录',
184
- btn: h => {
185
- return h(
186
- 'a-button',
187
- {
188
- props: {
189
- type: 'primary',
190
- size: 'small'
191
- },
192
- on: {
193
- click: () => {
194
- logout().then(() => {
195
- isReloginShow = false
196
- location.href = '/login'
197
- })
198
- }
199
- }
200
- },
201
- '确认'
202
- )
203
- },
204
- duration: 0,
205
- onClose: () => {
206
- isReloginShow = false
207
- }
208
- })
209
- }
210
- } else if (code === 500) {
211
- if (requestUrl !== '/login') {
212
- notification.error({
213
- message: '失败',
214
- description: msg
215
- })
216
- }
217
- } else if (code !== 200) {
218
- notification.error({
219
- message: '失败',
220
- description: msg
221
- })
222
- } else {
223
- return res.data
224
- }
225
- return Promise.reject(msg)
226
- } else {
227
- return res.data
228
- }
229
- }, errorHandler)
230
- }
231
-
232
- // 异常拦截处理器
233
- const errorHandler = (error) => {
234
- if (error.response) {
235
- const data = error.response.data
236
- // 从 localstorage 获取 token
237
- const token = localStorage.getItem(ACCESS_TOKEN)
238
- if (error.response.status === 403 || (data && data.code === 403)) {
239
- notification.error({
240
- message: '禁止访问',
241
- description: data
242
- })
243
- } else if (error.response.status === 401 || (data && data.code === 401)) {
244
- notification.error({
245
- message: '鉴权失败',
246
- description: data
247
- })
248
- if (token) {
249
- logout().then(() => {
250
- setTimeout(() => {
251
- window.location.reload()
252
- }, 1500)
253
- })
254
- }
255
- } else if (error.response.status === 500 || (data && data.code === 500)) {
256
- notification.error({
257
- message: '系统异常',
258
- description: data
259
- })
260
- } else {
261
- notification.error({
262
- message: '网络异常',
263
- description: data
264
- })
265
- }
266
- }
267
- return Promise.reject(error)
268
- }
269
-
270
- /**
271
- * 解析 url 中的参数
272
- * @param url
273
- * @returns {Object}
274
- */
275
- function parseUrlParams (url) {
276
- const params = {}
277
- if (!url || url === '' || typeof url !== 'string') {
278
- return params
279
- }
280
- const paramsStr = url.split('?')[1]
281
- if (!paramsStr) {
282
- return params
283
- }
284
- const paramsArr = paramsStr.replace(/&|=/g, ' ').split(' ')
285
- for (let i = 0; i < paramsArr.length / 2; i++) {
286
- const value = paramsArr[i * 2 + 1]
287
- params[paramsArr[i * 2]] = value === 'true' ? true : (value === 'false' ? false : value)
288
- }
289
- return params
290
- }
291
-
292
- export {
293
- METHOD,
294
- AUTH_TYPE,
295
- request,
296
- setAuthorization,
297
- removeAuthorization,
298
- checkAuthorization,
299
- loadInterceptors,
300
- parseUrlParams
301
- }
1
+ import axios from 'axios'
2
+ import Cookie from 'js-cookie'
3
+ import { ACCESS_TOKEN, SYSTEM_VERSION, V4_ACCESS_TOKEN } from '@vue2-client/store/mutation-types'
4
+ import notification from 'ant-design-vue/es/notification'
5
+ import errorCode from '@vue2-client/utils/errorCode'
6
+ import qs from 'qs'
7
+ import { logout } from '@vue2-client/services/user'
8
+
9
+ // 是否显示重新登录
10
+ let isReloginShow
11
+
12
+ axios.defaults.timeout = 5000
13
+ axios.defaults.withCredentials = true
14
+
15
+ // 认证类型
16
+ const AUTH_TYPE = {
17
+ BEARER: 'Bearer',
18
+ BASIC: 'basic',
19
+ AUTH1: 'auth1',
20
+ AUTH2: 'auth2'
21
+ }
22
+
23
+ // http method
24
+ const METHOD = {
25
+ GET: 'get',
26
+ POST: 'post',
27
+ PUT: 'put',
28
+ DELETE: 'delete'
29
+ }
30
+
31
+ /**
32
+ * axios请求
33
+ * @param url 请求地址
34
+ * @param method {METHOD} http method
35
+ * @param params 请求参数
36
+ * @param config
37
+ * @returns {Promise<AxiosResponse<T>>}
38
+ */
39
+ async function request (url, method, params, config) {
40
+ switch (method) {
41
+ case METHOD.GET:
42
+ return axios.get(url, { params, ...config })
43
+ case METHOD.POST:
44
+ return axios.post(url, params, config)
45
+ case METHOD.PUT:
46
+ return axios.put(url, params, config)
47
+ case METHOD.DELETE:
48
+ return axios.delete(url, config)
49
+ default:
50
+ return axios.get(url, { params, ...config })
51
+ }
52
+ }
53
+
54
+ /**
55
+ * 设置认证信息
56
+ * @param auth {Object}
57
+ * @param authType {AUTH_TYPE} 认证类型,默认:{AUTH_TYPE.BEARER}
58
+ */
59
+ function setAuthorization (auth, authType = AUTH_TYPE.BEARER) {
60
+ switch (authType) {
61
+ case AUTH_TYPE.BEARER:
62
+ Cookie.set(V4_ACCESS_TOKEN, 'Bearer ' + auth.token, { expires: auth.expireAt })
63
+ break
64
+ case AUTH_TYPE.BASIC:
65
+ case AUTH_TYPE.AUTH1:
66
+ case AUTH_TYPE.AUTH2:
67
+ default:
68
+ break
69
+ }
70
+ }
71
+
72
+ /**
73
+ * 设置系统版本
74
+ * @param value 系统版本
75
+ */
76
+ export function setSystemVersion (value) {
77
+ Cookie.set(SYSTEM_VERSION, value)
78
+ }
79
+
80
+ /**
81
+ * 获取系统版本
82
+ */
83
+ export function getSystemVersion () {
84
+ return Cookie.get(SYSTEM_VERSION)
85
+ }
86
+
87
+ /**
88
+ * 移出认证信息
89
+ * @param authType {AUTH_TYPE} 认证类型
90
+ */
91
+ function removeAuthorization (authType = AUTH_TYPE.BEARER) {
92
+ switch (authType) {
93
+ case AUTH_TYPE.BEARER:
94
+ Cookie.remove(V4_ACCESS_TOKEN)
95
+ break
96
+ case AUTH_TYPE.BASIC:
97
+ case AUTH_TYPE.AUTH1:
98
+ case AUTH_TYPE.AUTH2:
99
+ default:
100
+ break
101
+ }
102
+ }
103
+
104
+ /**
105
+ * 检查认证信息
106
+ * @param authType
107
+ * @returns {boolean}
108
+ */
109
+ function checkAuthorization (authType = AUTH_TYPE.BEARER) {
110
+ switch (authType) {
111
+ case AUTH_TYPE.BEARER:
112
+ if (Cookie.get(V4_ACCESS_TOKEN)) {
113
+ return true
114
+ }
115
+ break
116
+ case AUTH_TYPE.BASIC:
117
+ case AUTH_TYPE.AUTH1:
118
+ case AUTH_TYPE.AUTH2:
119
+ default:
120
+ break
121
+ }
122
+ return false
123
+ }
124
+
125
+ /**
126
+ * 加载 axios 拦截器
127
+ * @param interceptors
128
+ * @param options
129
+ */
130
+ function loadInterceptors () {
131
+ // 加载请求拦截器
132
+ axios.interceptors.request.use(config => {
133
+ const token = localStorage.getItem(ACCESS_TOKEN)
134
+ // 如果 token 存在
135
+ // 让每个请求携带自定义 token 请根据实际情况自行修改
136
+ if (token) {
137
+ if (config.url !== '/auth/login') {
138
+ // 判断是否为V4环境
139
+ const compatible = getSystemVersion()
140
+ if (compatible === 'V4') {
141
+ // V4 环境则添加 V4请求头
142
+ config.headers[V4_ACCESS_TOKEN] = token
143
+ } else {
144
+ config.headers[ACCESS_TOKEN] = token
145
+ }
146
+ }
147
+ }
148
+ if (!config.headers['Content-Type']) {
149
+ config.headers['Content-Type'] = 'application/json;charset=UTF-8'
150
+ }
151
+ // 处理params参数
152
+ if (config.params) {
153
+ const url = config.url + '?' + qs.stringify(config.params, { indices: false })
154
+ config.params = {}
155
+ config.url = url
156
+ }
157
+ return config
158
+ }, errorHandler)
159
+ // 加载响应拦截器
160
+ axios.interceptors.response.use((res) => {
161
+ // 判断是否为V4环境,不为compatible赋初始值
162
+ // 其有可能是undefined未定义,或第一次使用本系统LocalStorage在初始化,获得的值为null
163
+ const compatible = getSystemVersion()
164
+ if (compatible === 'V4') {
165
+ // 请求rul
166
+ const requestUrl = res.config.url
167
+ if (res.data.data) {
168
+ res.data = res.data.data
169
+ }
170
+ // 未设置状态码则默认成功状态
171
+ const code = res.data.code || 200
172
+ // 获取错误信息
173
+ const msg = errorCode[code] || res.data.msg || errorCode['default']
174
+ // 二进制数据则直接返回
175
+ if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
176
+ return res.data
177
+ }
178
+ if (code === 401) {
179
+ if (!isReloginShow) {
180
+ isReloginShow = true
181
+ notification.open({
182
+ message: '系统提示',
183
+ description: '登录状态已过期,请重新登录',
184
+ btn: h => {
185
+ return h(
186
+ 'a-button',
187
+ {
188
+ props: {
189
+ type: 'primary',
190
+ size: 'small'
191
+ },
192
+ on: {
193
+ click: () => {
194
+ logout().then(() => {
195
+ isReloginShow = false
196
+ location.href = '/login'
197
+ })
198
+ }
199
+ }
200
+ },
201
+ '确认'
202
+ )
203
+ },
204
+ duration: 0,
205
+ onClose: () => {
206
+ isReloginShow = false
207
+ }
208
+ })
209
+ }
210
+ } else if (code === 500) {
211
+ if (requestUrl !== '/login') {
212
+ notification.error({
213
+ message: '失败',
214
+ description: msg
215
+ })
216
+ }
217
+ } else if (code === 601) {
218
+ notification.warn({
219
+ message: '警告',
220
+ description: msg
221
+ })
222
+ } else if (code !== 200) {
223
+ notification.error({
224
+ message: '失败',
225
+ description: msg
226
+ })
227
+ } else {
228
+ return res.data
229
+ }
230
+ return Promise.reject(msg)
231
+ } else {
232
+ return res.data
233
+ }
234
+ }, errorHandler)
235
+ }
236
+
237
+ // 异常拦截处理器
238
+ const errorHandler = (error) => {
239
+ if (error.response) {
240
+ const data = error.response.data
241
+ // 从 localstorage 获取 token
242
+ const token = localStorage.getItem(ACCESS_TOKEN)
243
+ if (error.response.status === 403 || (data && data.code === 403)) {
244
+ notification.error({
245
+ message: '禁止访问',
246
+ description: data
247
+ })
248
+ } else if (error.response.status === 401 || (data && data.code === 401)) {
249
+ notification.error({
250
+ message: '鉴权失败',
251
+ description: data
252
+ })
253
+ if (token) {
254
+ logout().then(() => {
255
+ setTimeout(() => {
256
+ window.location.reload()
257
+ }, 1500)
258
+ })
259
+ }
260
+ } else if (error.response.status === 500 || (data && data.code === 500)) {
261
+ notification.error({
262
+ message: '系统异常',
263
+ description: data
264
+ })
265
+ } else if (error.response.status === 601 || (data && data.code === 601)) {
266
+ notification.warn({
267
+ message: '系统警告',
268
+ description: data
269
+ })
270
+ } else {
271
+ notification.error({
272
+ message: '网络异常',
273
+ description: data
274
+ })
275
+ }
276
+ }
277
+ return Promise.reject(error)
278
+ }
279
+
280
+ /**
281
+ * 解析 url 中的参数
282
+ * @param url
283
+ * @returns {Object}
284
+ */
285
+ function parseUrlParams (url) {
286
+ const params = {}
287
+ if (!url || url === '' || typeof url !== 'string') {
288
+ return params
289
+ }
290
+ const paramsStr = url.split('?')[1]
291
+ if (!paramsStr) {
292
+ return params
293
+ }
294
+ const paramsArr = paramsStr.replace(/&|=/g, ' ').split(' ')
295
+ for (let i = 0; i < paramsArr.length / 2; i++) {
296
+ const value = paramsArr[i * 2 + 1]
297
+ params[paramsArr[i * 2]] = value === 'true' ? true : (value === 'false' ? false : value)
298
+ }
299
+ return params
300
+ }
301
+
302
+ export {
303
+ METHOD,
304
+ AUTH_TYPE,
305
+ request,
306
+ setAuthorization,
307
+ removeAuthorization,
308
+ checkAuthorization,
309
+ loadInterceptors,
310
+ parseUrlParams
311
+ }