ソースを参照

修改通知公示,以及富文本

余思翰 11ヶ月前
コミット
b487664079
2個のファイルの変更248行の追加20行の削除
  1. 188
    1
      oa-ui/src/components/Editor/index.vue
  2. 60
    19
      oa-ui/src/views/index.vue

+ 188
- 1
oa-ui/src/components/Editor/index.vue ファイルの表示

13
       v-if="this.type == 'url'"
13
       v-if="this.type == 'url'"
14
     >
14
     >
15
     </el-upload>
15
     </el-upload>
16
+    <el-upload
17
+      :action="uploadUrl"
18
+      :before-upload="handleBeforeUploadVideo"
19
+      :on-success="handleUploadSuccessVideo"
20
+      :on-error="handleUploadErrorVideo"
21
+      name="file"
22
+      :show-file-list="false"
23
+      :headers="headers"
24
+      style="display: none"
25
+      ref="uploadVideo"
26
+      v-if="this.type == 'url'"
27
+    >
28
+    </el-upload>
29
+    <el-upload
30
+      :action="uploadUrl"
31
+      :before-upload="handleBeforeUploadFile"
32
+      :on-success="handleUploadSuccessFile"
33
+      :on-error="handleUploadErrorFile"
34
+      name="file"
35
+      :show-file-list="false"
36
+      :headers="headers"
37
+      style="display: none"
38
+      ref="uploadFile"
39
+      v-if="this.type == 'url'"
40
+    >
41
+    </el-upload>
16
     <div class="editor" ref="editor" :style="styles"></div>
42
     <div class="editor" ref="editor" :style="styles"></div>
17
   </div>
43
   </div>
18
 </template>
44
 </template>
24
 import "quill/dist/quill.bubble.css";
50
 import "quill/dist/quill.bubble.css";
25
 import { getToken } from "@/utils/auth";
51
 import { getToken } from "@/utils/auth";
26
 
52
 
53
+// 源码中是import直接倒入,这里要用Quill.import引入
54
+const Link = Quill.import("formats/link");
55
+// 自定义a链接
56
+class FileBlot extends Link {
57
+   
58
+  // 继承Link Blot
59
+  static create (value) {
60
+   
61
+    let node = undefined;
62
+    if (value && !value.href) {
63
+   
64
+      // 适应原本的Link Blot
65
+      node = super.create(value)
66
+    } else {
67
+   
68
+      // 自定义Link Blot
69
+      node = super.create(value.href)
70
+      node.href = value.href
71
+      node.innerText = value.innerText
72
+      // node.setAttribute('download', value.innerText);  // 左键点击即下载
73
+    }
74
+    return node;
75
+  }
76
+}
77
+FileBlot.blotName = "link" // 这里不用改,如果需要也可以保留原来的,这里用个新的blot
78
+FileBlot.tagName = "A"
79
+Quill.register(FileBlot) // 注册link
80
+
27
 export default {
81
 export default {
28
   name: "Editor",
82
   name: "Editor",
29
   props: {
83
   props: {
49
     },
103
     },
50
     /* 上传文件大小限制(MB) */
104
     /* 上传文件大小限制(MB) */
51
     fileSize: {
105
     fileSize: {
106
+      type: Number,
107
+      default: 50,
108
+    },
109
+    /* 上传图片大小限制(MB) */
110
+    imageSize: {
52
       type: Number,
111
       type: Number,
53
       default: 5,
112
       default: 5,
54
     },
113
     },
114
+    videoSize: {
115
+      type: Number,
116
+      default: 500,
117
+    },
55
     /* 类型(base64格式、url格式) */
118
     /* 类型(base64格式、url格式) */
56
     type: {
119
     type: {
57
       type: String,
120
       type: String,
77
             ["blockquote", "code-block"],                    // 引用  代码块
140
             ["blockquote", "code-block"],                    // 引用  代码块
78
             [{ list: "ordered" }, { list: "bullet" }],       // 有序、无序列表
141
             [{ list: "ordered" }, { list: "bullet" }],       // 有序、无序列表
79
             [{ indent: "-1" }, { indent: "+1" }],            // 缩进
142
             [{ indent: "-1" }, { indent: "+1" }],            // 缩进
80
-            [{ size: ["small", false, "large", "huge"] }],   // 字体大小
143
+            [{ size: ["20px","14px","16px", "large", "huge"] }],   // 字体大小
81
             [{ header: [1, 2, 3, 4, 5, 6, false] }],         // 标题
144
             [{ header: [1, 2, 3, 4, 5, 6, false] }],         // 标题
82
             [{ color: [] }, { background: [] }],             // 字体颜色、字体背景颜色
145
             [{ color: [] }, { background: [] }],             // 字体颜色、字体背景颜色
83
             [{ align: [] }],                                 // 对齐方式
146
             [{ align: [] }],                                 // 对齐方式
123
   },
186
   },
124
   methods: {
187
   methods: {
125
     init() {
188
     init() {
189
+      debugger
126
       const editor = this.$refs.editor;
190
       const editor = this.$refs.editor;
127
       this.Quill = new Quill(editor, this.options);
191
       this.Quill = new Quill(editor, this.options);
192
+      var Size = Quill.import("formats/size");
193
+      Size.whitelist = ["14px","16px", "large","20px", "huge"];
128
       // 如果设置了上传地址则自定义图片上传事件
194
       // 如果设置了上传地址则自定义图片上传事件
129
       if (this.type == 'url') {
195
       if (this.type == 'url') {
130
         let toolbar = this.Quill.getModule("toolbar");
196
         let toolbar = this.Quill.getModule("toolbar");
135
             this.quill.format("image", false);
201
             this.quill.format("image", false);
136
           }
202
           }
137
         });
203
         });
204
+        toolbar.addHandler("video", (value) => {
205
+          if (value) {
206
+            this.$refs.uploadVideo.$children[0].$refs.input.click();
207
+          } else {
208
+            this.quill.format("video", false);
209
+          }
210
+        });
211
+        toolbar.addHandler("link", (value) => {
212
+          if (value) {
213
+            this.$refs.uploadFile.$children[0].$refs.input.click();
214
+          } else {
215
+            this.quill.format("link", false);
216
+          }
217
+        });
138
       }
218
       }
139
       this.Quill.pasteHTML(this.currentValue);
219
       this.Quill.pasteHTML(this.currentValue);
140
       this.Quill.on("text-change", (delta, oldDelta, source) => {
220
       this.Quill.on("text-change", (delta, oldDelta, source) => {
164
         this.$message.error(`图片格式错误!`);
244
         this.$message.error(`图片格式错误!`);
165
         return false;
245
         return false;
166
       }
246
       }
247
+      // 校检文件大小
248
+      if (this.imageSize) {
249
+        const isLt = file.size / 1024 / 1024 < this.imageSize;
250
+        if (!isLt) {
251
+          this.$message.error(`上传文件大小不能超过 ${this.imageSize} MB!`);
252
+          return false;
253
+        }
254
+      }
255
+      return true;
256
+    },
257
+    handleBeforeUploadVideo(file) {
258
+      const type = ["video/mp4"];
259
+      const isVideo = type.includes(file.type);
260
+      // 检验文件格式
261
+      if (!isVideo) {
262
+        this.$message.error(`视频格式错误!`);
263
+        return false;
264
+      }
265
+      // 校检文件大小
266
+      if (this.videoSize) {
267
+        const isLt = file.size / 1024 / 1024 < this.videoSize;
268
+        if (!isLt) {
269
+          this.$message.error(`上传文件大小不能超过 ${this.videoSize} MB!`);
270
+          return false;
271
+        }
272
+      }
273
+      return true;
274
+    },
275
+    // 上传前校检格式和大小
276
+    handleBeforeUploadFile(file) {
167
       // 校检文件大小
277
       // 校检文件大小
168
       if (this.fileSize) {
278
       if (this.fileSize) {
169
         const isLt = file.size / 1024 / 1024 < this.fileSize;
279
         const isLt = file.size / 1024 / 1024 < this.fileSize;
175
       return true;
285
       return true;
176
     },
286
     },
177
     handleUploadSuccess(res, file) {
287
     handleUploadSuccess(res, file) {
288
+      debugger
178
       // 如果上传成功
289
       // 如果上传成功
179
       if (res.code == 200) {
290
       if (res.code == 200) {
180
         // 获取富文本组件实例
291
         // 获取富文本组件实例
189
         this.$message.error("图片插入失败");
300
         this.$message.error("图片插入失败");
190
       }
301
       }
191
     },
302
     },
303
+    handleUploadSuccessVideo(res, file) {
304
+      // 如果上传成功
305
+      if (res.code == 200) {
306
+        // 获取富文本组件实例
307
+        let quill = this.Quill;
308
+        // 获取光标所在位置
309
+        let length = quill.getSelection().index;
310
+        // 插入图片  res.url为服务器返回的图片地址
311
+        quill.insertEmbed(length, "video", process.env.VUE_APP_BASE_API + res.fileName);
312
+        // 调整光标到最后
313
+        quill.setSelection(length + 1);
314
+      } else {
315
+        this.$message.error("视频插入失败");
316
+      }
317
+    },
318
+    handleUploadSuccessFile(res, file) {
319
+      // 如果上传成功
320
+      if (res.code == 200) {
321
+        // 获取富文本组件实例
322
+        let quill = this.Quill;
323
+        // 获取光标所在位置
324
+        let length = quill.getSelection().index;
325
+        // 插入文件  res.url为服务器返回的图片地址
326
+        quill.insertEmbed(length, "link", 
327
+          {
328
+            href: process.env.VUE_APP_BASE_API + res.fileName, 
329
+            innerText: res.originalFilename
330
+          },
331
+        );
332
+        // 调整光标到最后
333
+        quill.setSelection(length + 1);
334
+      } else {
335
+        this.$message.error("文件插入失败");
336
+      }
337
+    },
192
     handleUploadError() {
338
     handleUploadError() {
193
       this.$message.error("图片插入失败");
339
       this.$message.error("图片插入失败");
194
     },
340
     },
341
+    handleUploadErrorVideo() {
342
+      this.$message.error("视频插入失败");
343
+    },
344
+    handleUploadErrorFile() {
345
+      this.$message.error("文件插入失败");
346
+    },
195
   },
347
   },
196
 };
348
 };
197
 </script>
349
 </script>
204
 .quill-img {
356
 .quill-img {
205
   display: none;
357
   display: none;
206
 }
358
 }
359
+.ql-align-right{
360
+  text-align: right;
361
+}
362
+.ql-align-center{
363
+  text-align: center;
364
+}
207
 .ql-snow .ql-tooltip[data-mode="link"]::before {
365
 .ql-snow .ql-tooltip[data-mode="link"]::before {
208
   content: "请输入链接地址:";
366
   content: "请输入链接地址:";
209
 }
367
 }
223
 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
381
 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
224
   content: "10px";
382
   content: "10px";
225
 }
383
 }
384
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="14px"]::before,
385
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="14px"]::before {
386
+  content: "14px";
387
+}
388
+.ql-size-14px {
389
+  font-size: 14px;
390
+}
391
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before,
392
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="16px"]::before {
393
+  content: "16px";
394
+}
395
+.ql-size-16px {
396
+  font-size: 16px;
397
+}
398
+
226
 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
399
 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
227
 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
400
 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
228
   content: "18px";
401
   content: "18px";
229
 }
402
 }
403
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before,
404
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before {
405
+  content: "20px";
406
+}
407
+.ql-size-20px {
408
+  font-size: 20px;
409
+}
230
 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
410
 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
231
 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
411
 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
232
   content: "32px";
412
   content: "32px";
233
 }
413
 }
414
+
415
+
234
 .ql-snow .ql-picker.ql-header .ql-picker-label::before,
416
 .ql-snow .ql-picker.ql-header .ql-picker-label::before,
235
 .ql-snow .ql-picker.ql-header .ql-picker-item::before {
417
 .ql-snow .ql-picker.ql-header .ql-picker-item::before {
236
   content: "文本";
418
   content: "文本";
271
 .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
453
 .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
272
   content: "等宽字体";
454
   content: "等宽字体";
273
 }
455
 }
456
+.ql-video {
457
+  width: 100%;
458
+  height: 425px;
459
+}
274
 </style>
460
 </style>
461
+

+ 60
- 19
oa-ui/src/views/index.vue ファイルの表示

2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2024-01-03 09:23:11
3
  * @Date: 2024-01-03 09:23:11
4
  * @LastEditors: Please set LastEditors
4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2024-07-16 09:50:08
5
+ * @LastEditTime: 2024-07-16 15:17:54
6
 -->
6
 -->
7
 
7
 
8
 <template>
8
 <template>
59
         </div>
59
         </div>
60
       </el-col>
60
       </el-col>
61
       <el-col :span="16" :xs="24">
61
       <el-col :span="16" :xs="24">
62
-        <div class="header">公告</div>
62
+        <div class="header">通知公示</div>
63
         <div class="notice-content">
63
         <div class="notice-content">
64
-          <el-table v-loading="noticeLoading" :data="noticeList" height="320px" @row-click="handleRowClick">
64
+          <el-table v-loading="noticeLoading" :data="noticeList" height="320px">
65
             <!-- <el-table-column label="序号" align="center" prop="noticeId" width="100" /> -->
65
             <!-- <el-table-column label="序号" align="center" prop="noticeId" width="100" /> -->
66
             <el-table-column label="公告类型" align="center" prop="noticeType" width="100">
66
             <el-table-column label="公告类型" align="center" prop="noticeType" width="100">
67
               <template slot-scope="scope">
67
               <template slot-scope="scope">
75
                 <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
75
                 <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
76
               </template>
76
               </template>
77
             </el-table-column>
77
             </el-table-column>
78
+            <el-table-column label="操作" width="90" align="center">
79
+              <template slot-scope="scope">
80
+                <el-button size="mini" type="text" icon="el-icon-view"
81
+                  @click="handleRowClick(scope.row)">查看详情</el-button>
82
+              </template>
83
+            </el-table-column>
78
           </el-table>
84
           </el-table>
79
           <div style="text-align: right;margin-top: 20px;">
85
           <div style="text-align: right;margin-top: 20px;">
80
             <el-pagination @current-change="getNotice" :current-page.sync="noticeQueryParams.pageNum"
86
             <el-pagination @current-change="getNotice" :current-page.sync="noticeQueryParams.pageNum"
92
       </el-col> -->
98
       </el-col> -->
93
     </el-row>
99
     </el-row>
94
 
100
 
95
-    <el-dialog title="" :visible.sync="noticeOpen" width="65%" append-to-body>
101
+    <el-dialog title="" :visible.sync="noticeOpen" width="750px" append-to-body>
96
       <h2 class="text-center">{{ clickNotice.noticeTitle }}</h2>
102
       <h2 class="text-center">{{ clickNotice.noticeTitle }}</h2>
97
-      <div v-html="clickNotice.noticeContent"></div>
103
+      <div class="pre-formatted" v-html="clickNotice.noticeContent"></div>
98
     </el-dialog>
104
     </el-dialog>
99
   </div>
105
   </div>
100
 </template>
106
 </template>
123
   },
129
   },
124
   data() {
130
   data() {
125
     return {
131
     return {
126
-      noticeOpen:false,
132
+      noticeOpen: false,
127
       times: new Date(),
133
       times: new Date(),
128
       user: {
134
       user: {
129
         dept: {}
135
         dept: {}
133
       projectData: [],
139
       projectData: [],
134
       noticeList: [],// 公告表格数据
140
       noticeList: [],// 公告表格数据
135
       noticeTotal: 0,
141
       noticeTotal: 0,
136
-      clickNotice:{},
142
+      clickNotice: {},
137
       noticeLoading: true,
143
       noticeLoading: true,
138
       noticeQueryParams: {
144
       noticeQueryParams: {
139
         pageNum: 1,
145
         pageNum: 1,
156
           bgColor: '#785aee',
162
           bgColor: '#785aee',
157
           boxShadow: '0 5px 20px rgba(120,90,238,0.5)',
163
           boxShadow: '0 5px 20px rgba(120,90,238,0.5)',
158
           path: '/task/process',
164
           path: '/task/process',
159
-          privilege:['system:deployment:add']
165
+          privilege: ['system:deployment:add']
160
         }, {
166
         }, {
161
           id: 2,
167
           id: 2,
162
           name: '待办任务',
168
           name: '待办任务',
164
           bgColor: '#e66794',
170
           bgColor: '#e66794',
165
           boxShadow: '0 5px 20px rgba(230,103,148,0.5)',
171
           boxShadow: '0 5px 20px rgba(230,103,148,0.5)',
166
           path: '/task/todo',
172
           path: '/task/todo',
167
-          privilege:['system:deployment:add']
173
+          privilege: ['system:deployment:add']
168
         }, {
174
         }, {
169
           id: 3,
175
           id: 3,
170
           name: '已办任务',
176
           name: '已办任务',
172
           bgColor: '#6389f4',
178
           bgColor: '#6389f4',
173
           boxShadow: '0 5px 20px rgba(99,137,244,0.5)',
179
           boxShadow: '0 5px 20px rgba(99,137,244,0.5)',
174
           path: '/task/finished',
180
           path: '/task/finished',
175
-          privilege:['system:deployment:add']
181
+          privilege: ['system:deployment:add']
176
         }, {
182
         }, {
177
           id: 4,
183
           id: 4,
178
           name: '项目台账',
184
           name: '项目台账',
180
           bgColor: '#e64c56',
186
           bgColor: '#e64c56',
181
           boxShadow: '0 5px 20px rgba(230,76,86,0.5)',
187
           boxShadow: '0 5px 20px rgba(230,76,86,0.5)',
182
           path: '/product/account/project',
188
           path: '/product/account/project',
183
-          privilege:['oa:project:query']
189
+          privilege: ['oa:project:query']
184
         }, {
190
         }, {
185
           id: 5,
191
           id: 5,
186
           name: '车辆管理',
192
           name: '车辆管理',
188
           bgColor: '#eeb62f',
194
           bgColor: '#eeb62f',
189
           boxShadow: '0 5px 20px rgba(238,182,47,0.5)',
195
           boxShadow: '0 5px 20px rgba(238,182,47,0.5)',
190
           path: '/oa/car/index',
196
           path: '/oa/car/index',
191
-          privilege:['oa:car:list']
197
+          privilege: ['oa:car:list']
192
         }, {
198
         }, {
193
           id: 6,
199
           id: 6,
194
           name: '设备管理',
200
           name: '设备管理',
196
           bgColor: '#0be1bd',
202
           bgColor: '#0be1bd',
197
           boxShadow: '0 5px 20px rgba(11,225,189,0.5)',
203
           boxShadow: '0 5px 20px rgba(11,225,189,0.5)',
198
           path: '/oa/device/equipment',
204
           path: '/oa/device/equipment',
199
-          privilege:['oa:device:list']
205
+          privilege: ['oa:device:list']
200
         }, {
206
         }, {
201
           id: 7,
207
           id: 7,
202
           name: '投标管理',
208
           name: '投标管理',
204
           bgColor: '#F7C59F',
210
           bgColor: '#F7C59F',
205
           boxShadow: '0 5px 20px rgba(247,197,159,0.5)',
211
           boxShadow: '0 5px 20px rgba(247,197,159,0.5)',
206
           path: '/business/tender',
212
           path: '/business/tender',
207
-          privilege:['oa:tender:query']
213
+          privilege: ['oa:tender:query']
208
         }, {
214
         }, {
209
           id: 8,
215
           id: 8,
210
           name: '人事管理',
216
           name: '人事管理',
212
           bgColor: '#20B2AA',
218
           bgColor: '#20B2AA',
213
           boxShadow: '0 5px 20px rgba(32,178,170,0.5)',
219
           boxShadow: '0 5px 20px rgba(32,178,170,0.5)',
214
           path: '/oa/staff/people',
220
           path: '/oa/staff/people',
215
-          privilege:['oa:salary:list']
216
-        }, 
221
+          privilege: ['oa:salary:list']
222
+        },
217
         // {
223
         // {
218
         //   id: 9,
224
         //   id: 9,
219
         //   name: '预算管理',
225
         //   name: '预算管理',
300
         return null
306
         return null
301
       }
307
       }
302
     },
308
     },
303
-    handleRowClick(row){
304
-      console.log(row);
309
+    handleRowClick(row) {
305
       this.clickNotice = row;
310
       this.clickNotice = row;
311
+      this.clickNotice.noticeContent = this.format(row.noticeContent);
306
       this.noticeOpen = true;
312
       this.noticeOpen = true;
313
+    },
314
+    format(html) {
315
+      var GRT = [
316
+        // img 样式
317
+        ['img', "max-width:100%;height:auto;"],
318
+      ];
319
+      for (let i = 0; i < GRT.length; i++) {
320
+        html = html.replace(new RegExp('<' + GRT[i][0] + '>|<' + GRT[i][0] + ' (.*?)>', 'gi'), function (word) {
321
+          // 分析 dom 上是否带有 style=""
322
+          if (word.indexOf('style=') != -1) {
323
+            var regIn = new RegExp('<' + GRT[i][0] + '(.*?)style="(.*?)"(.*?)(/?)>', 'gi');
324
+            return word.replace(regIn, '<' + GRT[i][0] + '$1style="$2 ' + GRT[i][1] + '"$3$4>');
325
+          } else {
326
+            var regIn = new RegExp('<' + GRT[i][0] + '(.*?)(/?)>', 'gi');
327
+            return word.replace(regIn, '<' + GRT[i][0] + '$1 style="' + GRT[i][1] + '$2">');
328
+          }
329
+        });
330
+      }
331
+      return html;
307
     }
332
     }
308
   }
333
   }
309
 }
334
 }
310
 </script>
335
 </script>
311
-
312
 <style scoped lang="scss">
336
 <style scoped lang="scss">
313
 .home {
337
 .home {
314
   padding: 20px 40px;
338
   padding: 20px 40px;
419
   border-radius: 15px;
443
   border-radius: 15px;
420
 }
444
 }
421
 
445
 
446
+.pre-formatted {
447
+  white-space: pre-wrap;
448
+  /* css-2.1, curent FF, Opera, Safari */
449
+  word-wrap: break-word;
450
+
451
+  /* Internet Explorer 5.5+ */
452
+  p {
453
+    width: 100% !important;
454
+    height: 100% !important;
455
+
456
+    img {
457
+      width: 100%;
458
+      height: 100%;
459
+    }
460
+  }
461
+}
462
+
422
 ::v-deep .el-calendar-table .el-calendar-day {
463
 ::v-deep .el-calendar-table .el-calendar-day {
423
   height: 39px;
464
   height: 39px;
424
   text-align: center;
465
   text-align: center;

読み込み中…
キャンセル
保存