vue2-client 1.2.26 → 1.2.28-test1

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.
Files changed (62) hide show
  1. package/.eslintrc.js +82 -81
  2. package/CHANGELOG.md +8 -0
  3. package/package.json +1 -1
  4. package/src/base-client/components/common/CreateQuery/CreateQuery.vue +2 -3
  5. package/src/base-client/components/common/CreateSimpleFormQuery/CreateSimpleFormQuery.vue +1 -2
  6. package/src/base-client/components/common/FormGroupEdit/FormGroupEdit.vue +1 -2
  7. package/src/base-client/components/common/XAddForm/XAddForm.vue +1 -1
  8. package/src/base-client/components/common/XAddNativeForm/XAddNativeForm.vue +315 -0
  9. package/src/base-client/components/common/XAddNativeForm/index.js +3 -0
  10. package/src/base-client/components/common/XAddNativeForm/index.md +56 -0
  11. package/src/base-client/components/common/XForm/XForm.vue +1 -1
  12. package/src/base-client/components/common/XForm/XFormItem.vue +1 -1
  13. package/src/base-client/components/common/XFormTable/XFormTable.vue +1 -2
  14. package/src/base-client/components/iot/CustomerDetailsView/CustomerDetailsView.vue +1 -2
  15. package/src/base-client/components/iot/DeviceBrandDetailsView/DeviceBrandDetailsView.vue +1 -2
  16. package/src/base-client/components/iot/DeviceDetailsView/DeviceDetailsView.vue +1 -2
  17. package/src/base-client/components/iot/DeviceDetailsView/part/DeviceDetailsCount.vue +1 -1
  18. package/src/base-client/components/iot/DeviceDetailsView/part/DeviceDetailsInstructOperate.vue +1 -2
  19. package/src/base-client/components/iot/DeviceTypeDetailsView/DeviceTypeDetailsView.vue +1 -2
  20. package/src/base-client/components/iot/InstructDetailsView/InstructDetailsView.vue +1 -3
  21. package/src/base-client/components/iot/LogDetailsView/LogDetailsView.vue +1 -2
  22. package/src/base-client/components/iot/MeterDetailsView/MeterDetailsView.vue +1 -2
  23. package/src/base-client/components/iot/MeterDetailsView/part/MeterDetailsCount.vue +1 -1
  24. package/src/base-client/components/iot/MeterDetailsView/part/MeterDetailsException.vue +1 -2
  25. package/src/base-client/components/iot/MeterDetailsView/part/MeterDetailsHandPlan.vue +1 -2
  26. package/src/base-client/components/iot/MeterDetailsView/part/MeterDetailsInstruct.vue +1 -2
  27. package/src/base-client/components/iot/MeterDetailsView/part/MeterDetailsMain.vue +1 -2
  28. package/src/base-client/components/iot/MeterDetailsView/part/MeterDetailsSellGas.vue +1 -2
  29. package/src/base-client/components/iot/WebmeterAnalysisView/WebmeterAnalysisView.vue +1 -2
  30. package/src/base-client/components/system/DictionaryDetailsView/DictionaryDetailsView.vue +1 -2
  31. package/src/base-client/components/system/QueryParamsDetailsView/QueryParamsDetailsView.vue +1 -2
  32. package/src/base-client/components/ticket/EmployeeDetailsView/EmployeeDetailsView.vue +1 -2
  33. package/src/base-client/components/ticket/TicketDetailsView/TicketDetailsView.vue +844 -846
  34. package/src/base-client/components/ticket/TicketDetailsView/part/TicketDetailsFlow.vue +1 -2
  35. package/src/base-client/components/ticket/TicketSubmitSuccessView/TicketSubmitSuccessView.vue +528 -529
  36. package/src/base-client/plugins/AppData.js +1 -2
  37. package/src/base-client/plugins/GetLoginInfoService.js +45 -14
  38. package/src/components/exception/ExceptionPage.vue +1 -1
  39. package/src/config/CreateQueryConfig.js +80 -40
  40. package/src/layouts/ComponentLayoutOne.vue +0 -1
  41. package/src/layouts/SinglePageView.vue +1 -1
  42. package/src/layouts/header/HeaderNotice.vue +1 -1
  43. package/src/pages/report/ReportTableHome.vue +1 -1
  44. package/src/pages/resourceManage/depListManage.vue +23 -0
  45. package/src/pages/resourceManage/funListManage.vue +23 -0
  46. package/src/pages/resourceManage/index.js +15 -0
  47. package/src/pages/resourceManage/orgListManage.vue +98 -0
  48. package/src/pages/resourceManage/resourceManageMain.vue +37 -34
  49. package/src/pages/resourceManage/roleListManage.vue +23 -0
  50. package/src/pages/resourceManage/staffListManage.vue +23 -0
  51. package/src/pages/system/ticket/index.vue +437 -438
  52. package/src/pages/system/ticket/submitTicketSuccess.vue +1 -2
  53. package/src/services/api/EmployeeDetailsViewApi.js +16 -16
  54. package/src/services/api/common.js +10 -0
  55. package/src/services/api/index.js +39 -0
  56. package/src/services/{api.js → apiService.js} +0 -0
  57. package/src/services/user.js +1 -1
  58. package/src/store/modules/account.js +2 -2
  59. package/src/utils/indexedDB.js +1 -1
  60. package/src/utils/request.js +1 -2
  61. package/src/utils/routerUtil.js +1 -13
  62. package/src/utils/util.js +12 -0
@@ -1,5 +1,4 @@
1
- import { post } from '@vue2-client/services/api/restTools'
2
- import { manageApi } from '@vue2-client/services/api/manage'
1
+ import { manageApi, post } from '@vue2-client/services/api'
3
2
 
4
3
  const GetAppDataService = {
5
4
  install (Vue) {
@@ -1,17 +1,6 @@
1
1
  import Vue from 'vue'
2
- import { SEARCH } from '@vue2-client/services/api'
3
- import { post } from '@vue2-client/services/api/restTools'
4
-
5
- const loginGen = async function (response) {
6
- Vue.$login.f = response
7
- await Promise.all([Vue.$appdata.load(), getGasman(), getLic(), getViewDetails()])
8
- const login = {
9
- f: Vue.$login.f,
10
- jwt: Vue.$login.f.id,
11
- r: Vue.$login.r
12
- }
13
- Vue.$store.commit('account/setLogin', login)
14
- }
2
+ import { SEARCH } from '@vue2-client/services/apiService'
3
+ import { post } from '@vue2-client/services/api'
15
4
 
16
5
  /**
17
6
  * 获取片区
@@ -107,7 +96,47 @@ async function getResourceFunction () {
107
96
  console.log('获取资源功能异常', error)
108
97
  }
109
98
  }
99
+ /**
100
+ * 获取组织管理数据
101
+ * @returns {Promise<void>}
102
+ */
103
+ async function getOrganization () {
104
+ try {
105
+ const resourceFunction = await post(SEARCH, {
106
+ source: 'tool.getFullTree(this.getRights().where(row.getType() == $organization$||row.getType() == $zone$))',
107
+ userid: Vue.$login.f.id
108
+ }, { resolveMsg: null, rejectMsg: null })
109
+ return resourceFunction
110
+ } catch (error) {
111
+ console.log('获取组织管理数据异常', error)
112
+ }
113
+ }
114
+ /**
115
+ * 完整资源树筛选指定名称的资源
116
+ * @param fun 要筛选的资源树
117
+ * @param name 筛选的资源名称
118
+ * @returns {*}
119
+ */
120
+ function searchFun (fun, name) {
121
+ if (fun.length > 0) {
122
+ if (fun[0].name == name) {
123
+ return fun[0].children
124
+ } else {
125
+ return searchFun(fun[0].children, name)
126
+ }
127
+ }
128
+ }
110
129
 
130
+ const loginGen = async function (response) {
131
+ Vue.$login.f = response
132
+ await Promise.all([Vue.$appdata.load(), getGasman(), getLic(), getViewDetails()])
133
+ const login = {
134
+ f: Vue.$login.f,
135
+ jwt: Vue.$login.f.id,
136
+ r: Vue.$login.r
137
+ }
138
+ Vue.$store.commit('account/setLogin', login)
139
+ }
111
140
  const GetLoginInfoService = {
112
141
  install (Vue) {
113
142
  // 给vue增添对话框显示方法
@@ -217,5 +246,7 @@ const GetLoginInfoService = {
217
246
 
218
247
  export default GetLoginInfoService
219
248
  export {
220
- getResourceFunction
249
+ getResourceFunction,
250
+ getOrganization,
251
+ searchFun
221
252
  }
@@ -7,7 +7,7 @@
7
7
  <h1>{{ config[type].title }}</h1>
8
8
  <div class="desc">{{ config[type].desc }}</div>
9
9
  <div class="action">
10
- <a-button type="primary" @click="backHome">返回首页</a-button>
10
+ <!--<a-button type="primary" @click="backHome">返回首页</a-button>-->
11
11
  </div>
12
12
  </div>
13
13
  </div>
@@ -1,40 +1,80 @@
1
- module.exports = {
2
- queryType: [
3
- {
4
- label: '相等(=)', key: '=', match: 'input;select;radio;monthPicker;datePicker;cascader;selects'
5
- },
6
- {
7
- label: '不相等(!=)', key: '!=', match: 'input;select;radio;monthPicker;datePicker;cascader;selects'
8
- },
9
- {
10
- label: '全模糊(like)', key: 'LIKE', match: 'input;select;radio;cascader;selects'
11
- },
12
- {
13
- label: '左模糊(left like)', key: 'LEFT_LIKE', match: 'input;select;radio;cascader;selects'
14
- },
15
- {
16
- label: '右模糊(right like)', key: 'RIGHT_LIKE', match: 'input;select;radio;cascader;selects'
17
- },
18
- {
19
- label: '大于(>)', key: '>', match: 'input;select;radio;monthPicker;datePicker;cascader;selects'
20
- },
21
- {
22
- label: '大于等于(>=)', key: '>=', match: 'input;select;radio;monthPicker;datePicker;cascader;selects'
23
- },
24
- {
25
- label: '小于(<)', key: '<', match: 'input;select;radio;monthPicker;datePicker;cascader;selects'
26
- },
27
- {
28
- label: '小于等于(<=)', key: '<=', match: 'input;select;radio;monthPicker;datePicker;cascader;selects'
29
- },
30
- {
31
- label: '包含(in)', key: 'IN', match: 'checkbox;select;cascader;selects'
32
- },
33
- {
34
- label: '不包含(not in)', key: 'NOT_IN', match: 'checkbox;select;cascader;selects'
35
- },
36
- {
37
- label: '之间(between)', key: 'BETWEEN', match: 'rangePicker'
38
- }
39
- ]
40
- }
1
+ module.exports = {
2
+ // 文件上传类型
3
+ file_ype: [
4
+ {
5
+ label: 'word文档',
6
+ accept: '.doc,.docx,'
7
+ },
8
+ {
9
+ label: 'excel表格',
10
+ accept: '.xlsx,.xls,'
11
+ },
12
+ {
13
+ label: 'ppt幻灯片',
14
+ accept: '.ppt,.pptx,'
15
+ },
16
+ {
17
+ label: '图片',
18
+ accept: '.jpg,.jpeg,.ico,.gif,svg,.webp,.png,.bmp,.pjpeg,'
19
+ },
20
+ {
21
+ label: '视频',
22
+ accept: '.mp4,.mov,.m4v,.wmv,.asf,.asx,.rm,.rmvb,.3gp,.avi,.mkv,'
23
+ },
24
+ {
25
+ label: '音频',
26
+ accept: '.mp3,.cda,.wav,.aif,.aiff,.ape,.ra,'
27
+ },
28
+ {
29
+ label: '压缩包',
30
+ accept: '.zip,.rar,.7z,'
31
+ },
32
+ {
33
+ label: '其他文本',
34
+ accept: '.json,.txt,'
35
+ },
36
+ {
37
+ label: '无限制',
38
+ accept: '*'
39
+ },
40
+ ],
41
+ // 查询方式
42
+ queryType: [
43
+ {
44
+ label: '相等(=)', key: '=', match: 'input;select;radio;monthPicker;datePicker;cascader;selects'
45
+ },
46
+ {
47
+ label: '不相等(!=)', key: '!=', match: 'input;select;radio;monthPicker;datePicker;cascader;selects'
48
+ },
49
+ {
50
+ label: '全模糊(like)', key: 'LIKE', match: 'input;select;radio;cascader;selects'
51
+ },
52
+ {
53
+ label: '左模糊(left like)', key: 'LEFT_LIKE', match: 'input;select;radio;cascader;selects'
54
+ },
55
+ {
56
+ label: '右模糊(right like)', key: 'RIGHT_LIKE', match: 'input;select;radio;cascader;selects'
57
+ },
58
+ {
59
+ label: '大于(>)', key: '>', match: 'input;select;radio;monthPicker;datePicker;cascader;selects'
60
+ },
61
+ {
62
+ label: '大于等于(>=)', key: '>=', match: 'input;select;radio;monthPicker;datePicker;cascader;selects'
63
+ },
64
+ {
65
+ label: '小于(<)', key: '<', match: 'input;select;radio;monthPicker;datePicker;cascader;selects'
66
+ },
67
+ {
68
+ label: '小于等于(<=)', key: '<=', match: 'input;select;radio;monthPicker;datePicker;cascader;selects'
69
+ },
70
+ {
71
+ label: '包含(in)', key: 'IN', match: 'checkbox;select;cascader;selects'
72
+ },
73
+ {
74
+ label: '不包含(not in)', key: 'NOT_IN', match: 'checkbox;select;cascader;selects'
75
+ },
76
+ {
77
+ label: '之间(between)', key: 'BETWEEN', match: 'rangePicker'
78
+ }
79
+ ]
80
+ }
@@ -35,7 +35,6 @@
35
35
  </script>
36
36
 
37
37
  <style lang="less">
38
- @import '~ant-design-vue/../../src/theme/index';
39
38
  #ComponentLayoutOne {
40
39
  .ant-layout-sider {
41
40
  .ant-layout-sider-zero-width-trigger {
@@ -13,7 +13,7 @@
13
13
  </template>
14
14
 
15
15
  <script>
16
- import PageToggleTransition from '../components/transition/PageToggleTransition'
16
+ import PageToggleTransition from '@vue2-client/components/transition/PageToggleTransition'
17
17
  import { ACCESS_TOKEN } from '@vue2-client/store/mutation-types'
18
18
  import { mapState, mapMutations } from 'vuex'
19
19
 
@@ -30,7 +30,7 @@
30
30
  </template>
31
31
 
32
32
  <script>
33
- import { post } from '@vue2-client/services/api/restTools'
33
+ import { post } from '@vue2-client/services/api'
34
34
  export default {
35
35
  name: 'HeaderNotice',
36
36
  data () {
@@ -3,7 +3,7 @@
3
3
  </template>
4
4
 
5
5
  <script>
6
- import { post } from '@vue2-client/services/api/restTools'
6
+ import { post } from '@vue2-client/services/api'
7
7
  import ReportTable from '@vue2-client/pages/report/ReportTable'
8
8
  export default {
9
9
  name: 'ReportTableHome',
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <div id="depListManage">
3
+
4
+ </div>
5
+ </template>
6
+
7
+ <script>
8
+ export default {
9
+ name: 'depListManage',
10
+ data () {
11
+ return {}
12
+ },
13
+ created () {
14
+ },
15
+ mounted () {
16
+ },
17
+ methods: {}
18
+ }
19
+ </script>
20
+
21
+ <style lang="less">
22
+
23
+ </style>
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <div id="funListManage">
3
+
4
+ </div>
5
+ </template>
6
+
7
+ <script>
8
+ export default {
9
+ name: 'funListManage',
10
+ data () {
11
+ return {}
12
+ },
13
+ created () {
14
+ },
15
+ mounted () {
16
+ },
17
+ methods: {}
18
+ }
19
+ </script>
20
+
21
+ <style lang="less">
22
+
23
+ </style>
@@ -0,0 +1,15 @@
1
+ import depListManage from '@vue2-client/pages/resourceManage/depListManage'
2
+ import funListManage from '@vue2-client/pages/resourceManage/funListManage'
3
+ import orgListManage from '@vue2-client/pages/resourceManage/orgListManage'
4
+ import resourceManageMain from '@vue2-client/pages/resourceManage/resourceManageMain'
5
+ import roleListManage from '@vue2-client/pages/resourceManage/roleListManage'
6
+ import staffListManage from '@vue2-client/pages/resourceManage/staffListManage'
7
+
8
+ export default resourceManageMain
9
+ export {
10
+ depListManage,
11
+ funListManage,
12
+ orgListManage,
13
+ roleListManage,
14
+ staffListManage
15
+ }
@@ -0,0 +1,98 @@
1
+ <template>
2
+ <div id="orgListManage">
3
+ <a-card :bordered="false">
4
+ <!--<a-row :gutter="48">-->
5
+ <!--<a-col>-->
6
+ <!--<a-space>-->
7
+ <!--<a-button type="primary" @click="addItem" v-if="!buttonState || buttonState.add">-->
8
+ <!--<a-icon :style="iconStyle" type="plus"/>新增-->
9
+ <!--</a-button>-->
10
+ <!--<a-button-->
11
+ <!--v-if="!buttonState || buttonState.edit"-->
12
+ <!--:loading="editDataLoading"-->
13
+ <!--:disabled="!isModify"-->
14
+ <!--class="btn-success"-->
15
+ <!--type="dashed"-->
16
+ <!--@click="editItem">-->
17
+ <!--<a-icon :style="iconStyle" type="edit"/>修改-->
18
+ <!--</a-button>-->
19
+ <!--<a-button :disabled="!isDelete" type="danger" @click="deleteItem" v-if="!buttonState || buttonState.delete">-->
20
+ <!--<a-icon :style="iconStyle" type="delete"/>删除-->
21
+ <!--</a-button>-->
22
+ <!--</a-space>-->
23
+ <!--<span :style="{ float: 'right', overflow: 'hidden', marginBottom: '8px' }">-->
24
+ <!--<a-button-group>-->
25
+ <!--<a-button @click="toggleIsFormShow">-->
26
+ <!--<a-icon :style="iconStyle" type="vertical-align-top"/>-->
27
+ <!--</a-button>-->
28
+ <!--<a-button @click="refresh(true)">-->
29
+ <!--<a-icon :style="iconStyle" type="reload" />-->
30
+ <!--</a-button>-->
31
+ <!--<a-button @click="showDrawer">-->
32
+ <!--<a-icon :style="iconStyle" type="table" />-->
33
+ <!--</a-button>-->
34
+ <!--<a-button @click="exports">-->
35
+ <!--<a-icon :style="iconStyle" type="cloud-download"/>-->
36
+ <!--</a-button>-->
37
+ <!--</a-button-group>-->
38
+ <!--</span>-->
39
+ <!--</a-col>-->
40
+ <!--</a-row>-->
41
+ <a-table
42
+ rowKey="id"
43
+ size="middle"
44
+ bordered
45
+ :pagination="false"
46
+ :columns="columns"
47
+ :data-source="funTree">
48
+ </a-table>
49
+ </a-card>
50
+ </div>
51
+ </template>
52
+
53
+ <script>
54
+ import { getOrganization, searchFun } from '@vue2-client/base-client/plugins/GetLoginInfoService'
55
+ import { getColumnsJson } from '@vue2-client/services/api'
56
+ export default {
57
+ // 组织管理
58
+ name: 'orgListManage',
59
+ data () {
60
+ return {
61
+ columnsJson: [],
62
+ funTree: [],
63
+ columns: [
64
+ {
65
+ title: '组织名称',
66
+ dataIndex: 'name'
67
+ },
68
+ {
69
+ title: '排序',
70
+ dataIndex: 'position'
71
+ },
72
+ {
73
+ title: '组件目录',
74
+ dataIndex: 'f_dir'
75
+ },
76
+ {
77
+ title: '描述',
78
+ dataIndex: 'f_description'
79
+ }
80
+ ]
81
+ }
82
+ },
83
+ created () {
84
+ },
85
+ async mounted () {
86
+ getColumnsJson('orgListManage', (res) => {
87
+ this.columnsJson = res
88
+ })
89
+ const fun = await getOrganization()
90
+ this.funTree = searchFun(fun, '组织机构')
91
+ },
92
+ methods: {
93
+ }
94
+ }
95
+ </script>
96
+
97
+ <style lang="less">
98
+ </style>
@@ -1,55 +1,58 @@
1
- <!--<template>-->
2
- <!--<div id="resourceManageMain">-->
3
- <!--<a-tabs>-->
4
- <!--<a-tab-pane key="1" force-render>-->
5
- <!--<span slot="tab"><a-icon type="apartment" />资源管理</span>-->
6
- <!--Content of Tab Pane 1-->
7
- <!--</a-tab-pane>-->
8
- <!--<a-tab-pane key="2" tab="功能管理" force-render>-->
9
- <!--Content of Tab Pane 2-->
10
- <!--</a-tab-pane>-->
11
- <!--<a-tab-pane key="3" tab="部门管理" force-render>-->
12
- <!--Content of Tab Pane 3-->
13
- <!--</a-tab-pane>-->
14
- <!--</a-tabs>-->
15
- <!--</div>-->
16
- <!--</template>-->
17
-
18
1
  <script>
19
- import { mapState } from 'vuex'
20
- import { getResourceFunction } from '@vue2-client/base-client/plugins/GetLoginInfoService'
2
+ import { depListManage, funListManage, orgListManage, roleListManage, staffListManage } from '@vue2-client/pages/resourceManage'
3
+ import exp403 from '@vue2-client/pages/exception/403'
4
+ import { getResourceFunction, searchFun } from '@vue2-client/base-client/plugins/GetLoginInfoService'
21
5
 
22
6
  export default {
23
7
  name: 'resourceManageMain',
24
- computed: {
25
- ...mapState('account', ['login'])
26
- },
8
+ components: { depListManage, funListManage, orgListManage, roleListManage, staffListManage },
27
9
  data () {
28
10
  return {
11
+ renderSW: false,
29
12
  resFun: []
30
13
  }
31
14
  },
15
+ render () {
16
+ if (!this.renderSW) return
17
+ if (!this.resFun || this.resFun.length <= 0) {
18
+ return (
19
+ <div id="resourceManageMain">
20
+ <exp403></exp403>
21
+ </div>
22
+ )
23
+ }
24
+ const tabPane = []
25
+ for (const [index, row] of this.resFun.entries()) {
26
+ tabPane.push(
27
+ <a-tab-pane key={index} force-render>
28
+ <span slot="tab"><a-icon type={row.icon || 'exclamation'}/>{row.name}</span>
29
+ <row.link></row.link>
30
+ </a-tab-pane>
31
+ )
32
+ }
33
+ return (
34
+ <div id="resourceManageMain">
35
+ <a-tabs>
36
+ {tabPane}
37
+ </a-tabs>
38
+ </div>
39
+ )
40
+ },
32
41
  created () {
33
42
  },
34
43
  async mounted () {
35
44
  const fun = await getResourceFunction()
36
- console.log('->', fun)
37
- this.resFun = this.searchFun(fun, '资源功能')
45
+ this.resFun = searchFun(fun, '资源功能')
46
+ this.renderSW = true
38
47
  },
39
48
  methods: {
40
- searchFun (fun, name) {
41
- if (fun.length > 0) {
42
- if (fun[0].name == name) {
43
- return fun[0].children
44
- } else {
45
- return this.searchFun(fun[0].children, name)
46
- }
47
- }
48
- }
49
49
  }
50
50
  }
51
51
  </script>
52
52
 
53
53
  <style lang="less">
54
-
54
+ #resourceManageMain {
55
+ background-color: @gray-1;
56
+ height: calc(100vh - 117px);
57
+ }
55
58
  </style>
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <div id="roleListManage">
3
+
4
+ </div>
5
+ </template>
6
+
7
+ <script>
8
+ export default {
9
+ name: 'roleListManage',
10
+ data () {
11
+ return {}
12
+ },
13
+ created () {
14
+ },
15
+ mounted () {
16
+ },
17
+ methods: {}
18
+ }
19
+ </script>
20
+
21
+ <style lang="less">
22
+
23
+ </style>
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <div id="staffListManage">
3
+
4
+ </div>
5
+ </template>
6
+
7
+ <script>
8
+ export default {
9
+ name: 'staffListManage',
10
+ data () {
11
+ return {}
12
+ },
13
+ created () {
14
+ },
15
+ mounted () {
16
+ },
17
+ methods: {}
18
+ }
19
+ </script>
20
+
21
+ <style lang="less">
22
+
23
+ </style>