更新常见问题答疑
Showing
29 changed files
with
3788 additions
and
265 deletions
... | @@ -22,7 +22,9 @@ | ... | @@ -22,7 +22,9 @@ |
22 | "nprogress": "0.2.0", | 22 | "nprogress": "0.2.0", |
23 | "vue": "2.5.17", | 23 | "vue": "2.5.17", |
24 | "vue-router": "3.0.1", | 24 | "vue-router": "3.0.1", |
25 | "vuex": "3.0.1" | 25 | "vuex": "3.0.1", |
26 | "@wangeditor/editor": "^5.1.1", | ||
27 | "@wangeditor/editor-for-vue": "^1.0.2" | ||
26 | }, | 28 | }, |
27 | "devDependencies": { | 29 | "devDependencies": { |
28 | "autoprefixer": "8.5.0", | 30 | "autoprefixer": "8.5.0", |
... | @@ -84,4 +86,4 @@ | ... | @@ -84,4 +86,4 @@ |
84 | "last 2 versions", | 86 | "last 2 versions", |
85 | "not ie <= 8" | 87 | "not ie <= 8" |
86 | ] | 88 | ] |
87 | } | 89 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
1 | module.exports = { | 1 | module.exports = { |
2 | testListGet: '/xxx/xxx/list', | 2 | getArticleClassify: '/admin/articleApi/classify/list', |
3 | setArticleClassify: '/admin/articleApi/classify', | ||
4 | |||
5 | getArticleList: '/admin/articleApi/article/list', | ||
6 | setArticleList: '/admin/articleApi/article', | ||
7 | getArticleDetail: '/admin/articleApi/article', | ||
8 | setArticle: '/admin/articleApi/article/save', | ||
9 | |||
10 | getArticleDashboard: '/admin/articleApi/stat/dashboard', | ||
11 | getArticleViewRank: '/admin/articleApi/stat/viewRank', | ||
12 | exportArticleViewRank: '/admin/articleApi/stat/viewRank/export', | ||
13 | getArticleClassifyRank: '/admin/articleApi/stat/classifyRank', | ||
14 | exportArticleClassifyRank: '/admin/articleApi/stat/classifyRank/export', | ||
15 | |||
16 | getArticleKeywordList: '/admin/articleApi/keyword/list', | ||
17 | setArticleKeywordList: '/admin/articleApi/keyword', | ||
18 | getArticleKeywordStat: '/admin/articleApi/keyword/stat', | ||
19 | |||
20 | upload: "/common/upload", | ||
21 | |||
3 | exportTable: exportTable, | 22 | exportTable: exportTable, |
4 | } | 23 | } |
5 | 24 | ... | ... |
src/api/fetch-api-new.js
0 → 100644
1 | import axios from 'axios'; | ||
2 | // import router from './../router' | ||
3 | import router from '@/router/index' | ||
4 | import { | ||
5 | Message | ||
6 | } from 'element-ui' | ||
7 | import { | ||
8 | getToken, | ||
9 | setToken, | ||
10 | removeToken | ||
11 | } from '@/utils/auth' | ||
12 | |||
13 | |||
14 | // 可以使用 | ||
15 | import { | ||
16 | MessageBox | ||
17 | } from 'element-ui' | ||
18 | |||
19 | /** | ||
20 | * 提示方法,自行处理 | ||
21 | * 可以使用 MessageBox | ||
22 | * | ||
23 | * @param {*} data | ||
24 | */ | ||
25 | let alreadyToast = false | ||
26 | |||
27 | function Toast(data) { | ||
28 | if (alreadyToast) { | ||
29 | return; | ||
30 | } | ||
31 | alreadyToast = true; | ||
32 | MessageBox.alert(data.message, '警告', { | ||
33 | confirmButtonText: '确定', | ||
34 | callback: action => { | ||
35 | alreadyToast = false; | ||
36 | // this.$message({ | ||
37 | // type: 'info', | ||
38 | // message: `action: ${action}` | ||
39 | // }) | ||
40 | } | ||
41 | }) | ||
42 | } | ||
43 | |||
44 | // axios的默认url | ||
45 | // axios.defaults.baseURL = "" | ||
46 | let base = 'https://api.k.wxpai.cn/bizproxy/tianbaoServiceApi'; | ||
47 | |||
48 | // 默认超时 | ||
49 | axios.defaults.timeout = 60000; | ||
50 | |||
51 | // 响应拦截器 | ||
52 | axios.interceptors.response.use( | ||
53 | response => { | ||
54 | if (response.status === 200) { | ||
55 | if (response.config.responseType == 'blob') { | ||
56 | return Promise.resolve(response) | ||
57 | } else if (response.data.code === 200) { | ||
58 | return Promise.resolve(response); | ||
59 | } else if (response.data.code == 404) { | ||
60 | Toast({ | ||
61 | message: '登录过期,请重新登录', | ||
62 | duration: 1000, | ||
63 | forbidClick: true | ||
64 | }); | ||
65 | removeToken(); | ||
66 | setTimeout(() => { | ||
67 | router.replace({ | ||
68 | path: '/login', | ||
69 | query: { | ||
70 | redirect: router.currentRoute.fullPath | ||
71 | } | ||
72 | }); | ||
73 | }, 1000); | ||
74 | } else { | ||
75 | Message({ | ||
76 | showClose: true, | ||
77 | message: response.data.errMsg, | ||
78 | type: 'error', | ||
79 | duration: 3000 | ||
80 | }) | ||
81 | return Promise.reject(response); | ||
82 | } | ||
83 | } else { | ||
84 | return Promise.reject(response); | ||
85 | } | ||
86 | }, | ||
87 | // 服务器状态码不是200的情况 | ||
88 | error => { | ||
89 | if (error.response.status) { | ||
90 | switch (error.response.status) { | ||
91 | // 401: 未登录 | ||
92 | // 未登录则跳转登录页面,并携带当前页面的路径 | ||
93 | // 在登录成功后返回当前页面,这一步需要在登录页操作。 | ||
94 | case 401: | ||
95 | router.replace({ | ||
96 | path: '/login', | ||
97 | query: { | ||
98 | redirect: router.currentRoute.fullPath | ||
99 | } | ||
100 | }); | ||
101 | break; | ||
102 | case 404: | ||
103 | // Toast({ | ||
104 | // message: '登录过期,请重新登录', | ||
105 | // duration: 1000, | ||
106 | // forbidClick: true | ||
107 | // }); | ||
108 | // removeToken(); | ||
109 | // setTimeout(() => { | ||
110 | // router.replace({ | ||
111 | // path: '/login', | ||
112 | // query: { | ||
113 | // redirect: router.currentRoute.fullPath | ||
114 | // } | ||
115 | // }); | ||
116 | // }, 1000); | ||
117 | break; | ||
118 | // 405请求不存在 | ||
119 | case 405: | ||
120 | Toast({ | ||
121 | message: '网络请求不存在', | ||
122 | duration: 1500, | ||
123 | forbidClick: true | ||
124 | }); | ||
125 | break; | ||
126 | // 其他错误,直接抛出错误提示 | ||
127 | default: | ||
128 | Toast({ | ||
129 | message: error.response.data.errMsg, | ||
130 | duration: 1500, | ||
131 | forbidClick: true | ||
132 | }); | ||
133 | } | ||
134 | return Promise.reject(error.response); | ||
135 | } | ||
136 | } | ||
137 | ); | ||
138 | |||
139 | |||
140 | /** | ||
141 | * 分解参数 | ||
142 | */ | ||
143 | function analysisParams(params) { | ||
144 | let { | ||
145 | url, | ||
146 | data, | ||
147 | mode, | ||
148 | opt = Object.assign({}, params.opt), | ||
149 | sid = true, | ||
150 | config, | ||
151 | method | ||
152 | } = params; | ||
153 | |||
154 | if (opt.dec) { | ||
155 | data = makerypt(data); | ||
156 | } | ||
157 | let reqUrl = `${base}${url}`; | ||
158 | if (mode == "custom") { | ||
159 | reqUrl = `${url}` | ||
160 | } | ||
161 | let headers = {} | ||
162 | if (sid) { | ||
163 | // headers.sessionId = getToken(); | ||
164 | headers.adminSessionId = getAdminToken(); | ||
165 | } | ||
166 | |||
167 | // console.log({ | ||
168 | // reqUrl, | ||
169 | // data, | ||
170 | // headers, | ||
171 | // opt, | ||
172 | // method, | ||
173 | // config | ||
174 | // }); | ||
175 | return { | ||
176 | reqUrl, | ||
177 | data, | ||
178 | headers, | ||
179 | opt, | ||
180 | method, | ||
181 | config | ||
182 | } | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * 封装get方法 | ||
187 | * @param {*} params | ||
188 | */ | ||
189 | export const httpGet = params => { | ||
190 | params.method = 'get'; | ||
191 | let { | ||
192 | reqUrl, | ||
193 | data, | ||
194 | headers, | ||
195 | opt, | ||
196 | method | ||
197 | } = analysisParams(params); | ||
198 | return axios.get(reqUrl, { | ||
199 | params: data, | ||
200 | headers, | ||
201 | opt | ||
202 | }).then(res => res.data.content); | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * 封装post方法 | ||
207 | * mode为custom时,忽略baseUrl | ||
208 | * @param {*} params | ||
209 | */ | ||
210 | export const httpPost = params => { | ||
211 | params.method = 'post'; | ||
212 | let { | ||
213 | reqUrl, | ||
214 | data, | ||
215 | headers, | ||
216 | opt, | ||
217 | method | ||
218 | } = analysisParams(params); | ||
219 | return axios.post(reqUrl, data, { | ||
220 | headers, | ||
221 | opt | ||
222 | }).then(res => res.data.content); | ||
223 | } | ||
224 | |||
225 | |||
226 | export const httpDelete = params => { | ||
227 | params.method = 'delete'; | ||
228 | let { | ||
229 | reqUrl, | ||
230 | data, | ||
231 | headers, | ||
232 | opt, | ||
233 | method | ||
234 | } = analysisParams(params); | ||
235 | // headers["Content-Type"] = "application/json" | ||
236 | return axios.delete(reqUrl, { | ||
237 | data, | ||
238 | headers, | ||
239 | opt | ||
240 | }).then(res => res.data.content); | ||
241 | } | ||
242 | |||
243 | /** | ||
244 | * 请求封装 | ||
245 | * 默认 post 可通过 method设置为get | ||
246 | * | ||
247 | * @param {*} params | ||
248 | * @returns | ||
249 | */ | ||
250 | export const request = params => { | ||
251 | let { | ||
252 | reqUrl, | ||
253 | data, | ||
254 | headers, | ||
255 | opt, | ||
256 | method | ||
257 | } = analysisParams(params); | ||
258 | |||
259 | if (method.toLowerCase() == "post") { | ||
260 | return axios.post(reqUrl, data, { | ||
261 | headers, | ||
262 | opt | ||
263 | }).then(res => res.data.content); | ||
264 | } else { | ||
265 | return axios.get(reqUrl, { | ||
266 | params: data, | ||
267 | headers, | ||
268 | opt | ||
269 | }).then(res => res.data.content); | ||
270 | } | ||
271 | } | ||
272 | |||
273 | /** | ||
274 | * 封装post方法 | ||
275 | * @param {*} params | ||
276 | * data数据是 formdata格式 | ||
277 | * 例如: | ||
278 | * this.file = file | ||
279 | let data = new FormData() //使用formData对象 | ||
280 | data.append('path', '/pro/mzczcradmin/') | ||
281 | data.append('file', file.file) | ||
282 | */ | ||
283 | export const httpFormdata = params => { | ||
284 | let { | ||
285 | reqUrl, | ||
286 | data, | ||
287 | headers, | ||
288 | opt, | ||
289 | method | ||
290 | } = analysisParams(params); | ||
291 | headers["Content-Type"] = "multipart/form-data"; | ||
292 | return axios.post(reqUrl, data, { | ||
293 | headers | ||
294 | }).then(res => res.data.content); | ||
295 | } | ||
296 | |||
297 | export const downloadExcel = (params, fileName) => { | ||
298 | let { | ||
299 | reqUrl, | ||
300 | data, | ||
301 | headers, | ||
302 | config | ||
303 | } = analysisParams(params); | ||
304 | return axios({ | ||
305 | method: 'get', | ||
306 | url: reqUrl, | ||
307 | params: data, | ||
308 | headers: headers, | ||
309 | responseType: 'blob', | ||
310 | ...config | ||
311 | }).then(res => { | ||
312 | let blob = new Blob([res.data], { | ||
313 | type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' | ||
314 | }) | ||
315 | let downloadElement = document.createElement('a') | ||
316 | let href = window.URL.createObjectURL(blob) | ||
317 | downloadElement.style.display = 'none' | ||
318 | downloadElement.href = href | ||
319 | downloadElement.download = fileName //下载后文件名 | ||
320 | document.body.appendChild(downloadElement) | ||
321 | downloadElement.click() //点击下载 | ||
322 | document.body.removeChild(downloadElement) //下载完成移除元素 | ||
323 | window.URL.revokeObjectURL(href) //释放掉blob对象 | ||
324 | }).catch(err => { | ||
325 | console.log('err', err) | ||
326 | Toast({ | ||
327 | message: '下载失败,请重新下载' | ||
328 | }) | ||
329 | }) | ||
330 | } | ||
331 | |||
332 | function getAdminToken() { | ||
333 | try { | ||
334 | let token = getToken(); | ||
335 | if (token != null && token != undefined) { | ||
336 | return token.adminSessionId; | ||
337 | } | ||
338 | return ""; | ||
339 | } catch (e) { | ||
340 | console.error(e); | ||
341 | return ""; | ||
342 | } | ||
343 | } | ||
344 | |||
345 | export function getHeaders() { | ||
346 | return { | ||
347 | 'adminSessionId': getAdminToken(), | ||
348 | } | ||
349 | } | ||
350 | |||
351 | // 导出表格 | ||
352 | export const buildExcelHeader = params => { | ||
353 | let { | ||
354 | reqUrl, | ||
355 | data, | ||
356 | headers | ||
357 | } = analysisParams(params); | ||
358 | let { | ||
359 | filename | ||
360 | } = params; | ||
361 | return axios({ | ||
362 | method: 'get', | ||
363 | url: reqUrl, | ||
364 | params: data, | ||
365 | headers: headers, | ||
366 | responseType: 'blob' | ||
367 | // onDownloadProgress:?config.onDownloadProgress | ||
368 | }).then(res => { | ||
369 | let blob = new Blob([res.data], { | ||
370 | type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' | ||
371 | }) | ||
372 | let downloadElement = document.createElement('a') | ||
373 | let href = window.URL.createObjectURL(blob) | ||
374 | downloadElement.style.display = 'none' | ||
375 | downloadElement.href = href | ||
376 | downloadElement.download = filename //下载后文件名 | ||
377 | document.body.appendChild(downloadElement) | ||
378 | downloadElement.click() //点击下载 | ||
379 | document.body.removeChild(downloadElement) //下载完成移除元素 | ||
380 | window.URL.revokeObjectURL(href) //释放掉blob对象 | ||
381 | }).catch(err => { | ||
382 | console.log("err", err) | ||
383 | Toast({ | ||
384 | message: '下载失败,请重新下载' | ||
385 | }) | ||
386 | }) | ||
387 | } |
src/assets/user/user.jpg
0 → 100644
3.93 KB
src/components/UploadImg/index.vue
0 → 100644
1 | <template> | ||
2 | <div :class="{'hide' : hideUpload}"> | ||
3 | <el-upload | ||
4 | :file-list="fileList" | ||
5 | :action="reqUrl" | ||
6 | :headers="headers" | ||
7 | :onSuccess="onSuccess" | ||
8 | :accept="isImg ? 'image/*' : ''" | ||
9 | list-type="picture-card" | ||
10 | :onPreview="onPreview" | ||
11 | :onRemove="onRemove" | ||
12 | :beforeUpload="beforeUpload" | ||
13 | :limit="limit || 1" | ||
14 | :data="extraData" | ||
15 | :disabled="disabled" | ||
16 | > | ||
17 | <i class="el-icon-plus"></i> | ||
18 | <div slot="tip" class="el-upload__tip">{{tips}}</div> | ||
19 | </el-upload> | ||
20 | <el-dialog :visible.sync="dialogVisible"> | ||
21 | <img width="100%" :src="dialogImageUrl" alt /> | ||
22 | </el-dialog> | ||
23 | <p v-if="sizeTips" class="tips">{{sizeTips}}</p> | ||
24 | </div> | ||
25 | </template> | ||
26 | |||
27 | <script> | ||
28 | /* | ||
29 | * value:当前上传的图片链接 String多图逗号隔开 | ||
30 | * limit:当前最大上传数,默认为1 | ||
31 | * isImg:true=限制上传类型为png或jpg,fales=不限制上传类型,默认为false | ||
32 | * maxFileSize:限制文件上传最大值 | ||
33 | * subPath:图片上传目录 | ||
34 | * disabled: 是否禁用上传F | ||
35 | */ | ||
36 | export default { | ||
37 | name: "UploadImg", | ||
38 | props: [ | ||
39 | "value", | ||
40 | "limit", | ||
41 | "isImg", | ||
42 | "maxFileSize", | ||
43 | "subPath", | ||
44 | "tip", | ||
45 | "disabled", | ||
46 | "sizeTips" | ||
47 | ], | ||
48 | data() { | ||
49 | return { | ||
50 | reqUrl: 'https://api.k.wxpai.cn/bizproxy/tianbaoServiceApi/' + app.api.upload, | ||
51 | headers: app.headers(), | ||
52 | dialogVisible: false, | ||
53 | hideUpload: false, | ||
54 | dialogImageUrl: "", | ||
55 | tips: "", | ||
56 | maxSize: 10 * 1024 * 1024, | ||
57 | fileList: [], | ||
58 | extraData: {} //上传额外参数 | ||
59 | }; | ||
60 | }, | ||
61 | watch: { | ||
62 | value(newVal) { | ||
63 | this.initData(); | ||
64 | } | ||
65 | }, | ||
66 | created() { | ||
67 | this.initData(); | ||
68 | }, | ||
69 | methods: { | ||
70 | initData() { | ||
71 | if (this.value) { | ||
72 | this.fileList = []; | ||
73 | let _value = this.value.split(","); | ||
74 | for (let i = 0; i < _value.length; i++) { | ||
75 | let obj = { | ||
76 | url: _value[i], | ||
77 | uid: i | ||
78 | }; | ||
79 | this.fileList.push(obj); | ||
80 | } | ||
81 | } | ||
82 | this.tips = this.tip; | ||
83 | if (this.subPath) { | ||
84 | this.extraData.subPath = this.subPath; | ||
85 | } | ||
86 | this.isMaxNumber(); | ||
87 | // if (this.isImg && this.maxFileSize) { | ||
88 | // this.tips = | ||
89 | // "只能上传jpg/png文件,且文件不超过" + this.maxFileSize + "K"; | ||
90 | // } else if (this.isImg) { | ||
91 | // this.tips = "只能上传jpg/png文件"; | ||
92 | // } else if (this.maxFileSize > 0) { | ||
93 | // this.tips = "文件不超过" + this.maxFileSize + "K"; | ||
94 | // } | ||
95 | }, | ||
96 | onSuccess(res, file) { | ||
97 | let nowFileList = []; | ||
98 | if (res.code == 200) { | ||
99 | this.fileList.push({ | ||
100 | url: res.content | ||
101 | }); | ||
102 | this.isMaxNumber(); | ||
103 | for (let i = 0; i < this.fileList.length; i++) { | ||
104 | nowFileList.push(this.fileList[i].url); | ||
105 | } | ||
106 | this.$emit("input", nowFileList.join(",")); | ||
107 | } else { | ||
108 | this.$notify.error({ | ||
109 | title: "错误", | ||
110 | message: res.errMsg | ||
111 | }); | ||
112 | } | ||
113 | }, | ||
114 | onPreview(file) { | ||
115 | this.dialogImageUrl = file.url; | ||
116 | this.dialogVisible = true; | ||
117 | }, | ||
118 | beforeUpload(file) { | ||
119 | if (this.maxFileSize) { | ||
120 | const isSize = file.size / 1024 < this.maxFileSize; | ||
121 | if (!isSize) { | ||
122 | this.$message.error( | ||
123 | "上传图片大小不能超过 " + this.maxFileSize + "K!" | ||
124 | ); | ||
125 | return false; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | return true; | ||
130 | }, | ||
131 | onRemove(file, fileList) { | ||
132 | let nowFileList = []; | ||
133 | for (let i = 0; i < this.fileList.length; i++) { | ||
134 | if (this.fileList[i].uid == file.uid) { | ||
135 | this.fileList.splice(i, 1); | ||
136 | for (let i = 0; i < this.fileList.length; i++) { | ||
137 | nowFileList.push(this.fileList[i].url); | ||
138 | } | ||
139 | this.isMaxNumber(); | ||
140 | break; | ||
141 | } | ||
142 | } | ||
143 | this.$emit("input", nowFileList.join(",")); | ||
144 | }, | ||
145 | isMaxNumber() { | ||
146 | if (this.limit) { | ||
147 | this.hideUpload = this.limit <= this.fileList.length; | ||
148 | } else { | ||
149 | this.hideUpload = this.fileList.length > 0; | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | }; | ||
154 | </script> | ||
155 | |||
156 | <style lang="scss" scoped> | ||
157 | .el-upload__tip { | ||
158 | // margin-top: -15px; | ||
159 | } | ||
160 | .hide /deep/.el-upload--picture-card { | ||
161 | display: none; | ||
162 | } | ||
163 | .tips { | ||
164 | margin: 0; | ||
165 | font-size: 12px; | ||
166 | line-height: 12px; | ||
167 | } | ||
168 | </style> |
src/components/WangEditor/index.vue
0 → 100644
1 | <template> | ||
2 | <div class="page" style="border: 1px solid #ccc;"> | ||
3 | <Toolbar | ||
4 | style="border-bottom: 1px solid #ccc" | ||
5 | :editor="editor" | ||
6 | :defaultConfig="toolbarConfig" | ||
7 | :mode="mode" | ||
8 | /> | ||
9 | <Editor | ||
10 | style="height: 500px; overflow-y: hidden;" | ||
11 | v-model="html" | ||
12 | :defaultConfig="editorConfig" | ||
13 | :mode="mode" | ||
14 | @onCreated="onCreated" | ||
15 | /> | ||
16 | </div> | ||
17 | </template><script> | ||
18 | import Vue from "vue"; | ||
19 | import { Editor, Toolbar } from "@wangeditor/editor-for-vue"; | ||
20 | |||
21 | export default Vue.extend({ | ||
22 | props: ["value", "subPath"], | ||
23 | components: { Editor, Toolbar }, | ||
24 | data() { | ||
25 | return { | ||
26 | editor: null, | ||
27 | html: "<p><br></p>", | ||
28 | toolbarConfig: { | ||
29 | excludeKeys: [ | ||
30 | "insertLink", | ||
31 | "todo", | ||
32 | "fullScreen", | ||
33 | "fontFamily", | ||
34 | "lineHeight", | ||
35 | "insertTable", | ||
36 | "codeBlock" | ||
37 | ] | ||
38 | }, | ||
39 | editorConfig: { | ||
40 | placeholder: "请输入内容...", | ||
41 | // autoFocus: false, | ||
42 | |||
43 | // 所有的菜单配置,都要在 MENU_CONF 属性下 | ||
44 | MENU_CONF: { | ||
45 | uploadImage: { | ||
46 | fieldName: "file", | ||
47 | server: | ||
48 | "https://api.k.wxpai.cn/bizproxy/tianbaoServiceApi/" + | ||
49 | app.api.upload, | ||
50 | meta: { | ||
51 | subPath: this.subPath | ||
52 | }, | ||
53 | customInsert(res, insertFn) { | ||
54 | console.log(res); | ||
55 | // res 即服务端的返回结果 | ||
56 | |||
57 | // 从 res 中找到 url alt href ,然后插图图片 | ||
58 | insertFn(res.content, "", ""); | ||
59 | } | ||
60 | }, | ||
61 | |||
62 | uploadVideo: { | ||
63 | fieldName: "file", | ||
64 | server: | ||
65 | "https://api.k.wxpai.cn/bizproxy/tianbaoServiceApi/" + | ||
66 | app.api.upload, | ||
67 | meta: { | ||
68 | subPath: this.subPath | ||
69 | }, | ||
70 | customInsert(res, insertFn) { | ||
71 | console.log(res); | ||
72 | // res 即服务端的返回结果 | ||
73 | |||
74 | // 从 res 中找到 url alt href ,然后插图图片 | ||
75 | insertFn(res.content, "", ""); | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | }, | ||
80 | mode: "default" // or 'simple' | ||
81 | }; | ||
82 | }, | ||
83 | watch: { | ||
84 | html(newVal, oldVal) { | ||
85 | this.$emit("input", newVal); | ||
86 | } | ||
87 | }, | ||
88 | methods: { | ||
89 | onCreated(editor) { | ||
90 | this.editor = Object.seal(editor); // 一定要用 Object.seal() ,否则会报错 | ||
91 | }, | ||
92 | onCreated(editor) { | ||
93 | this.editor = Object.seal(editor); // 【注意】一定要用 Object.seal() 否则会报错 | ||
94 | editor.on("modalOrPanelShow", modalOrPanel => {}); | ||
95 | // 可监听 `modalOrPanelShow` 和 `modalOrPanelHide` 自定义事件来设置样式、蒙层 | ||
96 | // this.editor.on("modalOrPanelShow", modalOrPanel => { | ||
97 | // modalOrPanel.isShow = false; | ||
98 | // // modalOrPanel.$elem[0].style.display = "none"; | ||
99 | // // if (modalOrPanel.type !== "modal") return; | ||
100 | // // const { $elem } = modalOrPanel; // modal element | ||
101 | |||
102 | // // 设置 modal 样式(定位、z-index) | ||
103 | // // 显示蒙层 | ||
104 | // }); | ||
105 | this.editor.on("modalOrPanelHide", () => { | ||
106 | // 隐藏蒙层 | ||
107 | }); | ||
108 | }, | ||
109 | onOk() { | ||
110 | this.editor.restoreSelection(); | ||
111 | SlateTransforms.setNodes( | ||
112 | this.editor, | ||
113 | { alt: this.alt, href: this.href }, | ||
114 | { match: n => SlateElement.isElement(n) } | ||
115 | ); | ||
116 | }, | ||
117 | onChange(editor) { | ||
118 | console.log("onChange", editor.getHtml()); // onChange 时获取编辑器最新内容 | ||
119 | // console.log(this.editor.getFragment()); | ||
120 | } | ||
121 | }, | ||
122 | mounted() { | ||
123 | setTimeout(() => { | ||
124 | this.html = this.value; | ||
125 | }, 500); | ||
126 | }, | ||
127 | beforeDestroy() { | ||
128 | const editor = this.editor; | ||
129 | if (editor == null) return; | ||
130 | editor.destroy(); // 组件销毁时,及时销毁编辑器 | ||
131 | } | ||
132 | }); | ||
133 | </script> | ||
134 | <style src="@wangeditor/editor/dist/css/style.css"></style> | ||
135 | <style lang="scss" scoped> | ||
136 | </style> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -4,7 +4,6 @@ import 'normalize.css/normalize.css' // A modern alternative to CSS resets | ... | @@ -4,7 +4,6 @@ import 'normalize.css/normalize.css' // A modern alternative to CSS resets |
4 | 4 | ||
5 | import ElementUI from 'element-ui' | 5 | import ElementUI from 'element-ui' |
6 | import 'element-ui/lib/theme-chalk/index.css' | 6 | import 'element-ui/lib/theme-chalk/index.css' |
7 | import locale from 'element-ui/lib/locale/lang/en' // lang i18n | ||
8 | 7 | ||
9 | import '@/styles/index.scss' // global css | 8 | import '@/styles/index.scss' // global css |
10 | 9 | ||
... | @@ -13,7 +12,17 @@ import store from './store' | ... | @@ -13,7 +12,17 @@ import store from './store' |
13 | import router from './router' | 12 | import router from './router' |
14 | 13 | ||
15 | import '@/icons' // icon | 14 | import '@/icons' // icon |
16 | import '@/permission' // permission control | 15 | // import '@/permission' // permission control |
16 | |||
17 | |||
18 | import { | ||
19 | httpGet, | ||
20 | httpPost, | ||
21 | httpDelete, | ||
22 | httpFormdata, | ||
23 | getHeaders, | ||
24 | downloadExcel | ||
25 | } from '@/api/fetch-api-new.js' | ||
17 | 26 | ||
18 | 27 | ||
19 | /** | 28 | /** |
... | @@ -24,12 +33,26 @@ import '@/permission' // permission control | ... | @@ -24,12 +33,26 @@ import '@/permission' // permission control |
24 | * it will intercept your request, so you won't see the request in the network. | 33 | * it will intercept your request, so you won't see the request in the network. |
25 | * If you remove `../mock` it will automatically request easy-mock data. | 34 | * If you remove `../mock` it will automatically request easy-mock data. |
26 | */ | 35 | */ |
27 | import '../mock' // simulation data | 36 | // import '../mock' // simulation data |
28 | 37 | ||
29 | Vue.use(ElementUI, { locale }) | 38 | Vue.use(ElementUI) |
30 | 39 | ||
31 | Vue.config.productionTip = false | 40 | Vue.config.productionTip = false |
32 | 41 | ||
42 | |||
43 | // 配置api | ||
44 | let api = require('@/api/api'); | ||
45 | // 挂载全局app | ||
46 | app.api = api; | ||
47 | app.get = httpGet; | ||
48 | app.post = httpPost; | ||
49 | app.delete = httpDelete; | ||
50 | app.form = httpFormdata; | ||
51 | app.headers = getHeaders; | ||
52 | app.downloadExcel = downloadExcel; | ||
53 | app.router = router; | ||
54 | window.app = app; | ||
55 | |||
33 | new Vue({ | 56 | new Vue({ |
34 | el: '#app', | 57 | el: '#app', |
35 | router, | 58 | router, | ... | ... |
... | @@ -114,8 +114,7 @@ export const constantRouterMap = [{ | ... | @@ -114,8 +114,7 @@ export const constantRouterMap = [{ |
114 | title: '天宝计算器', | 114 | title: '天宝计算器', |
115 | icon: 'nested' | 115 | icon: 'nested' |
116 | }, | 116 | }, |
117 | children: [ | 117 | children: [{ |
118 | { | ||
119 | path: '/calculator/pvpage', | 118 | path: '/calculator/pvpage', |
120 | name: 'pvpage', | 119 | name: 'pvpage', |
121 | component: () => import('@/views/calculator/pvpage'), | 120 | component: () => import('@/views/calculator/pvpage'), |
... | @@ -159,8 +158,7 @@ export const constantRouterMap = [{ | ... | @@ -159,8 +158,7 @@ export const constantRouterMap = [{ |
159 | title: '教育教学', | 158 | title: '教育教学', |
160 | icon: 'nested' | 159 | icon: 'nested' |
161 | }, | 160 | }, |
162 | children: [ | 161 | children: [{ |
163 | { | ||
164 | path: '/edu/live', | 162 | path: '/edu/live', |
165 | name: 'live', | 163 | name: 'live', |
166 | component: () => import('@/views/live/index'), | 164 | component: () => import('@/views/live/index'), |
... | @@ -253,6 +251,104 @@ export const constantRouterMap = [{ | ... | @@ -253,6 +251,104 @@ export const constantRouterMap = [{ |
253 | ] | 251 | ] |
254 | }, | 252 | }, |
255 | 253 | ||
254 | |||
255 | |||
256 | { | ||
257 | path: '/artice', | ||
258 | component: Layout, | ||
259 | redirect: '/artice/list', | ||
260 | name: 'artice', | ||
261 | meta: { | ||
262 | title: '常见问题答疑', | ||
263 | icon: 'nested' | ||
264 | }, | ||
265 | children: [{ | ||
266 | path: '/artice/list', | ||
267 | name: 'articleList', | ||
268 | component: () => import('@/views/Q&A/article/list'), | ||
269 | meta: { | ||
270 | title: '文章列表', | ||
271 | icon: '' | ||
272 | } | ||
273 | }, | ||
274 | { | ||
275 | path: '/artice/detail', | ||
276 | name: 'articleDetail', | ||
277 | component: () => import('@/views/Q&A/article/detail'), | ||
278 | meta: { | ||
279 | title: '设置文章', | ||
280 | icon: '' | ||
281 | }, | ||
282 | hidden: true | ||
283 | }, | ||
284 | { | ||
285 | path: '/report/article', | ||
286 | name: 'reportArticle', | ||
287 | component: () => import('@/views/Q&A/report/article'), | ||
288 | meta: { | ||
289 | title: '文章统计', | ||
290 | icon: '' | ||
291 | } | ||
292 | }, | ||
293 | { | ||
294 | path: '/artice/classify', | ||
295 | name: 'articeClassify', | ||
296 | component: () => import('@/views/Q&A/classify/list'), | ||
297 | meta: { | ||
298 | title: '文章分类', | ||
299 | icon: '' | ||
300 | } | ||
301 | }, | ||
302 | { | ||
303 | path: '/artice/classify/detail', | ||
304 | name: 'articeClassifyDetail', | ||
305 | component: () => import('@/views/Q&A/classify/detail'), | ||
306 | meta: { | ||
307 | title: '设置分类', | ||
308 | icon: '' | ||
309 | }, | ||
310 | hidden: true | ||
311 | }, | ||
312 | { | ||
313 | path: '/report/classify', | ||
314 | name: 'reportClassify', | ||
315 | component: () => import('@/views/Q&A/report/classify'), | ||
316 | meta: { | ||
317 | title: '分类统计', | ||
318 | icon: '' | ||
319 | } | ||
320 | }, | ||
321 | { | ||
322 | path: '/keyword/list', | ||
323 | name: 'keywordList', | ||
324 | component: () => import('@/views/Q&A/keyword/list'), | ||
325 | meta: { | ||
326 | title: '关键词', | ||
327 | icon: '' | ||
328 | } | ||
329 | }, | ||
330 | { | ||
331 | path: '/keyword/detail', | ||
332 | name: 'keywordDetail', | ||
333 | component: () => import('@/views/Q&A/keyword/detail'), | ||
334 | meta: { | ||
335 | title: '设置关键词', | ||
336 | icon: '' | ||
337 | }, | ||
338 | hidden: true | ||
339 | }, | ||
340 | { | ||
341 | path: '/report/keyword', | ||
342 | name: 'reportKeyword', | ||
343 | component: () => import('@/views/Q&A/report/keyword'), | ||
344 | meta: { | ||
345 | title: '关键词统计', | ||
346 | icon: '' | ||
347 | } | ||
348 | }, | ||
349 | ] | ||
350 | }, | ||
351 | |||
256 | // { | 352 | // { |
257 | // path: '/live', | 353 | // path: '/live', |
258 | // component: Layout, | 354 | // component: Layout, | ... | ... |
... | @@ -4,6 +4,6 @@ const getters = { | ... | @@ -4,6 +4,6 @@ const getters = { |
4 | token: state => state.user.token, | 4 | token: state => state.user.token, |
5 | avatar: state => state.user.avatar, | 5 | avatar: state => state.user.avatar, |
6 | name: state => state.user.name, | 6 | name: state => state.user.name, |
7 | roles: state => state.user.roles | 7 | // roles: state => state.user.roles |
8 | } | 8 | } |
9 | export default getters | 9 | export default getters | ... | ... |
1 | import Vue from 'vue' | 1 | import Vue from 'vue' |
2 | import Vuex from 'vuex' | 2 | import Vuex from 'vuex' |
3 | import app from './modules/app' | 3 | import app from './modules/app' |
4 | import user from './modules/user' | 4 | // import user from './modules/user' |
5 | import getters from './getters' | 5 | import getters from './getters' |
6 | 6 | ||
7 | Vue.use(Vuex) | 7 | Vue.use(Vuex) |
... | @@ -9,7 +9,7 @@ Vue.use(Vuex) | ... | @@ -9,7 +9,7 @@ Vue.use(Vuex) |
9 | const store = new Vuex.Store({ | 9 | const store = new Vuex.Store({ |
10 | modules: { | 10 | modules: { |
11 | app, | 11 | app, |
12 | user | 12 | // user |
13 | }, | 13 | }, |
14 | getters | 14 | getters |
15 | }) | 15 | }) | ... | ... |
1 | import { login, logout, getInfo } from '@/api/login' | 1 | import { |
2 | import { getToken, setToken, removeToken } from '@/utils/auth' | 2 | login, |
3 | logout, | ||
4 | getInfo | ||
5 | } from '@/api/login' | ||
6 | import { | ||
7 | getToken, | ||
8 | setToken, | ||
9 | removeToken | ||
10 | } from '@/utils/auth' | ||
3 | 11 | ||
4 | const user = { | 12 | const user = { |
5 | state: { | 13 | state: { |
... | @@ -26,22 +34,22 @@ const user = { | ... | @@ -26,22 +34,22 @@ const user = { |
26 | 34 | ||
27 | actions: { | 35 | actions: { |
28 | // 登录 | 36 | // 登录 |
29 | Login({ commit }, userInfo) { | 37 | Login({ |
38 | commit | ||
39 | }, userInfo) { | ||
30 | const username = userInfo.username.trim() | 40 | const username = userInfo.username.trim() |
31 | return new Promise((resolve, reject) => { | 41 | return new Promise((resolve, reject) => { |
32 | login(username, userInfo.password).then(response => { | 42 | setToken('admin-token') |
33 | const data = response.content | 43 | commit('SET_TOKEN', 'admin-token') |
34 | setToken(data.token) | 44 | resolve() |
35 | commit('SET_TOKEN', data.token) | ||
36 | resolve() | ||
37 | }).catch(error => { | ||
38 | reject(error) | ||
39 | }) | ||
40 | }) | 45 | }) |
41 | }, | 46 | }, |
42 | 47 | ||
43 | // 获取用户信息 | 48 | // 获取用户信息 |
44 | GetInfo({ commit, state }) { | 49 | GetInfo({ |
50 | commit, | ||
51 | state | ||
52 | }) { | ||
45 | return new Promise((resolve, reject) => { | 53 | return new Promise((resolve, reject) => { |
46 | getInfo(state.token).then(response => { | 54 | getInfo(state.token).then(response => { |
47 | const data = response.content | 55 | const data = response.content |
... | @@ -60,7 +68,10 @@ const user = { | ... | @@ -60,7 +68,10 @@ const user = { |
60 | }, | 68 | }, |
61 | 69 | ||
62 | // 登出 | 70 | // 登出 |
63 | LogOut({ commit, state }) { | 71 | LogOut({ |
72 | commit, | ||
73 | state | ||
74 | }) { | ||
64 | return new Promise((resolve, reject) => { | 75 | return new Promise((resolve, reject) => { |
65 | logout(state.token).then(() => { | 76 | logout(state.token).then(() => { |
66 | commit('SET_TOKEN', '') | 77 | commit('SET_TOKEN', '') |
... | @@ -74,7 +85,9 @@ const user = { | ... | @@ -74,7 +85,9 @@ const user = { |
74 | }, | 85 | }, |
75 | 86 | ||
76 | // 前端 登出 | 87 | // 前端 登出 |
77 | FedLogOut({ commit }) { | 88 | FedLogOut({ |
89 | commit | ||
90 | }) { | ||
78 | return new Promise(resolve => { | 91 | return new Promise(resolve => { |
79 | commit('SET_TOKEN', '') | 92 | commit('SET_TOKEN', '') |
80 | removeToken() | 93 | removeToken() | ... | ... |
... | @@ -9,6 +9,11 @@ | ... | @@ -9,6 +9,11 @@ |
9 | display: none; | 9 | display: none; |
10 | } | 10 | } |
11 | 11 | ||
12 | .dialog-footer{ | ||
13 | display: flex; | ||
14 | justify-content: flex-end; | ||
15 | } | ||
16 | |||
12 | //暂时性解决diolag 问题 https://github.com/ElemeFE/element/issues/2461 | 17 | //暂时性解决diolag 问题 https://github.com/ElemeFE/element/issues/2461 |
13 | .el-dialog { | 18 | .el-dialog { |
14 | transform: none; | 19 | transform: none; | ... | ... |
... | @@ -76,3 +76,29 @@ a:hover { | ... | @@ -76,3 +76,29 @@ a:hover { |
76 | .app-container { | 76 | .app-container { |
77 | padding: 20px; | 77 | padding: 20px; |
78 | } | 78 | } |
79 | |||
80 | .tablePage { | ||
81 | padding: 30px; | ||
82 | } | ||
83 | |||
84 | .fixed-bottom { | ||
85 | background-color: #fefefe; | ||
86 | text-align: center; | ||
87 | padding: 15px !important; | ||
88 | text-align: right; | ||
89 | } | ||
90 | |||
91 | |||
92 | .editPage { | ||
93 | margin: 30px 20%; | ||
94 | padding: 30px; | ||
95 | box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.1); | ||
96 | } | ||
97 | |||
98 | .pointer { | ||
99 | cursor: pointer; | ||
100 | } | ||
101 | |||
102 | .el-date-editor .el-range-separator { | ||
103 | padding: 0; | ||
104 | } | ... | ... |
... | @@ -25,50 +25,25 @@ service.interceptors.request.use( | ... | @@ -25,50 +25,25 @@ service.interceptors.request.use( |
25 | ) | 25 | ) |
26 | 26 | ||
27 | // response 拦截器 | 27 | // response 拦截器 |
28 | service.interceptors.response.use( | 28 | // service.interceptors.response.use( |
29 | response => { | 29 | // response => { |
30 | /** | 30 | // /** |
31 | * code为非20000是抛错 可结合自己业务进行修改 | 31 | // * code为非20000是抛错 可结合自己业务进行修改 |
32 | */ | 32 | // */ |
33 | // 业务数据 | 33 | // // 业务数据 |
34 | const res = response.data | 34 | // const res = response.data |
35 | if (res.code !== 200) { | 35 | // console.log(response.data) |
36 | Message({ | 36 | // return response.data |
37 | message: res.message, | 37 | // }, |
38 | type: 'error', | 38 | // error => { |
39 | duration: 5 * 1000 | 39 | // console.log('err' + error) // for debug |
40 | }) | 40 | // Message({ |
41 | 41 | // message: error.message, | |
42 | // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了; | 42 | // type: 'error', |
43 | if (res.code === 50008 || res.code === 50012 || res.code === 50014) { | 43 | // duration: 5 * 1000 |
44 | MessageBox.confirm( | 44 | // }) |
45 | '你已被登出,可以取消继续留在该页面,或者重新登录', | 45 | // return Promise.reject(error) |
46 | '确定登出', | 46 | // } |
47 | { | 47 | // ) |
48 | confirmButtonText: '重新登录', | ||
49 | cancelButtonText: '取消', | ||
50 | type: 'warning' | ||
51 | } | ||
52 | ).then(() => { | ||
53 | store.dispatch('FedLogOut').then(() => { | ||
54 | location.reload() // 为了重新实例化vue-router对象 避免bug | ||
55 | }) | ||
56 | }) | ||
57 | } | ||
58 | return Promise.reject('error') | ||
59 | } else { | ||
60 | return response.data | ||
61 | } | ||
62 | }, | ||
63 | error => { | ||
64 | console.log('err' + error) // for debug | ||
65 | Message({ | ||
66 | message: error.message, | ||
67 | type: 'error', | ||
68 | duration: 5 * 1000 | ||
69 | }) | ||
70 | return Promise.reject(error) | ||
71 | } | ||
72 | ) | ||
73 | 48 | ||
74 | export default service | 49 | export default service | ... | ... |
src/utils/utils.js
0 → 100644
1 | import app from "@/store/modules/app"; | ||
2 | |||
3 | // 正在表达式 | ||
4 | export const REGEXPS = { | ||
5 | "mobile": /^1\d{10}$/, | ||
6 | "email": /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/, | ||
7 | "password": /^[a-zA-Z0-9]{8,16}$/, | ||
8 | } | ||
9 | |||
10 | export function isExist(superAdmin, arr, val) { | ||
11 | if (superAdmin == 1) { | ||
12 | return true; | ||
13 | } else { | ||
14 | arr = arr ? arr : []; | ||
15 | if (arr.indexOf(val) != -1) { | ||
16 | return true; | ||
17 | } else { | ||
18 | return false; | ||
19 | } | ||
20 | } | ||
21 | } | ||
22 | |||
23 | // 验证手机 | ||
24 | export function checkMobile(str) { | ||
25 | return REGEXPS.mobile.test(str); | ||
26 | } | ||
27 | |||
28 | // 验证邮箱 | ||
29 | export function checkEmail(str) { | ||
30 | return REGEXPS.email.test(str); | ||
31 | } | ||
32 | |||
33 | // 检查密码 密码格式8-16位数字,字母校验 | ||
34 | export function checkPassword(str) { | ||
35 | return REGEXPS.password.test(str); | ||
36 | } | ||
37 | |||
38 | // 获取图片内src | ||
39 | export function getImgSrc(str) { | ||
40 | let imgReg = /<img.*?(?:>|\/>)/gi; //获取img的正则表达式 | ||
41 | let srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/gi; //获取所有src的正则表达式 | ||
42 | let imgList = str.match(imgReg); //imgList 为包含所有img标签的数组 | ||
43 | let srcList = str.match(srcReg); //srcList 为包含所有src标签的数组 | ||
44 | return srcList; | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | * 时间戳格式化(yyyy-MM-dd hh:mm:ss) | ||
49 | * @param {*} timestamp 时间戳 | ||
50 | * @param {*} format 格式 yyyy-MM-dd hh:mm:ss | ||
51 | */ | ||
52 | export const timestampFormat = (timestamp, format) => { | ||
53 | Date.prototype.Format = function (fmt) { | ||
54 | var o = { | ||
55 | "M+": this.getMonth() + 1, //月份 | ||
56 | "d+": this.getDate(), //日 | ||
57 | "h+": this.getHours(), //小时 | ||
58 | "m+": this.getMinutes(), //分 | ||
59 | "s+": this.getSeconds(), //秒 | ||
60 | "q+": Math.floor((this.getMonth() + 3) / 3), //季度 | ||
61 | "S": this.getMilliseconds() //毫秒 | ||
62 | }; | ||
63 | if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); | ||
64 | for (var k in o) { | ||
65 | if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); | ||
66 | } | ||
67 | return fmt; | ||
68 | } | ||
69 | |||
70 | if (timestamp && timestamp.length == 10) timestamp += "000"; | ||
71 | |||
72 | var date = new Date(); | ||
73 | if (timestamp) date.setTime(timestamp); | ||
74 | if (format == null || format == "") { | ||
75 | format = "yyyy-MM-dd hh:mm:ss"; | ||
76 | } | ||
77 | return date.Format(format); | ||
78 | }; | ||
79 | |||
80 | /** | ||
81 | * 复制内容到剪切板 | ||
82 | * @param val 复制文本内容 | ||
83 | * @param tips 复制成功提示,为空不提示 | ||
84 | */ | ||
85 | export function copyVal(val, tips) { | ||
86 | let oInput = document.createElement('input'); | ||
87 | oInput.value = val; | ||
88 | document.body.appendChild(oInput); | ||
89 | oInput.select(); | ||
90 | document.execCommand("Copy"); | ||
91 | if (tips) { | ||
92 | this.$message({ | ||
93 | message: tips, | ||
94 | type: 'success' | ||
95 | }); | ||
96 | } | ||
97 | oInput.remove() | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * 链接参数转换为obj | ||
102 | * 入参 完整链接 | ||
103 | * @param {*} url | ||
104 | */ | ||
105 | export function param2Obj(url) { | ||
106 | const search = url.split("?")[1]; | ||
107 | if (!search) { | ||
108 | return {}; | ||
109 | } | ||
110 | return JSON.parse( | ||
111 | '{"' + | ||
112 | decodeURIComponent(search) | ||
113 | .replace(/"/g, '\\"') | ||
114 | .replace(/&/g, '","') | ||
115 | .replace(/=/g, '":"') + | ||
116 | '"}' | ||
117 | ); | ||
118 | } | ||
119 | |||
120 | |||
121 | /** | ||
122 | * 获取环境信息 | ||
123 | * @return {Object} 环境信息对象 | ||
124 | */ | ||
125 | export function getEnv() { | ||
126 | var nav = window.navigator; | ||
127 | var env = { | ||
128 | iphone: false, | ||
129 | ipad: false, | ||
130 | android: false, | ||
131 | pc: false, | ||
132 | ios: false, | ||
133 | ver: "0" | ||
134 | }; | ||
135 | |||
136 | var ua = nav.userAgent; | ||
137 | var android = ua.match(/(Android)\s+([\d.]+)/); | ||
138 | var ipad = ua.match(/(iPad).*OS\s([\d_]+)/); | ||
139 | var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/); | ||
140 | if (ipad) { | ||
141 | env.ipad = (ipad[1] && true) || false; | ||
142 | env.ver = (ipad[2] && ipad[2].replace(/-/g, ".")) || ""; | ||
143 | env.ios = true; | ||
144 | } else if (iphone) { | ||
145 | env.iphone = (iphone[1] && true) || false; | ||
146 | env.ver = (iphone[2] && iphone[2].replace(/-/g, ".")) || ""; | ||
147 | env.ios = true; | ||
148 | } else if (android) { | ||
149 | env.android = (android[1] && true) || false; | ||
150 | env.ver = android[2]; | ||
151 | } else { | ||
152 | env.pc = true; | ||
153 | } | ||
154 | |||
155 | return env; | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * 生成uuid | ||
160 | * @param {*} unix_stamp | ||
161 | */ | ||
162 | export function uuid() { | ||
163 | let s = []; | ||
164 | let hexDigits = "0123456789abcdef"; | ||
165 | for (let i = 0; i < 32; i++) { | ||
166 | s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); | ||
167 | } | ||
168 | s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010 | ||
169 | s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01 | ||
170 | // s[8] = s[13] = s[18] = s[23] = "-"; | ||
171 | |||
172 | let uuid = s.join(""); | ||
173 | return uuid; | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * 设定页面 title | ||
178 | * @param {[type]} title [description] | ||
179 | */ | ||
180 | export function setTitle(title) { | ||
181 | if (!title) { | ||
182 | return; | ||
183 | } | ||
184 | document.title = title; | ||
185 | // if (ENV.ios && navigator.userAgent.toLowerCase().indexOf("micromessenger") !== -1) { | ||
186 | // 修复微信端IOS无法修改document.title的情况 | ||
187 | if ( | ||
188 | getEnv().ios && | ||
189 | (navigator.userAgent.toLowerCase().indexOf("micromessenger") !== -1 || | ||
190 | navigator.userAgent.toLowerCase().indexOf("alipay") !== -1) | ||
191 | ) { | ||
192 | //修复IOS微信端和支付宝无法修改document.title的情况 | ||
193 | var $iframe = document.createElement("iframe"); | ||
194 | $iframe.className = "C-hiddenIframe"; | ||
195 | $iframe.src = "/" + location.pathname.split("/")[1] + "/favicon.ico"; | ||
196 | $iframe.style.visibility = "hidden"; | ||
197 | $iframe.style.width = "1px"; | ||
198 | $iframe.style.height = "1px"; | ||
199 | $iframe.onload = function onIframeLoad() { | ||
200 | setTimeout(function () { | ||
201 | $iframe.onload = null; | ||
202 | onIframeLoad = null; | ||
203 | document.body.removeChild($iframe); | ||
204 | $iframe = null; | ||
205 | }, 0); | ||
206 | }; | ||
207 | document.body.appendChild($iframe); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | // 为链接添加参数 | ||
212 | export function addQuery(url, query) { | ||
213 | query = query || {}; | ||
214 | query = (function (query) { | ||
215 | var q = []; | ||
216 | Object.keys(query).forEach(function (_q) { | ||
217 | q.push(_q + "=" + query[_q]); | ||
218 | }); | ||
219 | return q.join("&"); | ||
220 | })(query); | ||
221 | if (url.indexOf("?") !== -1) { | ||
222 | url += "&" + query; | ||
223 | } else { | ||
224 | url += "?" + query; | ||
225 | } | ||
226 | return url; | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * 获得当前页面的path | ||
231 | * @return {String} 页面path | ||
232 | */ | ||
233 | export function getPath() { | ||
234 | var path = window.location.hash; | ||
235 | path = path || "#/"; | ||
236 | path = path === "#/" ? "#/index" : path; | ||
237 | path = path.split("?"); | ||
238 | return path[0]; | ||
239 | } | ||
240 | |||
241 | // 获取 url 参数 | ||
242 | export function getQuery(name) { | ||
243 | return ( | ||
244 | decodeURIComponent( | ||
245 | (new RegExp("[?|&]" + name + "=" + "([^&;]+?)(&|#|;|$)").exec( | ||
246 | location.href | ||
247 | ) || [, ""])[1].replace(/\+/g, "%20") | ||
248 | ) || null | ||
249 | ); | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * 升序排列 | ||
254 | * @param name 主要参数 | ||
255 | * @param minor 次要参数 主要参数相同时,比较次要参数 | ||
256 | */ | ||
257 | export function ascSort(name, minor) { | ||
258 | return function (o, p) { | ||
259 | var a, b; | ||
260 | if (o && p && typeof o === "object" && typeof p === "object") { | ||
261 | a = o[name]; | ||
262 | b = p[name]; | ||
263 | if (a === b) { | ||
264 | return typeof minor === "function" ? minor(o, p) : 0; | ||
265 | } | ||
266 | if (typeof a === typeof b) { | ||
267 | return a < b ? -1 : 1; | ||
268 | } | ||
269 | return typeof a < typeof b ? -1 : 1; | ||
270 | } else { | ||
271 | // throw ("error"); | ||
272 | return null; | ||
273 | } | ||
274 | }; | ||
275 | } | ||
276 | |||
277 | /** | ||
278 | * 升序排列 | ||
279 | * @param name 主要参数 | ||
280 | * @param minor 次要参数 主要参数相同时,比较次要参数 | ||
281 | */ | ||
282 | export function descSort(name, minor) { | ||
283 | return function (o, p) { | ||
284 | var a, b; | ||
285 | if (o && p && typeof o === "object" && typeof p === "object") { | ||
286 | a = o[name]; | ||
287 | b = p[name]; | ||
288 | if (a === b) { | ||
289 | return typeof minor === "function" ? minor(o, p) : 0; | ||
290 | } | ||
291 | if (typeof a === typeof b) { | ||
292 | return a > b ? -1 : 1; | ||
293 | } | ||
294 | return typeof a > typeof b ? -1 : 1; | ||
295 | } else { | ||
296 | // throw ("error"); | ||
297 | return null; | ||
298 | } | ||
299 | }; | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * 从数组中获取 key未value的对象 | ||
304 | * @param {*} value | ||
305 | * @param {*} key | ||
306 | * @param {*} list | ||
307 | */ | ||
308 | export function getObjByListKeyValue(value, key, list) { | ||
309 | let result = null; | ||
310 | list.forEach(element => { | ||
311 | if (element[key + ""] == value) { | ||
312 | result = element; | ||
313 | } | ||
314 | }); | ||
315 | return result; | ||
316 | } | ||
317 | |||
318 | /** | ||
319 | * 把 \n换行符转换成<br> | ||
320 | * 转换后需要用 v-html渲染 | ||
321 | * 用{{}}会当成字符串把 html渲染出来 | ||
322 | */ | ||
323 | export function formatBr(str) { | ||
324 | str = str.replace(/\n/g, "<br/>"); | ||
325 | return str; | ||
326 | } | ||
327 | |||
328 | // dd-MM-yyyy转yyyy-MM-dd | ||
329 | export function ddMMyyyy2yyyyMMdd(str) { | ||
330 | return str.replace(/-/g, "").replace(/^(\d{2})(\d{2})(\d{4})$/, "$3-$2-$1"); | ||
331 | } | ||
332 | |||
333 | /** | ||
334 | * 获取数字的小数位数 | ||
335 | * @param {*} num | ||
336 | */ | ||
337 | export function getDot(num) { | ||
338 | var numStr = num + ""; | ||
339 | var index = numStr.indexOf("."); | ||
340 | if (index == -1) { | ||
341 | return 0; | ||
342 | } else { | ||
343 | var t = numStr.slice(index + 1) || ''; | ||
344 | return t.length; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | /** | ||
349 | * 深复制 | ||
350 | * @param {*} source | ||
351 | * @returns | ||
352 | */ | ||
353 | export function deepClone(source) { | ||
354 | if (!source && typeof source !== 'object') { | ||
355 | throw new Error('error arguments', 'deepClone') | ||
356 | } | ||
357 | const targetObj = source.constructor === Array ? [] : {} | ||
358 | Object.keys(source).forEach(keys => { | ||
359 | if (source[keys] && typeof source[keys] === 'object') { | ||
360 | targetObj[keys] = deepClone(source[keys]) | ||
361 | } else { | ||
362 | targetObj[keys] = source[keys] | ||
363 | } | ||
364 | }) | ||
365 | return targetObj | ||
366 | } | ||
367 | |||
368 | /** | ||
369 | * @desc 函数防抖 | ||
370 | * @param func 函数 | ||
371 | * @param wait 延迟执行毫秒数 | ||
372 | * @param immediate true 表立即执行,false 表非立即执行 | ||
373 | */ | ||
374 | export function debounce(func, wait, immediate) { | ||
375 | let timeout; | ||
376 | |||
377 | return function () { | ||
378 | let context = this; | ||
379 | let args = arguments; | ||
380 | |||
381 | if (timeout) clearTimeout(timeout); | ||
382 | if (immediate) { | ||
383 | var callNow = !timeout; | ||
384 | timeout = setTimeout(() => { | ||
385 | timeout = null; | ||
386 | }, wait); | ||
387 | if (callNow) func.apply(context, args); | ||
388 | } else { | ||
389 | timeout = setTimeout(function () { | ||
390 | func.apply(context, args); | ||
391 | }, wait); | ||
392 | } | ||
393 | }; | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * @desc 函数节流 | ||
398 | * @param func 函数 | ||
399 | * @param wait 延迟执行毫秒数 | ||
400 | * @param type 1 表时间戳版,2 表定时器版 | ||
401 | * 时间戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内结束的时候。 | ||
402 | */ | ||
403 | export function throttle(func, wait, type) { | ||
404 | if (type === 1) { | ||
405 | var previous = 0; | ||
406 | } else if (type === 2) { | ||
407 | var timeout; | ||
408 | } | ||
409 | return function () { | ||
410 | let context = this; | ||
411 | let args = arguments; | ||
412 | if (type === 1) { | ||
413 | let now = Date.now(); | ||
414 | |||
415 | if (now - previous > wait) { | ||
416 | func.apply(context, args); | ||
417 | previous = now; | ||
418 | } | ||
419 | } else if (type === 2) { | ||
420 | if (!timeout) { | ||
421 | timeout = setTimeout(() => { | ||
422 | timeout = null; | ||
423 | func.apply(context, args); | ||
424 | }, wait); | ||
425 | } | ||
426 | } | ||
427 | }; | ||
428 | } | ||
429 | |||
430 | export function timestampToTime(row) { | ||
431 | if (row === 0 || row === '' || row == undefined) { | ||
432 | return '' | ||
433 | } | ||
434 | var date = new Date(Number(row)) | ||
435 | // var Y = date.getFullYear() + '-' | ||
436 | // var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-' | ||
437 | // var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ' | ||
438 | // var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':' | ||
439 | // var m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':' | ||
440 | // var s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds() | ||
441 | // return Y + M + D + h + m + s | ||
442 | |||
443 | var Y = date.getFullYear() + '.' | ||
444 | var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '.' | ||
445 | var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ' | ||
446 | var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':' | ||
447 | var m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) | ||
448 | return Y + M + D + h + m | ||
449 | } |
src/views/Q&A/article/detail.vue
0 → 100644
1 | <template> | ||
2 | <div class="editPage"> | ||
3 | <el-form | ||
4 | :model="editForm" | ||
5 | :loading="loading" | ||
6 | ref="editForm" | ||
7 | label-position="right" | ||
8 | label-width="auto" | ||
9 | style="padding-right: 30px" | ||
10 | v-loading="loading" | ||
11 | element-loading-text="操作中" | ||
12 | element-loading-spinner="el-icon-loading" | ||
13 | element-loading-background="rgba(255, 255, 255, 0.9)" | ||
14 | > | ||
15 | <el-form-item | ||
16 | label="所属分类" | ||
17 | prop="classifyCode" | ||
18 | :rules="{ required: true, message: '所属分类不能为空', trigger: 'change' }" | ||
19 | > | ||
20 | <el-select class="maxItem" v-model="editForm.classifyCode" placeholder="请选择所属分类"> | ||
21 | <el-option | ||
22 | v-for="item in classifyList" | ||
23 | :key="item.classifyCode" | ||
24 | :label="item.classifyName" | ||
25 | :value="item.classifyCode" | ||
26 | ></el-option> | ||
27 | </el-select> | ||
28 | </el-form-item> | ||
29 | |||
30 | <el-form-item | ||
31 | label="标题" | ||
32 | prop="articleTitle" | ||
33 | :rules="{ required: true, message: '标题不能为空', trigger: 'blur' }" | ||
34 | > | ||
35 | <el-input v-model="editForm.articleTitle" placeholder="请输入标题"></el-input> | ||
36 | </el-form-item> | ||
37 | |||
38 | <el-form-item | ||
39 | label="内容" | ||
40 | prop="content" | ||
41 | :rules="{ required: true, message: '内容不能为空', trigger: 'blur' }" | ||
42 | > | ||
43 | <WangEditor v-model="editForm.content" :subPath="subPath" /> | ||
44 | </el-form-item> | ||
45 | |||
46 | <el-form-item label="附件"> | ||
47 | <el-upload | ||
48 | class="upload-demo" | ||
49 | :onSuccess="successFile" | ||
50 | :onRemove="removeFile" | ||
51 | :file-list="editForm.attachments" | ||
52 | drag | ||
53 | action="https://api.k.wxpai.cn/bizproxy/tianbaoServiceApi/common/upload" | ||
54 | multiple | ||
55 | :data="extraData" | ||
56 | accept="application/pdf" | ||
57 | > | ||
58 | <i class="el-icon-upload"></i> | ||
59 | <div class="el-upload__text"> | ||
60 | 将文件拖到此处,或 | ||
61 | <em>点击上传</em> | ||
62 | </div> | ||
63 | <div class="el-upload__tip" slot="tip">*只能上传pdf文件</div> | ||
64 | </el-upload> | ||
65 | </el-form-item> | ||
66 | |||
67 | <el-form-item label="排序值"> | ||
68 | <el-input-number v-model="editForm.orderId" :min="0"></el-input-number> | ||
69 | </el-form-item> | ||
70 | <el-form-item label="是否在线" prop="onlineStatus"> | ||
71 | <el-switch | ||
72 | v-model="editForm.onlineStatus" | ||
73 | inactive-color="rgb(234,236,240)" | ||
74 | ></el-switch> | ||
75 | </el-form-item> | ||
76 | <el-form-item label="是否置顶" prop="inTop"> | ||
77 | <el-switch | ||
78 | v-model="editForm.inTop" | ||
79 | inactive-color="rgb(234,236,240)" | ||
80 | ></el-switch> | ||
81 | </el-form-item> | ||
82 | </el-form> | ||
83 | <div slot="footer" class="dialog-footer" style="padding-right:30px"> | ||
84 | <el-button @click="componentClose">取 消</el-button> | ||
85 | <el-button type="primary" @click="componentSubmit" :disabled="loading" :loading="loading">确定</el-button> | ||
86 | </div> | ||
87 | </div> | ||
88 | </template> | ||
89 | |||
90 | |||
91 | <script> | ||
92 | import UploadImg from "@/components/UploadImg/index.vue"; | ||
93 | import WangEditor from "@/components/WangEditor/index.vue"; | ||
94 | |||
95 | export default { | ||
96 | props: [], | ||
97 | components: { | ||
98 | UploadImg, | ||
99 | WangEditor | ||
100 | }, | ||
101 | data() { | ||
102 | return { | ||
103 | loading: false, | ||
104 | subPath: "article", | ||
105 | editForm: { | ||
106 | articleCode: null, | ||
107 | classifyCode: null, | ||
108 | articleTitle: null, | ||
109 | articleThumb: 0, | ||
110 | author: null, | ||
111 | content: "", | ||
112 | createTime: 0, | ||
113 | orderId: 0, | ||
114 | onlineStatus: true, | ||
115 | inTop: false, | ||
116 | attachments: [] | ||
117 | }, | ||
118 | classifyList: [], | ||
119 | extraData: { | ||
120 | subPath: "articleFile" | ||
121 | } | ||
122 | }; | ||
123 | }, | ||
124 | mounted() { | ||
125 | this.initData(); | ||
126 | }, | ||
127 | methods: { | ||
128 | async initData() { | ||
129 | this.editForm.articleCode = this.$route.query.articleCode; | ||
130 | if (this.editForm.articleCode != null) { | ||
131 | this.getDetail(); | ||
132 | } | ||
133 | this.getClassifyList(); | ||
134 | }, | ||
135 | getDetail() { | ||
136 | app | ||
137 | .get({ | ||
138 | url: app.api.getArticleDetail, | ||
139 | data: { | ||
140 | articleCode: this.editForm.articleCode | ||
141 | } | ||
142 | }) | ||
143 | .then(res => { | ||
144 | res.inTop = res.inTop == 1 ? true : false; | ||
145 | res.onlineStatus = res.onlineStatus == 1 ? true : false; | ||
146 | |||
147 | if (res.attachments) { | ||
148 | res.attachments = JSON.parse(res.attachments); | ||
149 | } else { | ||
150 | res.attachments = []; | ||
151 | } | ||
152 | |||
153 | this.editForm = res; | ||
154 | }); | ||
155 | }, | ||
156 | getClassifyList() { | ||
157 | app | ||
158 | .get({ url: app.api.getArticleClassify, data: null }) | ||
159 | .then(res => { | ||
160 | this.classifyList = res.list; | ||
161 | }) | ||
162 | .catch(e => {}); | ||
163 | }, | ||
164 | |||
165 | componentSubmit() { | ||
166 | this.$refs["editForm"].validate(valid => { | ||
167 | if (valid) { | ||
168 | if (this.loading) { | ||
169 | return; | ||
170 | } | ||
171 | this.loading = true; | ||
172 | let editForm = JSON.parse(JSON.stringify(this.editForm)); | ||
173 | editForm.inTop = this.editForm.inTop ? 1 : 0; | ||
174 | editForm.onlineStatus = this.editForm.onlineStatus ? 1 : 0; | ||
175 | editForm.createTime = new Date(this.editForm.createTime).getTime(); | ||
176 | if (this.editForm.attachments.length > 0) { | ||
177 | editForm.attachments = JSON.stringify(this.editForm.attachments); | ||
178 | } else { | ||
179 | editForm.attachments = ""; | ||
180 | } | ||
181 | |||
182 | console.log("this.editForm", editForm); | ||
183 | app | ||
184 | .post({ url: app.api.setArticle, data: editForm }) | ||
185 | .then(res => { | ||
186 | this.loading = false; | ||
187 | this.$notify({ | ||
188 | title: "成功", | ||
189 | message: "操作成功", | ||
190 | type: "success" | ||
191 | }); | ||
192 | this.$router.go(-1); | ||
193 | }) | ||
194 | .catch(e => { | ||
195 | this.loading = false; | ||
196 | }); | ||
197 | } | ||
198 | }); | ||
199 | }, | ||
200 | componentClose() { | ||
201 | this.$router.go(-1); | ||
202 | }, | ||
203 | |||
204 | successFile(res, file) { | ||
205 | if (res.code == 200) { | ||
206 | this.editForm.attachments.push({ | ||
207 | name: file.name, | ||
208 | path: res.content | ||
209 | }); | ||
210 | } else { | ||
211 | this.$notify.error({ | ||
212 | title: "错误", | ||
213 | message: res.errMsg | ||
214 | }); | ||
215 | } | ||
216 | }, | ||
217 | |||
218 | removeFile(file, fileList) { | ||
219 | this.editForm.attachments.forEach((item, index) => { | ||
220 | if (item.name == file.name) { | ||
221 | this.attachments.attachments.splice(index, 1); | ||
222 | } | ||
223 | }); | ||
224 | } | ||
225 | } | ||
226 | }; | ||
227 | </script> | ||
228 | <style lang="scss" scoped> | ||
229 | .tablePage { | ||
230 | margin: 0 auto; | ||
231 | } | ||
232 | |||
233 | .el-upload__tip { | ||
234 | color: rgb(190, 190, 190); | ||
235 | } | ||
236 | </style> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
src/views/Q&A/article/list.vue
0 → 100644
1 | <template> | ||
2 | <div class="tablePage"> | ||
3 | <!-- 筛选参数 --> | ||
4 | <el-header> | ||
5 | <el-form :inline="true" style="display:flex"> | ||
6 | <el-form-item style="flex-grow: 1"> | ||
7 | <el-input @change="getList" v-model="queryForm.query" placeholder="请输入标题名称"></el-input> | ||
8 | </el-form-item> | ||
9 | <el-form-item> | ||
10 | <el-button @click="handleShowEdit(null)" type="primary" icon="el-icon-plus">新建</el-button> | ||
11 | </el-form-item> | ||
12 | </el-form> | ||
13 | </el-header> | ||
14 | <!-- 表格 --> | ||
15 | <el-container> | ||
16 | <el-table :data="list" :loading="loading"> | ||
17 | <el-table-column type="index" min-width="50"></el-table-column> | ||
18 | <el-table-column | ||
19 | :show-overflow-tooltip="true" | ||
20 | label="标题" | ||
21 | prop="articleTitle" | ||
22 | min-width="200" | ||
23 | ></el-table-column> | ||
24 | <el-table-column label="排序值" prop="orderId" min-width="100"></el-table-column> | ||
25 | <el-table-column :show-overflow-tooltip="false" label="浏览次数" prop="viewNumber" width="130"></el-table-column> | ||
26 | <el-table-column label="状态"> | ||
27 | <template slot-scope="scope"> | ||
28 | <el-tag | ||
29 | v-if="scope.row.onlineStatus==1" | ||
30 | type="success" | ||
31 | class="pointer" | ||
32 | :class="{'not-allowed' : scope.row.sysList}" | ||
33 | @click="scope.row.sysList ? '' : handleChangeStatue(scope.row, 0)" | ||
34 | >在线</el-tag> | ||
35 | <el-tag | ||
36 | v-else | ||
37 | type="info" | ||
38 | class="pointer" | ||
39 | :class="{'not-allowed' : scope.row.sysList}" | ||
40 | @click="scope.row.sysList ? '' : handleChangeStatue(scope.row, 1)" | ||
41 | >下线</el-tag> | ||
42 | </template> | ||
43 | </el-table-column> | ||
44 | <el-table-column label="是否置顶" min-width="100"> | ||
45 | <template slot-scope="scope"> | ||
46 | <el-switch | ||
47 | @change="setList(scope.row)" | ||
48 | v-model="scope.row.inTop" | ||
49 | active-color="rgb(102,177,255)" | ||
50 | inactive-color="rgb(234,236,240)" | ||
51 | ></el-switch> | ||
52 | </template> | ||
53 | </el-table-column> | ||
54 | <el-table-column label="操作" min-width="100"> | ||
55 | <template slot-scope="scope"> | ||
56 | <el-button type="text" @click="handleShowEdit(scope.row.articleCode)">编辑</el-button> | ||
57 | <el-button type="text" @click="handleDelete(scope.row.articleCode)">删除</el-button> | ||
58 | </template> | ||
59 | </el-table-column> | ||
60 | </el-table> | ||
61 | </el-container> | ||
62 | <!-- 分页 --> | ||
63 | <el-footer class="fixed-bottom"> | ||
64 | <el-pagination | ||
65 | background | ||
66 | layout="total, sizes, prev, pager, next, jumper" | ||
67 | :current-page="queryForm.page" | ||
68 | @size-change="handleSizeChange" | ||
69 | @current-change="handleCurrentChange" | ||
70 | :page-sizes="[10,20,30,50]" | ||
71 | :page-size="queryForm.size" | ||
72 | :total="total" | ||
73 | ></el-pagination> | ||
74 | </el-footer> | ||
75 | </div> | ||
76 | </template> | ||
77 | |||
78 | <script> | ||
79 | import { timestampFormat } from "@/utils/utils"; | ||
80 | |||
81 | const getListApi = app.api.getArticleList; | ||
82 | const setListApi = app.api.setArticleList; | ||
83 | |||
84 | export default { | ||
85 | props: [], | ||
86 | components: {}, | ||
87 | data() { | ||
88 | return { | ||
89 | queryForm: { | ||
90 | page: 1, | ||
91 | size: 10, | ||
92 | query: "", | ||
93 | onlineStatus: null, | ||
94 | messageType: null, | ||
95 | vipMark: null | ||
96 | }, //列表默认传参 | ||
97 | list: [], //列表数据 | ||
98 | total: 0, //列表总数 | ||
99 | loading: true, //表格加载状态 | ||
100 | keyword: "accountCode", | ||
101 | |||
102 | pojo: null, | ||
103 | showEdit: false, | ||
104 | showChangePwd: false | ||
105 | }; | ||
106 | }, | ||
107 | created() { | ||
108 | this.initData(); | ||
109 | }, | ||
110 | methods: { | ||
111 | timestampFormat, | ||
112 | // 初始化数据 | ||
113 | async initData() { | ||
114 | this.getList(); | ||
115 | }, | ||
116 | // 获取列表 | ||
117 | getList(resize) { | ||
118 | if (resize && resize != undefined) { | ||
119 | this.queryForm.page = 1; | ||
120 | } | ||
121 | this.loading = true; | ||
122 | app | ||
123 | .get({ | ||
124 | url: getListApi, | ||
125 | data: this.queryForm | ||
126 | }) | ||
127 | .then(res => { | ||
128 | this.loading = false; | ||
129 | |||
130 | res.list.forEach(item => { | ||
131 | item.onlineStatus = item.onlineStatus == 1 ? true : false; | ||
132 | item.inTop = item.inTop == 1 ? true : false; | ||
133 | }); | ||
134 | |||
135 | this.list = res.list; | ||
136 | this.total = res.total; | ||
137 | }) | ||
138 | .catch(err => { | ||
139 | this.loading = false; | ||
140 | }); | ||
141 | }, | ||
142 | |||
143 | // 更新内容 | ||
144 | setList(item) { | ||
145 | let editForm = JSON.parse(JSON.stringify(item)); | ||
146 | editForm.inTop = item.inTop ? 1 : 0; | ||
147 | editForm.onlineStatus = item.onlineStatus ? 1 : 0; | ||
148 | |||
149 | app | ||
150 | .post({ | ||
151 | url: setListApi, | ||
152 | data: editForm | ||
153 | }) | ||
154 | .then(res => { | ||
155 | this.$message({ | ||
156 | message: "更新成功", | ||
157 | type: "success" | ||
158 | }); | ||
159 | // this.getList(); | ||
160 | }) | ||
161 | .catch(err => {}); | ||
162 | }, | ||
163 | |||
164 | setOrderType(val) { | ||
165 | if (!val.order) { | ||
166 | this.queryForm.orderType = ""; | ||
167 | this.getList(true); | ||
168 | return; | ||
169 | } | ||
170 | switch (val.prop) { | ||
171 | case "createAt": | ||
172 | if (val.order == "descending") { | ||
173 | this.queryForm.orderType = "id:desc"; | ||
174 | } else { | ||
175 | this.queryForm.orderType = "id:asc"; | ||
176 | } | ||
177 | this.getList(true); | ||
178 | break; | ||
179 | case "viewNumber": | ||
180 | if (val.order == "descending") { | ||
181 | this.queryForm.orderType = "viewNumber:desc"; | ||
182 | } else { | ||
183 | this.queryForm.orderType = "viewNumber:asc"; | ||
184 | } | ||
185 | this.getList(true); | ||
186 | break; | ||
187 | |||
188 | default: | ||
189 | break; | ||
190 | } | ||
191 | }, | ||
192 | |||
193 | // 上下架 | ||
194 | setOnlineStatus(item) { | ||
195 | item.onlineStatus = item.onlineStatus == 0 ? 1 : 0; | ||
196 | this.setList(item); | ||
197 | }, | ||
198 | |||
199 | // 置顶 | ||
200 | setOrderId(item) { | ||
201 | item.inTop = item.inTop == 1 ? 0 : 1; | ||
202 | this.setList(item); | ||
203 | }, | ||
204 | |||
205 | // 切换页码大小 | ||
206 | handleSizeChange(val) { | ||
207 | this.queryForm.size = val; | ||
208 | this.queryForm.page = 1; | ||
209 | this.initData(); | ||
210 | }, | ||
211 | |||
212 | // 切换页码 | ||
213 | handleCurrentChange(val) { | ||
214 | this.queryForm.page = val; | ||
215 | this.initData(); | ||
216 | }, | ||
217 | handleShowEdit(articleCode) { | ||
218 | this.$router.push({ | ||
219 | name: "articleDetail", | ||
220 | query: { | ||
221 | articleCode: articleCode | ||
222 | } | ||
223 | }); | ||
224 | }, | ||
225 | handleChangePwd(pojo) { | ||
226 | this.pojo = pojo; | ||
227 | this.showChangePwd = true; | ||
228 | }, | ||
229 | handleDelete(articleCode) { | ||
230 | this.$confirm("删除后,不可恢复 是否继续?", "提示", { | ||
231 | confirmButtonText: "确定", | ||
232 | cancelButtonText: "取消", | ||
233 | type: "warning" | ||
234 | }) | ||
235 | .then(() => { | ||
236 | this.loading = true; | ||
237 | app | ||
238 | .delete({ | ||
239 | url: setListApi, | ||
240 | data: { articleCode } | ||
241 | }) | ||
242 | .then(res => { | ||
243 | this.$message({ | ||
244 | message: "更新成功", | ||
245 | type: "success" | ||
246 | }); | ||
247 | this.getList(); | ||
248 | }) | ||
249 | .catch(err => {}); | ||
250 | }) | ||
251 | .catch(() => { | ||
252 | this.loading = true; | ||
253 | }); | ||
254 | }, | ||
255 | handleChangeStatue(row, status) { | ||
256 | let msg = status == 1 ? "是否上线当前文章?" : "是否下线当前文章?"; | ||
257 | let data = JSON.parse(JSON.stringify(row)); | ||
258 | data.onlineStatus = status; | ||
259 | data.inTop = data.inTop ? 1 : 0; | ||
260 | this.$confirm(msg, "提示", { | ||
261 | confirmButtonText: "确定", | ||
262 | cancelButtonText: "取消", | ||
263 | type: "warning" | ||
264 | }) | ||
265 | .then(() => { | ||
266 | this.loading = true; | ||
267 | app.post({ url: setListApi, data }).then(res => { | ||
268 | this.getList(); | ||
269 | this.$notify({ | ||
270 | title: "成功", | ||
271 | message: "操作成功", | ||
272 | type: "success" | ||
273 | }); | ||
274 | }); | ||
275 | }) | ||
276 | .catch(() => { | ||
277 | this.loading = true; | ||
278 | }); | ||
279 | } | ||
280 | } | ||
281 | }; | ||
282 | </script> | ||
283 | |||
284 | <style lang="scss" scoped> | ||
285 | /deep/ .el-dialog__wrapper { | ||
286 | overflow: hidden; | ||
287 | } | ||
288 | </style> |
src/views/Q&A/classify/detail.vue
0 → 100644
1 | <template> | ||
2 | <div class="editPage"> | ||
3 | <el-form | ||
4 | :model="editForm" | ||
5 | :loading="loading" | ||
6 | ref="editForm" | ||
7 | label-position="right" | ||
8 | label-width="auto" | ||
9 | style="padding-right:50px;" | ||
10 | v-loading="loading" | ||
11 | element-loading-text="操作中" | ||
12 | element-loading-spinner="el-icon-loading" | ||
13 | element-loading-background="rgba(255, 255, 255, 0.9)" | ||
14 | > | ||
15 | <el-form-item | ||
16 | label="名称" | ||
17 | prop="classifyName" | ||
18 | :rules="{ required: true, message: '名称不能为空', trigger: 'blur' }" | ||
19 | > | ||
20 | <el-input v-model="editForm.classifyName" placeholder="请输入名称"></el-input> | ||
21 | </el-form-item> | ||
22 | |||
23 | <el-form-item label="排序值"> | ||
24 | <el-input-number v-model="editForm.orderId" :min="0"></el-input-number> | ||
25 | </el-form-item> | ||
26 | |||
27 | <el-form-item | ||
28 | label="是否在线" | ||
29 | prop="onlineStatus" | ||
30 | :rules="{ required: true, message: '请选择状态', trigger: 'blur' }" | ||
31 | > | ||
32 | <el-switch | ||
33 | v-model="editForm.onlineStatus" | ||
34 | inactive-color="rgb(234,236,240)" | ||
35 | ></el-switch> | ||
36 | </el-form-item> | ||
37 | </el-form> | ||
38 | <div slot="footer" class="dialog-footer" style="padding-right:30px"> | ||
39 | <el-button @click="componentClose">取 消</el-button> | ||
40 | <el-button type="primary" @click="componentSubmit" :disabled="loading" :loading="loading">确定</el-button> | ||
41 | </div> | ||
42 | </div> | ||
43 | </template> | ||
44 | |||
45 | |||
46 | <script> | ||
47 | import UploadImg from "@/components/UploadImg/index.vue"; | ||
48 | |||
49 | export default { | ||
50 | props: [], | ||
51 | components: { UploadImg }, | ||
52 | data() { | ||
53 | return { | ||
54 | isLinkDialog: false, | ||
55 | searchLoading: false, | ||
56 | title: "轮播图", | ||
57 | submitUrl: "", | ||
58 | loading: false, | ||
59 | dialogVisiable: false, | ||
60 | editForm: { | ||
61 | classifyCode: "", | ||
62 | classifyIcon: "", | ||
63 | classifyHomePic: "", | ||
64 | classifyName: "", | ||
65 | onlineStatus: true, | ||
66 | onShow: false, | ||
67 | orderId: 0 | ||
68 | }, | ||
69 | // 连接值的候选项 | ||
70 | valueCandidates: [], | ||
71 | getForm: { | ||
72 | query: null, | ||
73 | page: 0, | ||
74 | size: 10 | ||
75 | }, | ||
76 | candidatesEnd: false, | ||
77 | fetchUrl: "", | ||
78 | labelKey: "", | ||
79 | valueKey: "" | ||
80 | }; | ||
81 | }, | ||
82 | mounted() { | ||
83 | this.initData(); | ||
84 | }, | ||
85 | methods: { | ||
86 | async initData() { | ||
87 | this.submitUrl = app.api.setArticleClassify; | ||
88 | if (this.$route.query.pojo != "null") { | ||
89 | this.editForm = JSON.parse(this.$route.query.pojo); | ||
90 | this.editForm.onlineStatus = this.editForm.onlineStatus ? true : false; | ||
91 | this.editForm.onShow = this.editForm.onShow ? true : false; | ||
92 | } | ||
93 | this.dialogVisiable = true; | ||
94 | }, | ||
95 | componentClose() { | ||
96 | this.$router.go(-1); | ||
97 | }, | ||
98 | componentClosed() { | ||
99 | this.$emit("closed"); | ||
100 | }, | ||
101 | componentSubmit() { | ||
102 | this.$refs["editForm"].validate(valid => { | ||
103 | if (valid) { | ||
104 | if (this.loading) { | ||
105 | return; | ||
106 | } | ||
107 | this.loading = true; | ||
108 | |||
109 | let editForm = JSON.parse(JSON.stringify(this.editForm)); | ||
110 | editForm.onlineStatus = this.editForm.onlineStatus ? 1 : 0; | ||
111 | editForm.onShow = this.editForm.onShow ? 1 : 0; | ||
112 | |||
113 | app | ||
114 | .post({ | ||
115 | url: this.submitUrl, | ||
116 | data: editForm | ||
117 | }) | ||
118 | .then(res => { | ||
119 | this.loading = false; | ||
120 | this.$notify({ | ||
121 | title: "成功", | ||
122 | message: "操作成功", | ||
123 | type: "success" | ||
124 | }); | ||
125 | this.$router.go(-1); | ||
126 | }) | ||
127 | .catch(e => { | ||
128 | this.loading = false; | ||
129 | }); | ||
130 | } | ||
131 | }); | ||
132 | } | ||
133 | } | ||
134 | }; | ||
135 | </script> | ||
136 | |||
137 | <style lang="scss" scoped> | ||
138 | .commoditySelect { | ||
139 | width: 100%; | ||
140 | max-width: auto; | ||
141 | } | ||
142 | .tablePage { | ||
143 | margin: 0 auto; | ||
144 | } | ||
145 | </style> |
src/views/Q&A/classify/list.vue
0 → 100644
1 | <template> | ||
2 | <div class="tablePage"> | ||
3 | <!-- 筛选参数 --> | ||
4 | <el-header> | ||
5 | <el-form :inline="true" style="display:flex"> | ||
6 | <el-form-item style="flex-grow: 1"></el-form-item> | ||
7 | <el-form-item> | ||
8 | <el-button @click="handleShowEdit(null)" type="primary" icon="el-icon-plus">新建</el-button> | ||
9 | </el-form-item> | ||
10 | </el-form> | ||
11 | </el-header> | ||
12 | <!-- 表格 --> | ||
13 | |||
14 | <el-container> | ||
15 | <el-table :data="list" :loading="loading"> | ||
16 | <el-table-column label="名称" prop="classifyName"></el-table-column> | ||
17 | <!-- <el-table-column label="图标" min-width="100"> | ||
18 | <template slot-scope="scope"> | ||
19 | <el-image style="width: 50px; height: 50px" :src="scope.row.classifyIcon"></el-image> | ||
20 | </template> | ||
21 | </el-table-column> | ||
22 | <el-table-column label="主分类图标" min-width="100"> | ||
23 | <template slot-scope="scope"> | ||
24 | <el-image style="width: 50px; height: 50px" :src="scope.row.classifyHomePic"></el-image> | ||
25 | </template> | ||
26 | </el-table-column>--> | ||
27 | |||
28 | <el-table-column label="状态"> | ||
29 | <template slot-scope="scope"> | ||
30 | <el-tag | ||
31 | v-if="scope.row.onlineStatus==1" | ||
32 | type="success" | ||
33 | class="pointer" | ||
34 | :class="{'not-allowed' : scope.row.sysList}" | ||
35 | @click="scope.row.sysList ? '' : handleChangeStatue(scope.row, 0)" | ||
36 | >在线</el-tag> | ||
37 | <el-tag | ||
38 | v-else | ||
39 | type="info" | ||
40 | class="pointer" | ||
41 | :class="{'not-allowed' : scope.row.sysList}" | ||
42 | @click="scope.row.sysList ? '' : handleChangeStatue(scope.row, 1)" | ||
43 | >下线</el-tag> | ||
44 | </template> | ||
45 | </el-table-column> | ||
46 | <el-table-column label="排序" prop="orderId"></el-table-column> | ||
47 | <el-table-column label="操作"> | ||
48 | <template slot-scope="scope"> | ||
49 | <el-button type="text" @click="handleShowEdit(scope.row)">编辑</el-button> | ||
50 | <el-button | ||
51 | type="text" | ||
52 | @click="handleDelete(scope.row)" | ||
53 | :disabled="scope.row.sysList ? true : false" | ||
54 | >删除</el-button> | ||
55 | </template> | ||
56 | </el-table-column> | ||
57 | </el-table> | ||
58 | </el-container> | ||
59 | <!-- 分页 --> | ||
60 | <el-footer class="fixed-bottom"> | ||
61 | <el-pagination | ||
62 | background | ||
63 | layout="total, sizes, prev, pager, next, jumper" | ||
64 | :current-page="queryForm.page" | ||
65 | @size-change="handleSizeChange" | ||
66 | @current-change="handleCurrentChange" | ||
67 | :page-sizes="[10,20,30,50]" | ||
68 | :page-size="queryForm.size" | ||
69 | :total="total" | ||
70 | ></el-pagination> | ||
71 | </el-footer> | ||
72 | </div> | ||
73 | </template> | ||
74 | |||
75 | <script> | ||
76 | // 列表路径 | ||
77 | const listUrl = app.api.getArticleClassify; | ||
78 | // 提交路径 | ||
79 | const postUrl = app.api.setArticleClassify; | ||
80 | // 唯一标识 | ||
81 | const primaryCodeName = "classifyCode"; | ||
82 | |||
83 | export default { | ||
84 | components: {}, | ||
85 | data() { | ||
86 | return { | ||
87 | postUrl, | ||
88 | queryForm: { | ||
89 | page: 1, | ||
90 | size: 10 | ||
91 | }, //列表默认传参 | ||
92 | list: [], //列表数据 | ||
93 | total: 0, //列表总数 | ||
94 | loading: true, //表格加载状态 | ||
95 | |||
96 | classifyCode: "", | ||
97 | relationsArticleCodes: [], | ||
98 | |||
99 | isShowRelations: false, | ||
100 | articlesList: [], | ||
101 | |||
102 | transferProps: { | ||
103 | key: "memberCode", | ||
104 | label: "name" | ||
105 | } | ||
106 | }; | ||
107 | }, | ||
108 | created() { | ||
109 | this.initData(); | ||
110 | }, | ||
111 | methods: { | ||
112 | // 初始化数据 | ||
113 | initData(resize) { | ||
114 | if (resize && resize != undefined) { | ||
115 | this.queryForm.page = 1; | ||
116 | } | ||
117 | |||
118 | this.getList(); | ||
119 | }, | ||
120 | |||
121 | // 获取列表 | ||
122 | getList() { | ||
123 | this.loading = true; | ||
124 | app | ||
125 | .get({ | ||
126 | url: listUrl, | ||
127 | data: this.queryForm | ||
128 | }) | ||
129 | .then(res => { | ||
130 | this.loading = false; | ||
131 | this.list = res.list; | ||
132 | this.total = res.total; | ||
133 | }) | ||
134 | .catch(err => { | ||
135 | this.loading = false; | ||
136 | }); | ||
137 | }, | ||
138 | |||
139 | // 切换页码大小 | ||
140 | handleSizeChange(val) { | ||
141 | this.queryForm.size = val; | ||
142 | this.queryForm.page = 1; | ||
143 | this.initData(); | ||
144 | }, | ||
145 | |||
146 | // 切换页码 | ||
147 | handleCurrentChange(val) { | ||
148 | this.queryForm.page = val; | ||
149 | this.initData(); | ||
150 | }, | ||
151 | |||
152 | handleShowEdit(pojo) { | ||
153 | this.$router.push({ | ||
154 | name: "articeClassifyDetail", | ||
155 | query: { | ||
156 | pojo: JSON.stringify(pojo) | ||
157 | } | ||
158 | }); | ||
159 | }, | ||
160 | |||
161 | handleShowRelation(classifyCode) { | ||
162 | this.relationsArticleCodes = []; | ||
163 | this.classifyCode = classifyCode; | ||
164 | this.getArticleRelativeArticles(classifyCode); | ||
165 | }, | ||
166 | |||
167 | handleDelete(pojo) { | ||
168 | this.$confirm("删除后,不可恢复 是否继续?", "提示", { | ||
169 | confirmButtonText: "确定", | ||
170 | cancelButtonText: "取消", | ||
171 | type: "warning" | ||
172 | }) | ||
173 | .then(() => { | ||
174 | let data = {}; | ||
175 | data[primaryCodeName] = pojo[primaryCodeName]; | ||
176 | this.loading = true; | ||
177 | app | ||
178 | .delete({ | ||
179 | url: postUrl, | ||
180 | data | ||
181 | }) | ||
182 | .then(res => { | ||
183 | this.getList(); | ||
184 | this.$notify({ | ||
185 | title: "成功", | ||
186 | message: "删除成功", | ||
187 | type: "success" | ||
188 | }); | ||
189 | }); | ||
190 | }) | ||
191 | .catch(() => { | ||
192 | this.loading = true; | ||
193 | }); | ||
194 | }, | ||
195 | handleChangeStatue(row, status) { | ||
196 | let msg = status == 1 ? "是否上线当前分类?" : "是否下线当前分类?"; | ||
197 | let data = JSON.parse(JSON.stringify(row)); | ||
198 | data.onlineStatus = status; | ||
199 | this.$confirm(msg, "提示", { | ||
200 | confirmButtonText: "确定", | ||
201 | cancelButtonText: "取消", | ||
202 | type: "warning" | ||
203 | }) | ||
204 | .then(() => { | ||
205 | this.loading = true; | ||
206 | app.post({ url: postUrl, data }).then(res => { | ||
207 | this.getList(); | ||
208 | this.$notify({ | ||
209 | title: "成功", | ||
210 | message: "操作成功", | ||
211 | type: "success" | ||
212 | }); | ||
213 | }); | ||
214 | }) | ||
215 | .catch(() => { | ||
216 | this.loading = true; | ||
217 | }); | ||
218 | }, | ||
219 | handleChangeShow(row, status) { | ||
220 | let msg = status == 1 ? "是否显示当前分类?" : "是否隐藏当前分类?"; | ||
221 | let data = JSON.parse(JSON.stringify(row)); | ||
222 | data.onShow = status; | ||
223 | this.$confirm(msg, "提示", { | ||
224 | confirmButtonText: "确定", | ||
225 | cancelButtonText: "取消", | ||
226 | type: "warning" | ||
227 | }) | ||
228 | .then(() => { | ||
229 | this.loading = true; | ||
230 | app.post({ url: postUrl, data }).then(res => { | ||
231 | this.getList(); | ||
232 | this.$notify({ | ||
233 | title: "成功", | ||
234 | message: "操作成功", | ||
235 | type: "success" | ||
236 | }); | ||
237 | }); | ||
238 | }) | ||
239 | .catch(() => { | ||
240 | this.loading = true; | ||
241 | }); | ||
242 | } | ||
243 | } | ||
244 | }; | ||
245 | </script> | ||
246 | |||
247 | <style scoped> | ||
248 | .transfer { | ||
249 | margin: 0 auto; | ||
250 | } | ||
251 | .not-allowed { | ||
252 | cursor: not-allowed; | ||
253 | } | ||
254 | </style> |
src/views/Q&A/keyword/detail.vue
0 → 100644
1 | <template> | ||
2 | <div class="editPage"> | ||
3 | <el-form | ||
4 | :model="editForm" | ||
5 | :loading="loading" | ||
6 | ref="editForm" | ||
7 | label-position="right" | ||
8 | label-width="auto" | ||
9 | style="padding-right:50px;" | ||
10 | v-loading="loading" | ||
11 | element-loading-text="操作中" | ||
12 | element-loading-spinner="el-icon-loading" | ||
13 | element-loading-background="rgba(255, 255, 255, 0.9)" | ||
14 | > | ||
15 | <el-form-item | ||
16 | label="关键词" | ||
17 | prop="keyword" | ||
18 | :rules="{ required: true, message: '关键词不能为空', trigger: 'blur' }" | ||
19 | > | ||
20 | <el-input v-model="editForm.keyword" placeholder="请输入关键词"></el-input> | ||
21 | </el-form-item> | ||
22 | |||
23 | <el-form-item label="排序值"> | ||
24 | <el-input-number v-model="editForm.orderId" :min="0"></el-input-number> | ||
25 | </el-form-item> | ||
26 | |||
27 | <el-form-item | ||
28 | label="是否在线" | ||
29 | prop="onlineStatus" | ||
30 | :rules="{ required: true, message: '请选择状态', trigger: 'blur' }" | ||
31 | > | ||
32 | <el-switch | ||
33 | v-model="editForm.onlineStatus" | ||
34 | inactive-color="rgb(234,236,240)" | ||
35 | ></el-switch> | ||
36 | </el-form-item> | ||
37 | </el-form> | ||
38 | <div slot="footer" class="dialog-footer" style="padding-right:30px"> | ||
39 | <el-button @click="componentClose">取 消</el-button> | ||
40 | <el-button type="primary" @click="componentSubmit" :disabled="loading" :loading="loading">确定</el-button> | ||
41 | </div> | ||
42 | </div> | ||
43 | </template> | ||
44 | |||
45 | |||
46 | <script> | ||
47 | import UploadImg from "@/components/UploadImg/index.vue"; | ||
48 | |||
49 | export default { | ||
50 | props: [], | ||
51 | components: { UploadImg }, | ||
52 | data() { | ||
53 | return { | ||
54 | isLinkDialog: false, | ||
55 | searchLoading: false, | ||
56 | title: "轮播图", | ||
57 | submitUrl: "", | ||
58 | loading: false, | ||
59 | dialogVisiable: false, | ||
60 | editForm: { | ||
61 | primaryCode: "", | ||
62 | keyword: "", | ||
63 | onlineStatus: true, | ||
64 | orderId: 0 | ||
65 | }, | ||
66 | // 连接值的候选项 | ||
67 | valueCandidates: [], | ||
68 | getForm: { | ||
69 | query: null, | ||
70 | page: 0, | ||
71 | size: 10 | ||
72 | }, | ||
73 | candidatesEnd: false, | ||
74 | fetchUrl: "", | ||
75 | labelKey: "", | ||
76 | valueKey: "" | ||
77 | }; | ||
78 | }, | ||
79 | mounted() { | ||
80 | this.initData(); | ||
81 | }, | ||
82 | methods: { | ||
83 | async initData() { | ||
84 | this.submitUrl = app.api.setArticleKeywordList; | ||
85 | if (this.$route.query.pojo != "null") { | ||
86 | this.editForm = JSON.parse(this.$route.query.pojo); | ||
87 | this.editForm.onlineStatus = this.editForm.onlineStatus ? true : false; | ||
88 | this.editForm.onShow = this.editForm.onShow ? true : false; | ||
89 | } | ||
90 | this.dialogVisiable = true; | ||
91 | }, | ||
92 | componentClose() { | ||
93 | this.$router.go(-1); | ||
94 | }, | ||
95 | componentClosed() { | ||
96 | this.$emit("closed"); | ||
97 | }, | ||
98 | componentSubmit() { | ||
99 | this.$refs["editForm"].validate(valid => { | ||
100 | if (valid) { | ||
101 | if (this.loading) { | ||
102 | return; | ||
103 | } | ||
104 | this.loading = true; | ||
105 | |||
106 | let editForm = JSON.parse(JSON.stringify(this.editForm)); | ||
107 | editForm.onlineStatus = this.editForm.onlineStatus ? 1 : 0; | ||
108 | editForm.onShow = this.editForm.onShow ? 1 : 0; | ||
109 | |||
110 | app | ||
111 | .post({ | ||
112 | url: this.submitUrl, | ||
113 | data: editForm | ||
114 | }) | ||
115 | .then(res => { | ||
116 | this.loading = false; | ||
117 | this.$notify({ | ||
118 | title: "成功", | ||
119 | message: "操作成功", | ||
120 | type: "success" | ||
121 | }); | ||
122 | this.$router.go(-1); | ||
123 | }) | ||
124 | .catch(e => { | ||
125 | this.loading = false; | ||
126 | }); | ||
127 | } | ||
128 | }); | ||
129 | } | ||
130 | } | ||
131 | }; | ||
132 | </script> | ||
133 | |||
134 | <style lang="scss" scoped> | ||
135 | .commoditySelect { | ||
136 | width: 100%; | ||
137 | max-width: auto; | ||
138 | } | ||
139 | .tablePage { | ||
140 | margin: 0 auto; | ||
141 | } | ||
142 | </style> |
src/views/Q&A/keyword/list.vue
0 → 100644
1 | <template> | ||
2 | <div class="tablePage"> | ||
3 | <!-- 筛选参数 --> | ||
4 | <el-header> | ||
5 | <el-form :inline="true" style="display:flex"> | ||
6 | <el-form-item style="flex-grow: 1"></el-form-item> | ||
7 | <el-form-item> | ||
8 | <el-button @click="handleShowEdit(null)" type="primary" icon="el-icon-plus">新建</el-button> | ||
9 | </el-form-item> | ||
10 | </el-form> | ||
11 | </el-header> | ||
12 | <!-- 表格 --> | ||
13 | |||
14 | <el-container> | ||
15 | <el-table :data="list" :loading="loading"> | ||
16 | <el-table-column label="关键词" prop="keyword"></el-table-column> | ||
17 | |||
18 | <el-table-column label="状态"> | ||
19 | <template slot-scope="scope"> | ||
20 | <el-tag | ||
21 | v-if="scope.row.onlineStatus==1" | ||
22 | type="success" | ||
23 | class="pointer" | ||
24 | :class="{'not-allowed' : scope.row.sysList}" | ||
25 | @click="scope.row.sysList ? '' : handleChangeStatue(scope.row, 0)" | ||
26 | >在线</el-tag> | ||
27 | <el-tag | ||
28 | v-else | ||
29 | type="info" | ||
30 | class="pointer" | ||
31 | :class="{'not-allowed' : scope.row.sysList}" | ||
32 | @click="scope.row.sysList ? '' : handleChangeStatue(scope.row, 1)" | ||
33 | >下线</el-tag> | ||
34 | </template> | ||
35 | </el-table-column> | ||
36 | <el-table-column label="排序" prop="orderId"></el-table-column> | ||
37 | <el-table-column label="操作"> | ||
38 | <template slot-scope="scope"> | ||
39 | <el-button type="text" @click="handleShowEdit(scope.row)">编辑</el-button> | ||
40 | <el-button | ||
41 | type="text" | ||
42 | @click="handleDelete(scope.row)" | ||
43 | :disabled="scope.row.sysList ? true : false" | ||
44 | >删除</el-button> | ||
45 | </template> | ||
46 | </el-table-column> | ||
47 | </el-table> | ||
48 | </el-container> | ||
49 | <!-- 分页 --> | ||
50 | <el-footer class="fixed-bottom"> | ||
51 | <el-pagination | ||
52 | background | ||
53 | layout="total, sizes, prev, pager, next, jumper" | ||
54 | :current-page="queryForm.page" | ||
55 | @size-change="handleSizeChange" | ||
56 | @current-change="handleCurrentChange" | ||
57 | :page-sizes="[10,20,30,50]" | ||
58 | :page-size="queryForm.size" | ||
59 | :total="total" | ||
60 | ></el-pagination> | ||
61 | </el-footer> | ||
62 | </div> | ||
63 | </template> | ||
64 | |||
65 | <script> | ||
66 | // 列表路径 | ||
67 | const listUrl = app.api.getArticleKeywordList; | ||
68 | // 提交路径 | ||
69 | const postUrl = app.api.setArticleKeywordList; | ||
70 | // 唯一标识 | ||
71 | const primaryCodeName = "primaryCode"; | ||
72 | |||
73 | export default { | ||
74 | components: {}, | ||
75 | data() { | ||
76 | return { | ||
77 | postUrl, | ||
78 | queryForm: { | ||
79 | page: 1, | ||
80 | size: 10 | ||
81 | }, //列表默认传参 | ||
82 | list: [], //列表数据 | ||
83 | total: 0, //列表总数 | ||
84 | loading: true, //表格加载状态 | ||
85 | |||
86 | classifyCode: "", | ||
87 | relationsArticleCodes: [], | ||
88 | |||
89 | isShowRelations: false, | ||
90 | articlesList: [], | ||
91 | |||
92 | transferProps: { | ||
93 | key: "memberCode", | ||
94 | label: "name" | ||
95 | } | ||
96 | }; | ||
97 | }, | ||
98 | created() { | ||
99 | this.initData(); | ||
100 | }, | ||
101 | methods: { | ||
102 | // 初始化数据 | ||
103 | initData(resize) { | ||
104 | if (resize && resize != undefined) { | ||
105 | this.queryForm.page = 1; | ||
106 | } | ||
107 | |||
108 | this.getList(); | ||
109 | }, | ||
110 | |||
111 | // 获取列表 | ||
112 | getList() { | ||
113 | this.loading = true; | ||
114 | app | ||
115 | .get({ | ||
116 | url: listUrl, | ||
117 | data: this.queryForm | ||
118 | }) | ||
119 | .then(res => { | ||
120 | this.loading = false; | ||
121 | this.list = res.list; | ||
122 | this.total = res.total; | ||
123 | }) | ||
124 | .catch(err => { | ||
125 | this.loading = false; | ||
126 | }); | ||
127 | }, | ||
128 | |||
129 | // 切换页码大小 | ||
130 | handleSizeChange(val) { | ||
131 | this.queryForm.size = val; | ||
132 | this.queryForm.page = 1; | ||
133 | this.initData(); | ||
134 | }, | ||
135 | |||
136 | // 切换页码 | ||
137 | handleCurrentChange(val) { | ||
138 | this.queryForm.page = val; | ||
139 | this.initData(); | ||
140 | }, | ||
141 | |||
142 | handleShowEdit(pojo) { | ||
143 | this.$router.push({ | ||
144 | name: "keywordDetail", | ||
145 | query: { | ||
146 | pojo: JSON.stringify(pojo) | ||
147 | } | ||
148 | }); | ||
149 | }, | ||
150 | |||
151 | handleShowRelation(classifyCode) { | ||
152 | this.relationsArticleCodes = []; | ||
153 | this.classifyCode = classifyCode; | ||
154 | this.getArticleRelativeArticles(classifyCode); | ||
155 | }, | ||
156 | |||
157 | handleDelete(pojo) { | ||
158 | this.$confirm("删除后,不可恢复 是否继续?", "提示", { | ||
159 | confirmButtonText: "确定", | ||
160 | cancelButtonText: "取消", | ||
161 | type: "warning" | ||
162 | }) | ||
163 | .then(() => { | ||
164 | let data = {}; | ||
165 | data[primaryCodeName] = pojo[primaryCodeName]; | ||
166 | this.loading = true; | ||
167 | app | ||
168 | .delete({ | ||
169 | url: postUrl, | ||
170 | data | ||
171 | }) | ||
172 | .then(res => { | ||
173 | this.getList(); | ||
174 | this.$notify({ | ||
175 | title: "成功", | ||
176 | message: "删除成功", | ||
177 | type: "success" | ||
178 | }); | ||
179 | }); | ||
180 | }) | ||
181 | .catch(() => { | ||
182 | this.loading = true; | ||
183 | }); | ||
184 | }, | ||
185 | handleChangeStatue(row, status) { | ||
186 | let msg = status == 1 ? "是否上线当前分类?" : "是否下线当前分类?"; | ||
187 | let data = JSON.parse(JSON.stringify(row)); | ||
188 | data.onlineStatus = status; | ||
189 | this.$confirm(msg, "提示", { | ||
190 | confirmButtonText: "确定", | ||
191 | cancelButtonText: "取消", | ||
192 | type: "warning" | ||
193 | }) | ||
194 | .then(() => { | ||
195 | this.loading = true; | ||
196 | app.post({ url: postUrl, data }).then(res => { | ||
197 | this.getList(); | ||
198 | this.$notify({ | ||
199 | title: "成功", | ||
200 | message: "操作成功", | ||
201 | type: "success" | ||
202 | }); | ||
203 | }); | ||
204 | }) | ||
205 | .catch(() => { | ||
206 | this.loading = true; | ||
207 | }); | ||
208 | }, | ||
209 | handleChangeShow(row, status) { | ||
210 | let msg = status == 1 ? "是否显示当前分类?" : "是否隐藏当前分类?"; | ||
211 | let data = JSON.parse(JSON.stringify(row)); | ||
212 | data.onShow = status; | ||
213 | this.$confirm(msg, "提示", { | ||
214 | confirmButtonText: "确定", | ||
215 | cancelButtonText: "取消", | ||
216 | type: "warning" | ||
217 | }) | ||
218 | .then(() => { | ||
219 | this.loading = true; | ||
220 | app.post({ url: postUrl, data }).then(res => { | ||
221 | this.getList(); | ||
222 | this.$notify({ | ||
223 | title: "成功", | ||
224 | message: "操作成功", | ||
225 | type: "success" | ||
226 | }); | ||
227 | }); | ||
228 | }) | ||
229 | .catch(() => { | ||
230 | this.loading = true; | ||
231 | }); | ||
232 | } | ||
233 | } | ||
234 | }; | ||
235 | </script> | ||
236 | |||
237 | <style scoped> | ||
238 | .transfer { | ||
239 | margin: 0 auto; | ||
240 | } | ||
241 | .not-allowed { | ||
242 | cursor: not-allowed; | ||
243 | } | ||
244 | </style> |
src/views/Q&A/report/article.vue
0 → 100644
1 | <template> | ||
2 | <div class="tablePage"> | ||
3 | <!-- 筛选参数 --> | ||
4 | <el-header> | ||
5 | <el-form :inline="true" style="display:flex"> | ||
6 | <el-form-item style="flex-grow: 1"> | ||
7 | <el-date-picker | ||
8 | v-model="date" | ||
9 | @change="setData" | ||
10 | type="daterange" | ||
11 | align="right" | ||
12 | unlink-panels | ||
13 | range-separator="至" | ||
14 | start-placeholder="开始日期" | ||
15 | end-placeholder="结束日期" | ||
16 | :picker-options="pickerOptions" | ||
17 | ></el-date-picker> | ||
18 | </el-form-item> | ||
19 | |||
20 | <el-form-item> | ||
21 | <el-button @click="exportList()" type="primary"> | ||
22 | <i class="el-icon-download"></i>导出明细 | ||
23 | </el-button> | ||
24 | </el-form-item> | ||
25 | </el-form> | ||
26 | </el-header> | ||
27 | |||
28 | <div class="dataBoxList"> | ||
29 | <div class="dataBox"> | ||
30 | <h5 class="tit">整体报告</h5> | ||
31 | <div class="dataList"> | ||
32 | <div class="item"> | ||
33 | <label>浏览次数</label> | ||
34 | <h5>{{dashboardInfo.viewNumber}}</h5> | ||
35 | </div> | ||
36 | <div class="item"> | ||
37 | <label>浏览人数</label> | ||
38 | <h5>{{dashboardInfo.viewPerson}}</h5> | ||
39 | </div> | ||
40 | <div class="item"> | ||
41 | <label>分享次数</label> | ||
42 | <h5>{{dashboardInfo.shareNumber}}</h5> | ||
43 | </div> | ||
44 | </div> | ||
45 | </div> | ||
46 | |||
47 | <!-- 表格 --> | ||
48 | <el-container> | ||
49 | <el-table :data="list" :loading="loading"> | ||
50 | <el-table-column | ||
51 | label="标题" | ||
52 | prop="articleTitle" | ||
53 | min-width="300" | ||
54 | :show-overflow-tooltip="true" | ||
55 | ></el-table-column> | ||
56 | <el-table-column label="分类" prop="classifyName"></el-table-column> | ||
57 | <el-table-column label="标签" prop="tagName"></el-table-column> | ||
58 | <el-table-column label="浏览次数" prop="viewNumber"></el-table-column> | ||
59 | <el-table-column label="浏览人数" prop="viewPerson"></el-table-column> | ||
60 | <el-table-column label="分享次数" prop="shareNumber"></el-table-column> | ||
61 | </el-table> | ||
62 | </el-container> | ||
63 | <!-- 分页 --> | ||
64 | <!-- <el-footer class="fixed-bottom"> | ||
65 | <el-pagination | ||
66 | background | ||
67 | layout="total, sizes, prev, pager, next, jumper" | ||
68 | :current-page="dashboardForm.page" | ||
69 | @size-change="handleSizeChange" | ||
70 | @current-change="handleCurrentChange" | ||
71 | :page-sizes="[10,20,30,50]" | ||
72 | :page-size="dashboardForm.size" | ||
73 | :total="total" | ||
74 | ></el-pagination> | ||
75 | </el-footer>--> | ||
76 | </div> | ||
77 | </div> | ||
78 | </template> | ||
79 | |||
80 | <script> | ||
81 | import { mapGetters } from "vuex"; | ||
82 | import { timestampFormat } from "@/utils/utils"; | ||
83 | import { buildExcelHeader } from "@/api/fetch-api-new.js"; | ||
84 | export default { | ||
85 | name: "Dashboard", | ||
86 | data() { | ||
87 | return { | ||
88 | date: [], | ||
89 | pickerOptions: { | ||
90 | shortcuts: [ | ||
91 | { | ||
92 | text: "最近一周", | ||
93 | onClick(picker) { | ||
94 | const end = new Date(); | ||
95 | const start = new Date(); | ||
96 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); | ||
97 | picker.$emit("pick", [start, end]); | ||
98 | } | ||
99 | }, | ||
100 | { | ||
101 | text: "最近一个月", | ||
102 | onClick(picker) { | ||
103 | const end = new Date(); | ||
104 | const start = new Date(); | ||
105 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); | ||
106 | picker.$emit("pick", [start, end]); | ||
107 | } | ||
108 | }, | ||
109 | { | ||
110 | text: "最近三个月", | ||
111 | onClick(picker) { | ||
112 | const end = new Date(); | ||
113 | const start = new Date(); | ||
114 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); | ||
115 | picker.$emit("pick", [start, end]); | ||
116 | } | ||
117 | } | ||
118 | ] | ||
119 | }, | ||
120 | |||
121 | dashboardForm: { | ||
122 | dateRange: "", | ||
123 | page: 1, | ||
124 | size: 9999 | ||
125 | }, | ||
126 | |||
127 | dashboardInfo: { viewNumber: 0, shareNumber: 0, viewPerson: 0 }, | ||
128 | |||
129 | list: [], //列表数据 | ||
130 | total: 0, //列表总数 | ||
131 | loading: true //表格加载状态 | ||
132 | }; | ||
133 | }, | ||
134 | computed: { | ||
135 | startDate() { | ||
136 | let date = this.date; | ||
137 | let result = (date && date[0]) || ""; | ||
138 | if (result) { | ||
139 | result = date[0].getTime(); | ||
140 | } | ||
141 | return result; | ||
142 | }, | ||
143 | |||
144 | endDate() { | ||
145 | let date = this.date; | ||
146 | let result = (date && date[1]) || ""; | ||
147 | if (result) { | ||
148 | result = date[1].getTime(); | ||
149 | } | ||
150 | return result; | ||
151 | } | ||
152 | }, | ||
153 | methods: { | ||
154 | initData() { | ||
155 | const end = new Date(); | ||
156 | const start = new Date(); | ||
157 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); | ||
158 | this.date = [start, end]; | ||
159 | |||
160 | this.setData(); | ||
161 | }, | ||
162 | |||
163 | getMemberDashboard(resize) { | ||
164 | app | ||
165 | .get({ | ||
166 | url: app.api.getArticleDashboard, | ||
167 | data: this.dashboardForm | ||
168 | }) | ||
169 | .then(res => { | ||
170 | this.dashboardInfo = res; | ||
171 | }) | ||
172 | .catch(err => {}); | ||
173 | }, | ||
174 | |||
175 | getList(resize) { | ||
176 | if (resize && resize != undefined) { | ||
177 | this.dashboardForm.page = 1; | ||
178 | } | ||
179 | this.loading = true; | ||
180 | app | ||
181 | .get({ | ||
182 | url: app.api.getArticleViewRank, | ||
183 | data: this.dashboardForm | ||
184 | }) | ||
185 | .then(res => { | ||
186 | this.loading = false; | ||
187 | this.list = res; | ||
188 | }) | ||
189 | .catch(err => { | ||
190 | this.loading = false; | ||
191 | }); | ||
192 | }, | ||
193 | |||
194 | setData() { | ||
195 | this.dashboardForm.dateRange = | ||
196 | timestampFormat(this.startDate, "yyyy-MM-dd") + | ||
197 | "," + | ||
198 | timestampFormat(this.endDate, "yyyy-MM-dd"); | ||
199 | this.getMemberDashboard(); | ||
200 | this.getList(); | ||
201 | }, | ||
202 | |||
203 | // 切换页码大小 | ||
204 | handleSizeChange(val) { | ||
205 | this.queryForm.size = val; | ||
206 | this.queryForm.page = 1; | ||
207 | this.initData(); | ||
208 | }, | ||
209 | |||
210 | // 切换页码 | ||
211 | handleCurrentChange(val) { | ||
212 | this.queryForm.page = val; | ||
213 | this.initData(); | ||
214 | }, | ||
215 | |||
216 | //导出,下载表格 | ||
217 | exportList() { | ||
218 | let fileName = | ||
219 | "资料库明细" + timestampFormat(new Date().getTime()) + ".xlsx"; | ||
220 | |||
221 | buildExcelHeader({ | ||
222 | url: app.api.exportArticleViewRank, | ||
223 | data: this.dashboardForm, | ||
224 | filename: fileName | ||
225 | }); | ||
226 | } | ||
227 | }, | ||
228 | mounted() {}, | ||
229 | created() { | ||
230 | this.initData(); | ||
231 | } | ||
232 | }; | ||
233 | </script> | ||
234 | |||
235 | <style lang="scss" scoped> | ||
236 | .stat-container { | ||
237 | color: #1a1b1c; | ||
238 | font-weight: 400; | ||
239 | position: relative; | ||
240 | max-width: 1100px; | ||
241 | margin: 0 auto; | ||
242 | padding: 30px; | ||
243 | margin-top: 5px; | ||
244 | background-color: white; | ||
245 | .userInfo { | ||
246 | display: flex; | ||
247 | align-items: center; | ||
248 | span { | ||
249 | font-size: 40px; | ||
250 | margin-left: 30px; | ||
251 | } | ||
252 | } | ||
253 | .btn { | ||
254 | margin-top: 30px; | ||
255 | } | ||
256 | .formBox { | ||
257 | width: 500px; | ||
258 | background-color: white; | ||
259 | padding: 20px; | ||
260 | border-radius: 10px; | ||
261 | margin-top: 30px; | ||
262 | .footerBtn { | ||
263 | text-align: right; | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | |||
268 | h5 { | ||
269 | margin: 0; | ||
270 | } | ||
271 | .dataBoxList { | ||
272 | display: flex; | ||
273 | flex-wrap: wrap; | ||
274 | justify-content: space-between; | ||
275 | } | ||
276 | .dataBox { | ||
277 | width: 100%; | ||
278 | min-height: 240px; | ||
279 | background-color: rgb(242, 242, 242); | ||
280 | overflow: hidden; | ||
281 | margin-bottom: 30px; | ||
282 | .tit { | ||
283 | font-size: 22px; | ||
284 | margin: 30px; | ||
285 | } | ||
286 | |||
287 | .dataList { | ||
288 | display: flex; | ||
289 | justify-content: center; | ||
290 | margin-top: 60px; | ||
291 | .item { | ||
292 | width: 250px; | ||
293 | text-align: center; | ||
294 | label { | ||
295 | font-size: 16px; | ||
296 | } | ||
297 | h5 { | ||
298 | font-size: 40px; | ||
299 | margin: 20px 0; | ||
300 | } | ||
301 | } | ||
302 | } | ||
303 | |||
304 | .chartList { | ||
305 | width: 98%; | ||
306 | display: flex; | ||
307 | margin: 30px 0; | ||
308 | margin-left: 1%; | ||
309 | .chare { | ||
310 | width: 100%; | ||
311 | height: 400px; | ||
312 | } | ||
313 | } | ||
314 | } | ||
315 | |||
316 | .fixed-bottom { | ||
317 | width: 100%; | ||
318 | text-align: right; | ||
319 | } | ||
320 | |||
321 | .el-header { | ||
322 | padding: 0; | ||
323 | } | ||
324 | </style> |
src/views/Q&A/report/classify.vue
0 → 100644
1 | <template> | ||
2 | <div class="tablePage"> | ||
3 | <!-- 筛选参数 --> | ||
4 | <el-header> | ||
5 | <el-form :inline="true" style="display:flex"> | ||
6 | <el-form-item style="flex-grow: 1"> | ||
7 | <el-date-picker | ||
8 | v-model="date" | ||
9 | @change="setData" | ||
10 | type="daterange" | ||
11 | align="right" | ||
12 | unlink-panels | ||
13 | range-separator="至" | ||
14 | start-placeholder="开始日期" | ||
15 | end-placeholder="结束日期" | ||
16 | :picker-options="pickerOptions" | ||
17 | ></el-date-picker> | ||
18 | </el-form-item> | ||
19 | |||
20 | <el-form-item> | ||
21 | <el-button @click="exportList()" type="primary"> | ||
22 | <i class="el-icon-download"></i>导出明细 | ||
23 | </el-button> | ||
24 | </el-form-item> | ||
25 | </el-form> | ||
26 | </el-header> | ||
27 | |||
28 | <!-- 表格 --> | ||
29 | <el-container> | ||
30 | <el-table :data="list" :loading="loading"> | ||
31 | <el-table-column label="分类名称" prop="classifyName"></el-table-column> | ||
32 | <el-table-column label="浏览次数" prop="viewNumber"></el-table-column> | ||
33 | <el-table-column label="浏览人数" prop="viewPerson"></el-table-column> | ||
34 | </el-table> | ||
35 | </el-container> | ||
36 | <!-- 分页 --> | ||
37 | <!-- <el-footer class="fixed-bottom"> | ||
38 | <el-pagination | ||
39 | background | ||
40 | layout="total, sizes, prev, pager, next, jumper" | ||
41 | :current-page="dashboardForm.page" | ||
42 | @size-change="handleSizeChange" | ||
43 | @current-change="handleCurrentChange" | ||
44 | :page-sizes="[10,20,30,50]" | ||
45 | :page-size="dashboardForm.size" | ||
46 | :total="total" | ||
47 | ></el-pagination> | ||
48 | </el-footer>--> | ||
49 | </div> | ||
50 | </template> | ||
51 | |||
52 | <script> | ||
53 | import { mapGetters } from "vuex"; | ||
54 | import { timestampFormat } from "@/utils/utils"; | ||
55 | import { buildExcelHeader } from "@/api/fetch-api-new.js"; | ||
56 | export default { | ||
57 | name: "Dashboard", | ||
58 | data() { | ||
59 | return { | ||
60 | date: [], | ||
61 | pickerOptions: { | ||
62 | shortcuts: [ | ||
63 | { | ||
64 | text: "最近一周", | ||
65 | onClick(picker) { | ||
66 | const end = new Date(); | ||
67 | const start = new Date(); | ||
68 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); | ||
69 | picker.$emit("pick", [start, end]); | ||
70 | } | ||
71 | }, | ||
72 | { | ||
73 | text: "最近一个月", | ||
74 | onClick(picker) { | ||
75 | const end = new Date(); | ||
76 | const start = new Date(); | ||
77 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); | ||
78 | picker.$emit("pick", [start, end]); | ||
79 | } | ||
80 | }, | ||
81 | { | ||
82 | text: "最近三个月", | ||
83 | onClick(picker) { | ||
84 | const end = new Date(); | ||
85 | const start = new Date(); | ||
86 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); | ||
87 | picker.$emit("pick", [start, end]); | ||
88 | } | ||
89 | } | ||
90 | ] | ||
91 | }, | ||
92 | |||
93 | dashboardForm: { | ||
94 | dateRange: "", | ||
95 | page: 1, | ||
96 | size: 9999 | ||
97 | }, | ||
98 | |||
99 | dashboardInfo: {}, | ||
100 | |||
101 | list: [], //列表数据 | ||
102 | total: 0, //列表总数 | ||
103 | loading: true //表格加载状态 | ||
104 | }; | ||
105 | }, | ||
106 | computed: { | ||
107 | startDate() { | ||
108 | let date = this.date; | ||
109 | let result = (date && date[0]) || ""; | ||
110 | if (result) { | ||
111 | result = date[0].getTime(); | ||
112 | } | ||
113 | return result; | ||
114 | }, | ||
115 | |||
116 | endDate() { | ||
117 | let date = this.date; | ||
118 | let result = (date && date[1]) || ""; | ||
119 | if (result) { | ||
120 | result = date[1].getTime(); | ||
121 | } | ||
122 | return result; | ||
123 | } | ||
124 | }, | ||
125 | methods: { | ||
126 | initData() { | ||
127 | const end = new Date(); | ||
128 | const start = new Date(); | ||
129 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); | ||
130 | this.date = [start, end]; | ||
131 | |||
132 | this.setData(); | ||
133 | }, | ||
134 | |||
135 | getList(resize) { | ||
136 | if (resize && resize != undefined) { | ||
137 | this.dashboardForm.page = 1; | ||
138 | } | ||
139 | this.loading = true; | ||
140 | app | ||
141 | .get({ | ||
142 | url: app.api.getArticleClassifyRank, | ||
143 | data: this.dashboardForm | ||
144 | }) | ||
145 | .then(res => { | ||
146 | this.loading = false; | ||
147 | this.list = res; | ||
148 | }) | ||
149 | .catch(err => { | ||
150 | this.loading = false; | ||
151 | }); | ||
152 | }, | ||
153 | |||
154 | setData() { | ||
155 | this.dashboardForm.dateRange = | ||
156 | timestampFormat(this.startDate, "yyyy-MM-dd") + | ||
157 | "," + | ||
158 | timestampFormat(this.endDate, "yyyy-MM-dd"); | ||
159 | this.getList(); | ||
160 | }, | ||
161 | |||
162 | // 切换页码大小 | ||
163 | handleSizeChange(val) { | ||
164 | this.queryForm.size = val; | ||
165 | this.queryForm.page = 1; | ||
166 | this.initData(); | ||
167 | }, | ||
168 | |||
169 | // 切换页码 | ||
170 | handleCurrentChange(val) { | ||
171 | this.queryForm.page = val; | ||
172 | this.initData(); | ||
173 | }, | ||
174 | |||
175 | //导出,下载表格 | ||
176 | exportList() { | ||
177 | let fileName = | ||
178 | "分类明细" + timestampFormat(new Date().getTime()) + ".xlsx"; | ||
179 | |||
180 | buildExcelHeader({ | ||
181 | url: app.api.exportArticleClassifyRank, | ||
182 | data: this.dashboardForm, | ||
183 | filename: fileName | ||
184 | }); | ||
185 | } | ||
186 | }, | ||
187 | mounted() {}, | ||
188 | created() { | ||
189 | this.initData(); | ||
190 | } | ||
191 | }; | ||
192 | </script> | ||
193 | |||
194 | <style lang="scss" scoped> | ||
195 | .stat-container { | ||
196 | color: #1a1b1c; | ||
197 | font-weight: 400; | ||
198 | position: relative; | ||
199 | max-width: 1100px; | ||
200 | margin: 0 auto; | ||
201 | padding: 30px; | ||
202 | margin-top: 5px; | ||
203 | background-color: white; | ||
204 | .userInfo { | ||
205 | display: flex; | ||
206 | align-items: center; | ||
207 | span { | ||
208 | font-size: 40px; | ||
209 | margin-left: 30px; | ||
210 | } | ||
211 | } | ||
212 | .btn { | ||
213 | margin-top: 30px; | ||
214 | } | ||
215 | .formBox { | ||
216 | width: 500px; | ||
217 | background-color: white; | ||
218 | padding: 20px; | ||
219 | border-radius: 10px; | ||
220 | margin-top: 30px; | ||
221 | .footerBtn { | ||
222 | text-align: right; | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | |||
227 | h5 { | ||
228 | margin: 0; | ||
229 | } | ||
230 | .dataBoxList { | ||
231 | display: flex; | ||
232 | flex-wrap: wrap; | ||
233 | justify-content: space-between; | ||
234 | } | ||
235 | .dataBox { | ||
236 | width: 100%; | ||
237 | min-height: 240px; | ||
238 | background-color: rgb(242, 242, 242); | ||
239 | overflow: hidden; | ||
240 | margin-bottom: 30px; | ||
241 | .tit { | ||
242 | font-size: 22px; | ||
243 | margin: 30px; | ||
244 | } | ||
245 | |||
246 | .dataList { | ||
247 | display: flex; | ||
248 | justify-content: center; | ||
249 | margin-top: 60px; | ||
250 | .item { | ||
251 | width: 250px; | ||
252 | text-align: center; | ||
253 | label { | ||
254 | font-size: 16px; | ||
255 | } | ||
256 | h5 { | ||
257 | font-size: 40px; | ||
258 | margin: 20px 0; | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | |||
263 | .chartList { | ||
264 | width: 98%; | ||
265 | display: flex; | ||
266 | margin: 30px 0; | ||
267 | margin-left: 1%; | ||
268 | .chare { | ||
269 | width: 100%; | ||
270 | height: 400px; | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | |||
275 | .fixed-bottom { | ||
276 | width: 100%; | ||
277 | text-align: right; | ||
278 | } | ||
279 | |||
280 | .el-header { | ||
281 | padding: 0; | ||
282 | } | ||
283 | </style> |
src/views/Q&A/report/keyword.vue
0 → 100644
1 | <template> | ||
2 | <div class="tablePage"> | ||
3 | <!-- 筛选参数 --> | ||
4 | <el-header> | ||
5 | <el-form :inline="true" style="display:flex"> | ||
6 | <el-form-item style="flex-grow: 1"> | ||
7 | <el-date-picker | ||
8 | v-model="date" | ||
9 | @change="setData" | ||
10 | type="daterange" | ||
11 | align="right" | ||
12 | unlink-panels | ||
13 | range-separator="至" | ||
14 | start-placeholder="开始日期" | ||
15 | end-placeholder="结束日期" | ||
16 | :picker-options="pickerOptions" | ||
17 | ></el-date-picker> | ||
18 | </el-form-item> | ||
19 | |||
20 | <!-- <el-form-item> | ||
21 | <el-button @click="exportList()" type="primary"> | ||
22 | <i class="el-icon-download"></i>导出明细 | ||
23 | </el-button> | ||
24 | </el-form-item> --> | ||
25 | </el-form> | ||
26 | </el-header> | ||
27 | |||
28 | <!-- 表格 --> | ||
29 | <el-container> | ||
30 | <el-table :data="list" :loading="loading"> | ||
31 | <el-table-column label="关键词" prop="word"></el-table-column> | ||
32 | <el-table-column label="搜索次数" prop="times"></el-table-column> | ||
33 | <el-table-column label="搜索匹配文章数" prop="match"></el-table-column> | ||
34 | </el-table> | ||
35 | </el-container> | ||
36 | <!-- 分页 --> | ||
37 | <!-- <el-footer class="fixed-bottom"> | ||
38 | <el-pagination | ||
39 | background | ||
40 | layout="total, sizes, prev, pager, next, jumper" | ||
41 | :current-page="dashboardForm.page" | ||
42 | @size-change="handleSizeChange" | ||
43 | @current-change="handleCurrentChange" | ||
44 | :page-sizes="[10,20,30,50]" | ||
45 | :page-size="dashboardForm.size" | ||
46 | :total="total" | ||
47 | ></el-pagination> | ||
48 | </el-footer>--> | ||
49 | </div> | ||
50 | </template> | ||
51 | |||
52 | <script> | ||
53 | import { mapGetters } from "vuex"; | ||
54 | import { timestampFormat } from "@/utils/utils"; | ||
55 | import { buildExcelHeader } from "@/api/fetch-api-new.js"; | ||
56 | export default { | ||
57 | name: "Dashboard", | ||
58 | data() { | ||
59 | return { | ||
60 | date: [], | ||
61 | pickerOptions: { | ||
62 | shortcuts: [ | ||
63 | { | ||
64 | text: "最近一周", | ||
65 | onClick(picker) { | ||
66 | const end = new Date(); | ||
67 | const start = new Date(); | ||
68 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); | ||
69 | picker.$emit("pick", [start, end]); | ||
70 | } | ||
71 | }, | ||
72 | { | ||
73 | text: "最近一个月", | ||
74 | onClick(picker) { | ||
75 | const end = new Date(); | ||
76 | const start = new Date(); | ||
77 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); | ||
78 | picker.$emit("pick", [start, end]); | ||
79 | } | ||
80 | }, | ||
81 | { | ||
82 | text: "最近三个月", | ||
83 | onClick(picker) { | ||
84 | const end = new Date(); | ||
85 | const start = new Date(); | ||
86 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); | ||
87 | picker.$emit("pick", [start, end]); | ||
88 | } | ||
89 | } | ||
90 | ] | ||
91 | }, | ||
92 | |||
93 | dashboardForm: { | ||
94 | dateRange: "", | ||
95 | page: 1, | ||
96 | size: 9999 | ||
97 | }, | ||
98 | |||
99 | dashboardInfo: {}, | ||
100 | |||
101 | list: [], //列表数据 | ||
102 | total: 0, //列表总数 | ||
103 | loading: true //表格加载状态 | ||
104 | }; | ||
105 | }, | ||
106 | computed: { | ||
107 | startDate() { | ||
108 | let date = this.date; | ||
109 | let result = (date && date[0]) || ""; | ||
110 | if (result) { | ||
111 | result = date[0].getTime(); | ||
112 | } | ||
113 | return result; | ||
114 | }, | ||
115 | |||
116 | endDate() { | ||
117 | let date = this.date; | ||
118 | let result = (date && date[1]) || ""; | ||
119 | if (result) { | ||
120 | result = date[1].getTime(); | ||
121 | } | ||
122 | return result; | ||
123 | } | ||
124 | }, | ||
125 | methods: { | ||
126 | initData() { | ||
127 | const end = new Date(); | ||
128 | const start = new Date(); | ||
129 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); | ||
130 | this.date = [start, end]; | ||
131 | |||
132 | this.setData(); | ||
133 | }, | ||
134 | |||
135 | getList(resize) { | ||
136 | if (resize && resize != undefined) { | ||
137 | this.dashboardForm.page = 1; | ||
138 | } | ||
139 | this.loading = true; | ||
140 | app | ||
141 | .get({ | ||
142 | url: app.api.getArticleKeywordStat, | ||
143 | data: this.dashboardForm | ||
144 | }) | ||
145 | .then(res => { | ||
146 | this.loading = false; | ||
147 | this.list = res; | ||
148 | }) | ||
149 | .catch(err => { | ||
150 | this.loading = false; | ||
151 | }); | ||
152 | }, | ||
153 | |||
154 | setData() { | ||
155 | this.dashboardForm.dateRange = | ||
156 | timestampFormat(this.startDate, "yyyy-MM-dd") + | ||
157 | "," + | ||
158 | timestampFormat(this.endDate, "yyyy-MM-dd"); | ||
159 | this.getList(); | ||
160 | }, | ||
161 | |||
162 | // 切换页码大小 | ||
163 | handleSizeChange(val) { | ||
164 | this.queryForm.size = val; | ||
165 | this.queryForm.page = 1; | ||
166 | this.initData(); | ||
167 | }, | ||
168 | |||
169 | // 切换页码 | ||
170 | handleCurrentChange(val) { | ||
171 | this.queryForm.page = val; | ||
172 | this.initData(); | ||
173 | }, | ||
174 | |||
175 | //导出,下载表格 | ||
176 | exportList() { | ||
177 | let fileName = | ||
178 | "分类明细" + timestampFormat(new Date().getTime()) + ".xlsx"; | ||
179 | |||
180 | buildExcelHeader({ | ||
181 | url: app.api.exportArticleClassifyRank, | ||
182 | data: this.dashboardForm, | ||
183 | filename: fileName | ||
184 | }); | ||
185 | } | ||
186 | }, | ||
187 | mounted() {}, | ||
188 | created() { | ||
189 | this.initData(); | ||
190 | } | ||
191 | }; | ||
192 | </script> | ||
193 | |||
194 | <style lang="scss" scoped> | ||
195 | .stat-container { | ||
196 | color: #1a1b1c; | ||
197 | font-weight: 400; | ||
198 | position: relative; | ||
199 | max-width: 1100px; | ||
200 | margin: 0 auto; | ||
201 | padding: 30px; | ||
202 | margin-top: 5px; | ||
203 | background-color: white; | ||
204 | .userInfo { | ||
205 | display: flex; | ||
206 | align-items: center; | ||
207 | span { | ||
208 | font-size: 40px; | ||
209 | margin-left: 30px; | ||
210 | } | ||
211 | } | ||
212 | .btn { | ||
213 | margin-top: 30px; | ||
214 | } | ||
215 | .formBox { | ||
216 | width: 500px; | ||
217 | background-color: white; | ||
218 | padding: 20px; | ||
219 | border-radius: 10px; | ||
220 | margin-top: 30px; | ||
221 | .footerBtn { | ||
222 | text-align: right; | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | |||
227 | h5 { | ||
228 | margin: 0; | ||
229 | } | ||
230 | .dataBoxList { | ||
231 | display: flex; | ||
232 | flex-wrap: wrap; | ||
233 | justify-content: space-between; | ||
234 | } | ||
235 | .dataBox { | ||
236 | width: 100%; | ||
237 | min-height: 240px; | ||
238 | background-color: rgb(242, 242, 242); | ||
239 | overflow: hidden; | ||
240 | margin-bottom: 30px; | ||
241 | .tit { | ||
242 | font-size: 22px; | ||
243 | margin: 30px; | ||
244 | } | ||
245 | |||
246 | .dataList { | ||
247 | display: flex; | ||
248 | justify-content: center; | ||
249 | margin-top: 60px; | ||
250 | .item { | ||
251 | width: 250px; | ||
252 | text-align: center; | ||
253 | label { | ||
254 | font-size: 16px; | ||
255 | } | ||
256 | h5 { | ||
257 | font-size: 40px; | ||
258 | margin: 20px 0; | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | |||
263 | .chartList { | ||
264 | width: 98%; | ||
265 | display: flex; | ||
266 | margin: 30px 0; | ||
267 | margin-left: 1%; | ||
268 | .chare { | ||
269 | width: 100%; | ||
270 | height: 400px; | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | |||
275 | .fixed-bottom { | ||
276 | width: 100%; | ||
277 | text-align: right; | ||
278 | } | ||
279 | |||
280 | .el-header { | ||
281 | padding: 0; | ||
282 | } | ||
283 | </style> |
1 | <template> | 1 | <template> |
2 | <div class="navbar"> | 2 | <div class="navbar"> |
3 | <hamburger :toggle-click="toggleSideBar" :is-active="sidebar.opened" class="hamburger-container"/> | 3 | <hamburger |
4 | :toggle-click="toggleSideBar" | ||
5 | :is-active="sidebar.opened" | ||
6 | class="hamburger-container" | ||
7 | /> | ||
4 | <breadcrumb /> | 8 | <breadcrumb /> |
5 | <el-dropdown class="avatar-container" trigger="click"> | 9 | <el-dropdown class="avatar-container" trigger="click"> |
6 | <div class="avatar-wrapper"> | 10 | <div class="avatar-wrapper"> |
7 | <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar"> | 11 | <img :src="require('@/assets/user/user.jpg')" class="user-avatar" /> |
8 | <i class="el-icon-caret-bottom"/> | 12 | <i class="el-icon-caret-bottom" /> |
9 | </div> | 13 | </div> |
10 | <el-dropdown-menu slot="dropdown" class="user-dropdown"> | 14 | <el-dropdown-menu slot="dropdown" class="user-dropdown"> |
11 | <router-link class="inlineBlock" to="/"> | 15 | <router-link class="inlineBlock" to="/"> |
12 | <el-dropdown-item> | 16 | <el-dropdown-item>Home</el-dropdown-item> |
13 | Home | ||
14 | </el-dropdown-item> | ||
15 | </router-link> | 17 | </router-link> |
16 | <el-dropdown-item divided> | 18 | <el-dropdown-item divided> |
17 | <span style="display:block;" @click="logout">LogOut</span> | 19 | <span style="display:block;" @click="logout">LogOut</span> |
... | @@ -22,9 +24,9 @@ | ... | @@ -22,9 +24,9 @@ |
22 | </template> | 24 | </template> |
23 | 25 | ||
24 | <script> | 26 | <script> |
25 | import { mapGetters } from 'vuex' | 27 | import { mapGetters } from "vuex"; |
26 | import Breadcrumb from '@/components/Breadcrumb' | 28 | import Breadcrumb from "@/components/Breadcrumb"; |
27 | import Hamburger from '@/components/Hamburger' | 29 | import Hamburger from "@/components/Hamburger"; |
28 | 30 | ||
29 | export default { | 31 | export default { |
30 | components: { | 32 | components: { |
... | @@ -32,29 +34,27 @@ export default { | ... | @@ -32,29 +34,27 @@ export default { |
32 | Hamburger | 34 | Hamburger |
33 | }, | 35 | }, |
34 | computed: { | 36 | computed: { |
35 | ...mapGetters([ | 37 | ...mapGetters(["sidebar", "avatar"]) |
36 | 'sidebar', | ||
37 | 'avatar' | ||
38 | ]) | ||
39 | }, | 38 | }, |
40 | methods: { | 39 | methods: { |
41 | toggleSideBar() { | 40 | toggleSideBar() { |
42 | this.$store.dispatch('ToggleSideBar') | 41 | this.$store.dispatch("ToggleSideBar"); |
43 | }, | 42 | }, |
44 | logout() { | 43 | logout() { |
45 | this.$store.dispatch('LogOut').then(() => { | 44 | // this.$store.dispatch('LogOut').then(() => { |
46 | location.reload() // 为了重新实例化vue-router对象 避免bug | 45 | // location.reload() // 为了重新实例化vue-router对象 避免bug |
47 | }) | 46 | // }) |
47 | this.$router.push({ path: "/login" }); | ||
48 | } | 48 | } |
49 | } | 49 | } |
50 | } | 50 | }; |
51 | </script> | 51 | </script> |
52 | 52 | ||
53 | <style rel="stylesheet/scss" lang="scss" scoped> | 53 | <style rel="stylesheet/scss" lang="scss" scoped> |
54 | .navbar { | 54 | .navbar { |
55 | height: 50px; | 55 | height: 50px; |
56 | line-height: 50px; | 56 | line-height: 50px; |
57 | box-shadow: 0 1px 3px 0 rgba(0,0,0,.12), 0 0 3px 0 rgba(0,0,0,.04); | 57 | box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04); |
58 | .hamburger-container { | 58 | .hamburger-container { |
59 | line-height: 58px; | 59 | line-height: 58px; |
60 | height: 50px; | 60 | height: 50px; | ... | ... |
1 | <template> | 1 | <template> |
2 | <div class="login-container"> | 2 | <div class="login-container"> |
3 | <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left"> | 3 | <el-form |
4 | <h3 class="title">Trimble Geospatial</h3> | 4 | ref="loginForm" |
5 | <el-form-item prop="username"> | 5 | :model="loginForm" |
6 | <span class="svg-container"> | 6 | :rules="loginRules" |
7 | <svg-icon icon-class="user" /> | 7 | class="login-form" |
8 | </span> | 8 | auto-complete="on" |
9 | <el-input v-model="loginForm.username" name="username" type="text" auto-complete="on" placeholder="username" /> | 9 | label-position="left" |
10 | </el-form-item> | 10 | > |
11 | <el-form-item prop="password"> | 11 | <h3 class="title">Trimble Geospatial</h3> |
12 | <span class="svg-container"> | 12 | <el-form-item prop="username"> |
13 | <svg-icon icon-class="password" /> | 13 | <span class="svg-container"> |
14 | </span> | 14 | <svg-icon icon-class="user" /> |
15 | <el-input :type="pwdType" v-model="loginForm.password" name="password" auto-complete="on" placeholder="password" @keyup.enter.native="handleLogin" /> | 15 | </span> |
16 | <span class="show-pwd" @click="showPwd"> | 16 | <el-input |
17 | <svg-icon :icon-class="pwdType === 'password' ? 'eye' : 'eye-open'" /> | 17 | v-model="loginForm.username" |
18 | </span> | 18 | name="username" |
19 | </el-form-item> | 19 | type="text" |
20 | <el-form-item> | 20 | auto-complete="on" |
21 | <el-button :loading="loading" type="primary" style="width:100%;" @click.native.prevent="handleLogin"> | 21 | placeholder="username" |
22 | Sign in | 22 | /> |
23 | </el-button> | 23 | </el-form-item> |
24 | </el-form-item> | 24 | <el-form-item prop="password"> |
25 | <!--<div class="tips"> | 25 | <span class="svg-container"> |
26 | <svg-icon icon-class="password" /> | ||
27 | </span> | ||
28 | <el-input | ||
29 | :type="pwdType" | ||
30 | v-model="loginForm.password" | ||
31 | name="password" | ||
32 | auto-complete="on" | ||
33 | placeholder="password" | ||
34 | @keyup.enter.native="handleLogin" | ||
35 | /> | ||
36 | <span class="show-pwd" @click="showPwd"> | ||
37 | <svg-icon :icon-class="pwdType === 'password' ? 'eye' : 'eye-open'" /> | ||
38 | </span> | ||
39 | </el-form-item> | ||
40 | <el-form-item> | ||
41 | <el-button | ||
42 | :loading="loading" | ||
43 | type="primary" | ||
44 | style="width:100%;" | ||
45 | @click.native.prevent="handleLogin" | ||
46 | >Sign in</el-button> | ||
47 | </el-form-item> | ||
48 | <!--<div class="tips"> | ||
26 | <span style="margin-right:20px;">username: admin</span> | 49 | <span style="margin-right:20px;">username: admin</span> |
27 | <span> password: admin</span> | 50 | <span> password: admin</span> |
28 | </div>--> | 51 | </div>--> |
29 | </el-form> | 52 | </el-form> |
30 | </div> | 53 | </div> |
31 | </template> | 54 | </template> |
32 | 55 | ||
33 | <script> | 56 | <script> |
34 | import { isvalidUsername } from '@/utils/validate' | 57 | import { isvalidUsername } from "@/utils/validate"; |
58 | import { setToken } from "@/utils/auth"; | ||
35 | 59 | ||
36 | export default { | 60 | export default { |
37 | name: 'Login', | 61 | name: "Login", |
38 | data() { | 62 | data() { |
39 | const validateUsername = (rule, value, callback) => { | 63 | const validateUsername = (rule, value, callback) => { |
40 | if (!isvalidUsername(value)) { | 64 | if (!isvalidUsername(value)) { |
41 | callback(new Error('请输入正确的用户名')) | 65 | callback(new Error("请输入正确的用户名")); |
42 | } else { | 66 | } else { |
43 | callback() | 67 | callback(); |
44 | } | 68 | } |
45 | } | 69 | }; |
46 | const validatePass = (rule, value, callback) => { | 70 | const validatePass = (rule, value, callback) => { |
47 | if (value.length < 5) { | 71 | if (value.length < 5) { |
48 | callback(new Error('密码不能小于5位')) | 72 | callback(new Error("密码不能小于5位")); |
49 | } else { | 73 | } else { |
50 | callback() | 74 | callback(); |
51 | } | 75 | } |
52 | } | 76 | }; |
53 | return { | 77 | return { |
54 | loginForm: { | 78 | loginForm: { |
55 | username: 'admin', | 79 | username: "admin", |
56 | password: 'admin' | 80 | password: "admin" |
57 | }, | 81 | }, |
58 | loginRules: { | 82 | loginRules: { |
59 | username: [ | 83 | username: [ |
60 | { | 84 | { |
61 | required: true, | 85 | required: true, |
62 | trigger: 'blur', | 86 | trigger: "blur", |
63 | validator: validateUsername | 87 | validator: validateUsername |
64 | } | 88 | } |
65 | ], | 89 | ], |
66 | password: [ | 90 | password: [{ required: true, trigger: "blur", validator: validatePass }] |
67 | { required: true, trigger: 'blur', validator: validatePass } | 91 | }, |
68 | ] | 92 | loading: false, |
69 | }, | 93 | pwdType: "password", |
70 | loading: false, | 94 | redirect: undefined |
71 | pwdType: 'password', | 95 | }; |
72 | redirect: undefined | 96 | }, |
73 | } | 97 | watch: { |
74 | }, | 98 | $route: { |
75 | watch: { | 99 | handler: function(route) { |
76 | $route: { | 100 | this.redirect = route.query && route.query.redirect; |
77 | handler: function(route) { | 101 | }, |
78 | this.redirect = route.query && route.query.redirect | 102 | immediate: true |
79 | }, | 103 | } |
80 | immediate: true | 104 | }, |
81 | } | 105 | methods: { |
106 | showPwd() { | ||
107 | if (this.pwdType === "password") { | ||
108 | this.pwdType = ""; | ||
109 | } else { | ||
110 | this.pwdType = "password"; | ||
111 | } | ||
82 | }, | 112 | }, |
83 | methods: { | 113 | handleLogin() { |
84 | showPwd() { | 114 | this.$refs.loginForm.validate(valid => { |
85 | if (this.pwdType === 'password') { | 115 | if (valid) { |
86 | this.pwdType = '' | 116 | this.loading = true; |
87 | } else { | 117 | setToken('admin-token') |
88 | this.pwdType = 'password' | 118 | this.$router.push({ path: this.redirect || "/" }); |
89 | } | 119 | // setToken; |
90 | }, | 120 | // this.$store |
91 | handleLogin() { | 121 | // .dispatch('Login', this.loginForm) |
92 | this.$refs.loginForm.validate(valid => { | 122 | // .then(() => { |
93 | if (valid) { | 123 | // this.loading = false |
94 | this.loading = true | 124 | // this.$router.push({ path: this.redirect || '/' }) |
95 | this.$store | 125 | // // this.$router.push({ path: '/dictionary/pv' }) |
96 | .dispatch('Login', this.loginForm) | 126 | // }) |
97 | .then(() => { | 127 | // .catch(() => { |
98 | this.loading = false | 128 | // this.loading = false |
99 | this.$router.push({ path: this.redirect || '/' }) | 129 | // }) |
100 | // this.$router.push({ path: '/dictionary/pv' }) | 130 | } else { |
101 | }) | 131 | console.log("error submit!!"); |
102 | .catch(() => { | 132 | return false; |
103 | this.loading = false | ||
104 | }) | ||
105 | } else { | ||
106 | console.log('error submit!!') | ||
107 | return false | ||
108 | } | ||
109 | }) | ||
110 | } | 133 | } |
134 | }); | ||
111 | } | 135 | } |
112 | } | 136 | } |
137 | }; | ||
113 | </script> | 138 | </script> |
114 | 139 | ||
115 | <style rel="stylesheet/scss" lang="scss"> | 140 | <style rel="stylesheet/scss" lang="scss"> |
... | @@ -118,30 +143,30 @@ $light_gray: #eee; | ... | @@ -118,30 +143,30 @@ $light_gray: #eee; |
118 | 143 | ||
119 | /* reset element-ui css */ | 144 | /* reset element-ui css */ |
120 | .login-container { | 145 | .login-container { |
121 | .el-input { | 146 | .el-input { |
122 | display: inline-block; | 147 | display: inline-block; |
123 | height: 47px; | 148 | height: 47px; |
124 | width: 85%; | 149 | width: 85%; |
125 | input { | 150 | input { |
126 | background: transparent; | 151 | background: transparent; |
127 | border: 0px; | 152 | border: 0px; |
128 | -webkit-appearance: none; | 153 | -webkit-appearance: none; |
129 | border-radius: 0px; | 154 | border-radius: 0px; |
130 | padding: 12px 5px 12px 15px; | 155 | padding: 12px 5px 12px 15px; |
131 | color: $light_gray; | 156 | color: $light_gray; |
132 | height: 47px; | 157 | height: 47px; |
133 | &:-webkit-autofill { | 158 | &:-webkit-autofill { |
134 | -webkit-box-shadow: 0 0 0px 1000px $bg inset !important; | 159 | -webkit-box-shadow: 0 0 0px 1000px $bg inset !important; |
135 | -webkit-text-fill-color: #fff !important; | 160 | -webkit-text-fill-color: #fff !important; |
136 | } | 161 | } |
137 | } | ||
138 | } | ||
139 | .el-form-item { | ||
140 | border: 1px solid rgba(255, 255, 255, 0.1); | ||
141 | background: rgba(0, 0, 0, 0.1); | ||
142 | border-radius: 5px; | ||
143 | color: #454545; | ||
144 | } | 162 | } |
163 | } | ||
164 | .el-form-item { | ||
165 | border: 1px solid rgba(255, 255, 255, 0.1); | ||
166 | background: rgba(0, 0, 0, 0.1); | ||
167 | border-radius: 5px; | ||
168 | color: #454545; | ||
169 | } | ||
145 | } | 170 | } |
146 | </style> | 171 | </style> |
147 | 172 | ||
... | @@ -150,52 +175,52 @@ $bg: #2d3a4b; | ... | @@ -150,52 +175,52 @@ $bg: #2d3a4b; |
150 | $dark_gray: #889aa4; | 175 | $dark_gray: #889aa4; |
151 | $light_gray: #eee; | 176 | $light_gray: #eee; |
152 | .login-container { | 177 | .login-container { |
153 | position: fixed; | 178 | position: fixed; |
154 | height: 100%; | 179 | height: 100%; |
155 | width: 100%; | 180 | width: 100%; |
156 | background-color: $bg; | 181 | background-color: $bg; |
157 | .login-form { | 182 | .login-form { |
158 | position: absolute; | 183 | position: absolute; |
159 | left: 0; | 184 | left: 0; |
160 | right: 0; | 185 | right: 0; |
161 | width: 520px; | 186 | width: 520px; |
162 | max-width: 100%; | 187 | max-width: 100%; |
163 | padding: 35px 35px 15px 35px; | 188 | padding: 35px 35px 15px 35px; |
164 | margin: 120px auto; | 189 | margin: 120px auto; |
165 | } | 190 | } |
166 | .tips { | 191 | .tips { |
167 | font-size: 14px; | 192 | font-size: 14px; |
168 | color: #fff; | 193 | color: #fff; |
169 | margin-bottom: 10px; | 194 | margin-bottom: 10px; |
170 | span { | 195 | span { |
171 | &:first-of-type { | 196 | &:first-of-type { |
172 | margin-right: 16px; | 197 | margin-right: 16px; |
173 | } | 198 | } |
174 | } | ||
175 | } | ||
176 | .svg-container { | ||
177 | padding: 6px 5px 6px 15px; | ||
178 | color: $dark_gray; | ||
179 | vertical-align: middle; | ||
180 | width: 30px; | ||
181 | display: inline-block; | ||
182 | } | ||
183 | .title { | ||
184 | font-size: 26px; | ||
185 | font-weight: 400; | ||
186 | color: $light_gray; | ||
187 | margin: 0px auto 40px auto; | ||
188 | text-align: center; | ||
189 | font-weight: bold; | ||
190 | } | ||
191 | .show-pwd { | ||
192 | position: absolute; | ||
193 | right: 10px; | ||
194 | top: 7px; | ||
195 | font-size: 16px; | ||
196 | color: $dark_gray; | ||
197 | cursor: pointer; | ||
198 | user-select: none; | ||
199 | } | 199 | } |
200 | } | ||
201 | .svg-container { | ||
202 | padding: 6px 5px 6px 15px; | ||
203 | color: $dark_gray; | ||
204 | vertical-align: middle; | ||
205 | width: 30px; | ||
206 | display: inline-block; | ||
207 | } | ||
208 | .title { | ||
209 | font-size: 26px; | ||
210 | font-weight: 400; | ||
211 | color: $light_gray; | ||
212 | margin: 0px auto 40px auto; | ||
213 | text-align: center; | ||
214 | font-weight: bold; | ||
215 | } | ||
216 | .show-pwd { | ||
217 | position: absolute; | ||
218 | right: 10px; | ||
219 | top: 7px; | ||
220 | font-size: 16px; | ||
221 | color: $dark_gray; | ||
222 | cursor: pointer; | ||
223 | user-select: none; | ||
224 | } | ||
200 | } | 225 | } |
201 | </style> | 226 | </style> | ... | ... |
-
Please register or sign in to post a comment