long
2021-11-04 2f7798820057f2c996640e221cddd02a27f64621
提交 | 用户 | age
36b711 1 <template>
L 2   <div class="app-container">
7f89d0 3     <!-- 返回按钮和标题 -->
C 4     <!-- <el-page-header class="mb20" content="xx" @back="$router.go(-1)" /> -->
5
36b711 6     <!-- 搜索区 ↓↓↓↓↓↓↓↓↓↓ -->
L 7     <el-form v-show="showSearch" ref="searchForm" :inline="true">
8       <el-form-item label="角色名称">
9         <el-input
10           v-model="keyWord"
11           placeholder="请输入角色名称"
12           clearable
13           size="small"
14           style="width: 240px"
15           maxlength="50"
16           @keyup.enter.native="reGetList"
17         />
18       </el-form-item>
19       <el-form-item>
20         <el-button type="cyan" icon="el-icon-search" size="mini" @click="reGetList">搜索</el-button>
21         <el-button icon="el-icon-refresh" size="mini" @click="resetHandle">重置</el-button>
22       </el-form-item>
23     </el-form>
24     <!-- 搜索区 ↑↑↑↑↑↑↑↑↑↑ -->
25
26     <!-- 操作区 ↓↓↓↓↓↓↓↓↓↓ -->
27     <el-row :gutter="10" class="mb8">
7f89d0 28       <!-- 权限判断 v-if="getAuthValueFN('xxx_add')" -->
36b711 29       <el-col :span="1.5">
L 30         <el-button
31           type="primary"
32           icon="el-icon-plus"
33           size="mini"
34           @click="showAddDialog"
35         >新增</el-button>
36       </el-col>
eaaa5b 37       <el-col :span="1.5">
L 38         <el-button
39           v-if="getAuthValueFN('xxxx')"
40           type="primary"
41           icon="el-icon-download"
42           size="mini"
43           @click="exportList"
f84ee2 44         >导出列表</el-button>
eaaa5b 45       </el-col>
L 46       <el-col :span="1.5">
47         <el-button
48           v-if="getAuthValueFN('xxxx')"
49           type="primary"
50           class="rel"
51           size="mini"
52           icon="el-icon-upload2"
53           style="overflow:hidden"
3dcc7c 54         >导入数据
eaaa5b 55           <input id="upload" ref="upload" type="file" @change="fileChange">
L 56         </el-button>
57       </el-col>
f84ee2 58       <el-col :span="1.5">
L 59         <!-- 导出模版 -->
60         <a v-if="getAuthValueFN('xxxx')" href="./static/excel/schedule.xls" download>
5f052d 61           <el-button type="primary" icon="el-icon-download" size="mini">下载导入模版</el-button>
f84ee2 62         </a>
L 63       </el-col>
64
36b711 65       <right-toolbar :show-search.sync="showSearch" @queryTable="getList" />
L 66     </el-row>
67     <!-- 操作区 ↑↑↑↑↑↑↑↑↑↑ -->
68
54e0b4 69     <el-table :data="list" :max-height="clienHeight" stripe>
36b711 70       <el-table-column type="index" label="序号" align="center" width="60" />
1dcdda 71       <el-table-column label="头像" prop="headImg" align="center" min-width="100">
L 72         <template slot-scope="scope">
73           <el-image :src="scope.row.headImg" style="width:50px;height:50px;" fit="contain" :preview-src-list="[scope.row.headImg]">
74             <div slot="error" class="image-slot">
75               <svg-icon icon-class="avatar" style="width:50px;height:50px;" />
76             </div>
77           </el-image>
78         </template>
79       </el-table-column>
36b711 80       <el-table-column label="角色名称" prop="name" align="center" min-width="120" />
L 81       <el-table-column label="角色名称" prop="name" align="center" min-width="120" />
1dcdda 82       <el-table-column label="专家建议" prop="adviceInfo" align="center" min-width="160">
L 83         <template slot-scope="scope">
84           <el-popover
85             placement="top-start"
86             width="400"
87             popper-class="el-popover_tableFilter"
88             trigger="hover"
89             :popper-options="{ removeOnDestroy: true }"
90           >
91             <div style="max-height: 500px;overflow-y: auto;">{{ scope.row.adviceInfo }}</div>
92             <div slot="reference" class="line-clamp-2" style="line-height: 1.2">{{ scope.row.adviceInfo }}</div>
93           </el-popover>
94         </template>
95       </el-table-column>
36b711 96       <el-table-column label="角色名称" prop="name" align="center" min-width="120" />
L 97       <el-table-column label="角色名称" prop="name" align="center" min-width="120" />
98       <el-table-column label="角色名称" prop="name" align="center" min-width="120" />
99       <el-table-column label="角色名称" prop="name" align="center" min-width="120" />
100       <el-table-column label="角色名称" prop="name" align="center" min-width="120" />
101       <el-table-column label="角色名称" prop="name" align="center" min-width="120" />
102       <el-table-column label="角色名称" prop="name" align="center" min-width="120" />
103       <el-table-column label="是否上架" prop="isUp" align="center" min-width="100">
104         <template slot-scope="scope">
7f89d0 105           <!-- 权限判断 v-if="getAuthValueFN('xxx_edit')" -->
36b711 106           <el-switch
L 107             v-model="scope.row.isUp"
108             :active-value="1"
109             :inactive-value="0"
110             @change="handleUpChange(scope.row)"
111           />
112         </template>
113       </el-table-column>
114       <el-table-column label="创建时间" prop="createTime" align="center" min-width="160" />
115       <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120" fixed="right">
116         <template slot-scope="scope">
7f89d0 117           <!-- 权限判断 v-if="getAuthValueFN('xxx_edit')" -->
36b711 118           <el-button
L 119             size="mini"
120             type="text"
121             icon="el-icon-edit"
122             @click="showEditDialog(scope.row)"
123           >编辑</el-button>
7f89d0 124           <!-- 权限判断 v-if="getAuthValueFN('xxx_del')" -->
36b711 125           <el-button
L 126             size="mini"
127             type="text warn"
128             icon="el-icon-delete"
129             @click="handleDelete(scope.row)"
130           >删除</el-button>
131         </template>
132       </el-table-column>
133     </el-table>
134
135     <!-- 新增&编辑 -->
7f89d0 136     <el-dialog v-el-drag-dialog :title="(dialogData.type=='add'?'新增':'编辑') + objectName" width="500px" :visible.sync="dialogVisible" append-to-body :before-close="hideDialog" :close-on-click-modal="false">
36b711 137       <el-form ref="refDialog" :model="dialogData" label-width="110px" :rules="rules" size="small">
L 138         <el-form-item label="名称" prop="name">
139           <el-input v-model="dialogData.name" placeholder="请输入名称" maxlength="50" />
140         </el-form-item>
141         <el-form-item label="是否上架" prop="isUp">
142           <el-switch
143             v-model="dialogData.isUp"
144             :active-value="1"
145             :inactive-value="0"
146           />
147         </el-form-item>
eaaa5b 148         <el-form-item prop="uploadImgs">
L 149           <span slot="label">
150             图片<br><span style="color: #999;font-size: 12px">(xxx*xxx像素)</span>
151           </span>
152           <!-- 上传图片组件(单图) -->
153           <UploadSingleImg
154             ref="refUploadImg"
155             v-model="dialogData.uploadImgs"
156             @change.capture="$refs.refDialog.clearValidate()"
157           />
158         </el-form-item>
36b711 159       </el-form>
L 160       <div slot="footer" class="dialog-footer">
161         <el-button @click="hideDialog">取消</el-button>
162         <el-button type="primary" @click="submitHandle">确定</el-button>
163       </div>
164     </el-dialog>
165
166     <pagination
167       v-show="total>0"
168       :total="total"
169       :page.sync="pageNum"
170       :limit.sync="pageSize"
171       @pagination="getList"
172     />
eaaa5b 173
L 174     <!-- upload放大图片 -->
175     <el-dialog :visible.sync="uploadPreviewVisible" style="text-align:center">
176       <img style="max-width:100%" :src="uploadPreviewUrl" alt="">
177     </el-dialog>
178
36b711 179   </div>
L 180 </template>
181
182 <script>
183
eaaa5b 184 import UploadSingleImg from '@/components_simple/UploadSingleImg'
L 185 import mixin_upload from '@/mixins/upload.js' // 通用上传图片预览
36b711 186 export default {
L 187   name: 'Demo',
eaaa5b 188   components: { UploadSingleImg },
L 189   mixins: [mixin_upload],
36b711 190   data() {
L 191     return {
c00018 192       clienHeight: document.body.clientHeight - 240, // 列表最大高度(适用于列表列太多,不方便水平滑动时,需添加max-height)
36b711 193       showSearch: true, // 是否显示搜索区
7f89d0 194       keyWord: '', // 搜索区字段,可自行扩展其余字段
36b711 195
7f89d0 196       // TODO
C 197       objectName: 'xx', // 对象名称,用于删除提示、启用提示、弹窗标题等
198
199       // 数据列表
36b711 200       list: [],
L 201
202       // 弹窗数据
203       dialogVisible: false,
204       dialogData: {},
7f89d0 205
C 206       // 富文本编辑器
207       // rangenum: null,
36b711 208
L 209       // 分页 ↓↓↓↓↓↓↓↓↓↓
210       total: 0,
211       pageNum: 1,
212       pageSize: 20,
213       // 分页 ↑↑↑↑↑↑↑↑↑↑
214
215       // 表单校验
216       rules: {
217         name: [
218           { required: true, message: '名称不能为空', trigger: 'change' }
219         ],
220         isUp: [
221           { required: true, message: '是否上架不能为空', trigger: 'change' }
eaaa5b 222         ],
L 223         uploadImgs: [
224           { required: true, message: '图片不能为空' }
36b711 225         ]
L 226       }
227     }
228   },
229   mounted() {
230     this.init()
231   },
232   methods: {
233     // 初始化
234     init() {
235       this.getList()
236     },
237
7f89d0 238     // ========== 富文本相关
C 239     // 富文本编辑器的内容赋值
240     // catchData(content) {
241     //   if (content === '<p><br></p>') content = ''
242     //   try {
243     //     const currentRange = window.getSelection().getRangeAt(0)
244     //     this.rangenum = currentRange
245     //   } catch (e) {
246     //
247     //   }
248     //   this.$set(this.dialogData, 'content', content)
249     //   this.$refs[this.formName].validateField('content')
250     // },
251     // ========== 富文本相关
252
36b711 253     // 获取列表
L 254     getList() {
255       var { pageNum, pageSize, keyWord } = this
256       this.postFN({
7f89d0 257         // TODO url
36b711 258         url: 'xxx',
L 259         params: {
260           pageNum: pageNum,
261           pageSize: pageSize,
262           keyWord: keyWord
263         },
264         mockData: {
265           code: 100,
266           msg: '',
267           data: {
268             list: [{
269               id: 'xxx',
270               index: 1,
271               name: '超级管理员',
1dcdda 272               createTime: '2020-08-09 10:10:10',
L 273               adviceInfo: '啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦'
36b711 274             }],
L 275             total: 100
276           }
277         }
278       }, (inf) => {
7f89d0 279         // 测试用
36b711 280         for (var i = 0; i < 19; i++) {
L 281           inf.list.push({
282             id: 'xxx',
283             index: 1,
284             name: '超级管理员',
285             createTime: '2020-08-09 10:10:10'
286           })
287         }
288         this.list = inf.list || []
289         this.total = inf.total
290       })
291     },
292     // 重新获取列表
293     reGetList() {
294       this.pageNum = 1
295       this.getList()
296     },
297     // 重置
298     resetHandle() {
299       this.keyWord = ''
300       this.reGetList()
301     },
302     // 删除
303     handleDelete(item) {
304       // 打开二次确认弹窗
305       this.$confirm('是否确认删除该角色?', '提示', {
306         confirmButtonText: '确定',
307         cancelButtonText: '取消',
308         type: 'warning'
309       }).then(() => {
310         // 确定回调
7f89d0 311         // TODO url
36b711 312         this.postFN({
L 313           url: 'xxx',
314           params: {
315             id: item.id
316           },
317           mockData: {
318             code: 100,
319             msg: '',
320             data: {}
321           }
322         }, () => {
323           this.getList()
324           this.$messageSuc('删除成功')
325         })
326       }).catch(() => {})
327     },
328     // 修改是否上架 todo
329     handleUpChange(item) {
330       const text = item.isUp === 1 ? '上架' : '下架'
331       this.$confirm('确认要' + text + '该角色吗?', '提示', {
332         confirmButtonText: '确定',
333         cancelButtonText: '取消',
334         type: 'warning'
335       }).then(() => {
336         this.postFN({
337           url: 'xxx',
7f89d0 338           // TODO url
36b711 339           params: {
9f3f35 340             id: item.id,
L 341             isUp: item.isUp
36b711 342           },
L 343           mockData: {
344             code: 100,
345             msg: '',
346             data: {}
347           }
348         }, () => {
349           this.$messageSuc(text + '成功')
4dde14 350         }, (res) => {
L 351           item.isUp = item.isUp === 1 ? 0 : 1
352           this.$messageError(res.msg)
36b711 353         })
L 354       }).catch(() => {
355         item.isUp = item.isUp === 1 ? 0 : 1
356       })
357     },
358
359     // 打开新增弹窗
360     showAddDialog() {
361       var dialogData = {
362         type: 'add',
363         isUp: 1
364       }
365       this.dialogVisible = true
366       this.$nextTick(() => {
367         this.dialogData = dialogData
368         this.$refs['refDialog'].resetFields()
369       })
370     },
371     // 打开编辑弹框
372     showEditDialog(item) {
373       var dialogData = {
374         type: 'edit',
375         ...item
376       }
eaaa5b 377       dialogData.uploadImgs = [{ url: item.imgUrl, status: 'success' }]
L 378
36b711 379       console.log('dialogData', dialogData)
L 380       this.dialogVisible = true
381       this.$nextTick(() => {
382         this.dialogData = dialogData
383         this.$refs['refDialog'].resetFields()
384       })
385     },
386     // 关闭编辑弹窗
387     hideDialog() {
388       this.dialogData = {}
389       this.dialogVisible = false
7f89d0 390       // 清空富文本
C 391       // this.rangenum = null
36b711 392     },
L 393     // 提交新增&编辑
394     submitHandle() {
395       this.$refs['refDialog'].validate(valid => {
396         if (valid) {
eaaa5b 397           this.$refs.refUploadImg.runUploadImg((imgUrl) => {
L 398             imgUrl && this.$set(this.dialogData, 'imgUrl', imgUrl)
399             this.submitReq()
400           })
36b711 401         }
L 402       })
403     },
404     // 提交接口
405     submitReq() {
406       var { dialogData } = this
407       var params = {
408         name: dialogData.name,
eaaa5b 409         isUp: dialogData.isUp,
L 410         imgUrl: dialogData.imgUrl
36b711 411       }
L 412
413       if (dialogData.password) params.password = dialogData.password
414
415       var isAdd = dialogData.type === 'add'
7f89d0 416       // TODO url
C 417       var url = isAdd ? 'xxx/add' : 'xxx/edit'
36b711 418
L 419       !isAdd && (params.id = dialogData.id)
420
421       this.postFN({
422         url: url,
423         params: params,
424         mockData: {
425           code: 100,
426           msg: '',
427           data: {}
428         }
429       }, () => {
430         this.$messageSuc('保存成功')
431         this.hideDialog()
b82c1e 432         isAdd ? this.reGetList() : this.getList()
36b711 433       })
eaaa5b 434     },
L 435
436     // 导出列表
437     exportList() {
438       var { keyWord } = this
439       const params = {
440         keyWord: keyWord
441       }
442       this.postFN({
443         url: 'xxxx',
444         params,
445         mockData: {
446           code: 100,
447           msg: '',
448           data: {
449             path: 'xxx'
450           }
451         }
452       }, (inf) => {
453         window.location.href = inf.path
454       })
455     },
456
457     // 清空file
458     clearFile() {
459       this.$refs.upload.value = ''
460     },
461     // 导入
462     fileChange(e) {
463       const file = e.target.files[0]
464       if (!file) {
465         this.clearFile()
466         return
467       }
468
469       // 1. 判断文件类型
470       if (!/\.(xls|xlsx)$/.test(e.target.value)) {
471         this.$messageError('请选择xls或xlsx格式文件')
472         this.clearFile()
473         return
474       }
475
476       // 2. 上传
477       const formData = new FormData()
478       formData.append('file', file)
479       formData.append('virtualPrizeId', this.id)
480       this.postFN({
481         url: 'admin/virtualPrizeItem/importData',
482         header: { 'Content-Type': 'multipart/form-data' },
483         params: formData,
484         mockData: {
485           code: 100,
486           msg: '',
487           data: {}
488         }
489       }, (inf) => {
490         // 部分不成功
491         if (inf && inf.arr && inf.arr.length) {
492           inf.arr.forEach((o) => {
493             this.$messageError(o)
494           })
495         } else {
496           this.$messageSuc('导入成功')
497         }
498         this.clearFile()
499         this.reGetList() // 刷新
500       }, (res) => {
501         this.$messageError('导入失败:' + (res.msg || '未知原因'))
502         this.clearFile()
503         this.reGetList() // 刷新
504       })
36b711 505     }
L 506   }
507 }
508 </script>
509
510 <style lang="scss" scoped>
eaaa5b 511 #upload{
L 512   position: absolute;
513   top: 0;
514   left: 0;
515   width: 100%;
516   height: 100%;
517   opacity: 0;
518   z-index: 1;
519   cursor: pointer;
520   -webkit-appearance: none;
521   appearance: none;
522 }
523 .rel{
524   position: relative;
525   cursor: pointer;
526 }
36b711 527 </style>