Commit 5a1d02dffdea63bc9b38bcf334f2dd9889db0dd3

Authored by YunaiV
1 parent d1cbe0c3

mp:素材管理,增加【图片】

yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/ErrorCodeConstants.java
... ... @@ -32,8 +32,10 @@ public interface ErrorCodeConstants {
32 32 ErrorCode USER_UPDATE_TAG_FAIL = new ErrorCode(1006003001, "更新用户标签失败,原因:{}");
33 33  
34 34 // ========== 公众号素材 1006004000============
35   - ErrorCode MATERIAL_UPLOAD_FAIL = new ErrorCode(1006004000, "上传素材失败,原因:{}");
36   - ErrorCode MATERIAL_IMAGE_UPLOAD_FAIL = new ErrorCode(1006004000, "上传图片失败,原因:{}");
  35 + ErrorCode MATERIAL_NOT_EXISTS = new ErrorCode(1006004000, "素材不存在");
  36 + ErrorCode MATERIAL_UPLOAD_FAIL = new ErrorCode(1006004001, "上传素材失败,原因:{}");
  37 + ErrorCode MATERIAL_IMAGE_UPLOAD_FAIL = new ErrorCode(1006004002, "上传图片失败,原因:{}");
  38 + ErrorCode MATERIAL_DELETE_FAIL = new ErrorCode(1006004003, "删除素材失败,原因:{}");
37 39  
38 40 // ========== 公众号消息 1006005000============
39 41 ErrorCode MESSAGE_SEND_FAIL = new ErrorCode(1006005000, "发送消息失败,原因:{}");
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/MpMaterialController.java
... ... @@ -7,12 +7,11 @@ import cn.iocoder.yudao.module.mp.convert.material.MpMaterialConvert;
7 7 import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO;
8 8 import cn.iocoder.yudao.module.mp.service.material.MpMaterialService;
9 9 import io.swagger.annotations.Api;
  10 +import io.swagger.annotations.ApiImplicitParam;
10 11 import io.swagger.annotations.ApiOperation;
  12 +import org.springframework.security.access.prepost.PreAuthorize;
11 13 import org.springframework.validation.annotation.Validated;
12   -import org.springframework.web.bind.annotation.GetMapping;
13   -import org.springframework.web.bind.annotation.PostMapping;
14   -import org.springframework.web.bind.annotation.RequestMapping;
15   -import org.springframework.web.bind.annotation.RestController;
  14 +import org.springframework.web.bind.annotation.*;
16 15  
17 16 import javax.annotation.Resource;
18 17 import javax.validation.Valid;
... ... @@ -20,8 +19,6 @@ import java.io.IOException;
20 19  
21 20 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
22 21  
23   -// TODO @芋艿:权限
24   -
25 22 @Api(tags = "管理后台 - 公众号素材")
26 23 @RestController
27 24 @RequestMapping("/mp/material")
... ... @@ -33,6 +30,7 @@ public class MpMaterialController {
33 30  
34 31 @ApiOperation("上传临时素材")
35 32 @PostMapping("/upload-temporary")
  33 + @PreAuthorize("@ss.hasPermission('mp:material:upload-temporary')")
36 34 public CommonResult<MpMaterialUploadRespVO> uploadTemporaryMaterial(
37 35 @Valid MpMaterialUploadTemporaryReqVO reqVO) throws IOException {
38 36 MpMaterialDO material = mpMaterialService.uploadTemporaryMaterial(reqVO);
... ... @@ -41,14 +39,25 @@ public class MpMaterialController {
41 39  
42 40 @ApiOperation("上传永久素材")
43 41 @PostMapping("/upload-permanent")
  42 + @PreAuthorize("@ss.hasPermission('mp:material:upload-permanent')")
44 43 public CommonResult<MpMaterialUploadRespVO> uploadPermanentMaterial(
45 44 @Valid MpMaterialUploadPermanentReqVO reqVO) throws IOException {
46 45 MpMaterialDO material = mpMaterialService.uploadPermanentMaterial(reqVO);
47 46 return success(MpMaterialConvert.INSTANCE.convert(material));
48 47 }
49 48  
  49 + @ApiOperation("删除素材")
  50 + @DeleteMapping("/delete-permanent")
  51 + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
  52 + @PreAuthorize("@ss.hasPermission('mp:material:delete')")
  53 + public CommonResult<Boolean> deleteMaterial(@RequestParam("id") Long id) {
  54 + mpMaterialService.deleteMaterial(id);
  55 + return success(true);
  56 + }
  57 +
50 58 @ApiOperation("上传图文内容中的图片")
51 59 @PostMapping("/upload-news-image")
  60 + @PreAuthorize("@ss.hasPermission('mp:material:upload-news-image')")
52 61 public CommonResult<String> uploadNewsImage(@Valid MpMaterialUploadNewsImageReqVO reqVO)
53 62 throws IOException {
54 63 return success(mpMaterialService.uploadNewsImage(reqVO));
... ... @@ -56,10 +65,10 @@ public class MpMaterialController {
56 65  
57 66 @ApiOperation("获得素材分页")
58 67 @GetMapping("/page")
  68 + @PreAuthorize("@ss.hasPermission('mp:material:query')")
59 69 public CommonResult<PageResult<MpMaterialRespVO>> getMaterialPage(@Valid MpMaterialPageReqVO pageReqVO) {
60 70 PageResult<MpMaterialDO> pageResult = mpMaterialService.getMaterialPage(pageReqVO);
61 71 return success(MpMaterialConvert.INSTANCE.convertPage(pageResult));
62 72 }
63 73  
64   -
65 74 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/material/MpMaterialMapper.java
... ... @@ -22,7 +22,8 @@ public interface MpMaterialMapper extends BaseMapperX&lt;MpMaterialDO&gt; {
22 22 return selectPage(pageReqVO, new LambdaQueryWrapperX<MpMaterialDO>()
23 23 .eq(MpMaterialDO::getAccountId, pageReqVO.getAccountId())
24 24 .eqIfPresent(MpMaterialDO::getPermanent, pageReqVO.getPermanent())
25   - .eqIfPresent(MpMaterialDO::getType, pageReqVO.getType()));
  25 + .eqIfPresent(MpMaterialDO::getType, pageReqVO.getType())
  26 + .orderByDesc(MpMaterialDO::getId));
26 27 }
27 28  
28 29 default List<MpMaterialDO> selectListByMediaId(Collection<String> mediaIds) {
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/material/MpMaterialService.java
... ... @@ -74,4 +74,11 @@ public interface MpMaterialService {
74 74 */
75 75 List<MpMaterialDO> getMaterialListByMediaId(Collection<String> mediaIds);
76 76  
  77 + /**
  78 + * 删除素材
  79 + *
  80 + * @param id 编号
  81 + */
  82 + void deleteMaterial(Long id);
  83 +
77 84 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/material/MpMaterialServiceImpl.java
... ... @@ -32,8 +32,7 @@ import java.util.Collection;
32 32 import java.util.List;
33 33  
34 34 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
35   -import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.MATERIAL_IMAGE_UPLOAD_FAIL;
36   -import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.MATERIAL_UPLOAD_FAIL;
  35 +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.*;
37 36  
38 37 /**
39 38 * 公众号素材 Service 接口
... ... @@ -172,6 +171,27 @@ public class MpMaterialServiceImpl implements MpMaterialService {
172 171 return mpMaterialMapper.selectListByMediaId(mediaIds);
173 172 }
174 173  
  174 + @Override
  175 + public void deleteMaterial(Long id) {
  176 + MpMaterialDO material = mpMaterialMapper.selectById(id);
  177 + if (material == null) {
  178 + throw exception(MATERIAL_NOT_EXISTS);
  179 + }
  180 +
  181 + // 第一步,从公众号删除
  182 + if (material.getPermanent()) {
  183 + WxMpService mpService = mpServiceFactory.getRequiredMpService(material.getAppId());
  184 + try {
  185 + mpService.getMaterialService().materialDelete(material.getMediaId());
  186 + } catch (WxErrorException e) {
  187 + throw exception(MATERIAL_DELETE_FAIL, e.getError().getErrorMsg());
  188 + }
  189 + }
  190 +
  191 + // 第二步,从数据库中删除
  192 + mpMaterialMapper.deleteById(id);
  193 + }
  194 +
175 195 /**
176 196 * 下载微信媒体文件的内容,并上传到文件服务
177 197 *
... ...
yudao-ui-admin/src/api/mp/material.js
... ... @@ -8,3 +8,11 @@ export function getMaterialPage(query) {
8 8 params: query
9 9 })
10 10 }
  11 +
  12 +// 删除公众号永久素材
  13 +export function deletePermanentMaterial(id) {
  14 + return request({
  15 + url: '/mp/material/delete-permanent?id=' + id,
  16 + method: 'delete'
  17 + })
  18 +}
... ...
yudao-ui-admin/src/views/mp/components/wx-material-select/main.vue
... ... @@ -19,9 +19,6 @@
19 19 </div>
20 20 </div>
21 21 <!-- 分页组件 -->
22   - <div v-if="list.length <= 0 && !loading" class="el-table__empty-block">
23   - <span class="el-table__empty-text">暂无数据</span>
24   - </div>
25 22 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
26 23 @pagination="getMaterialPage"/>
27 24 </div>
... ... @@ -92,9 +89,6 @@
92 89 </div>
93 90 </div>
94 91 <!-- 分页组件 -->
95   - <div v-if="list.length <= 0 && !loading" class="el-table__empty-block">
96   - <span class="el-table__empty-text">暂无数据</span>
97   - </div>
98 92 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
99 93 @pagination="getMaterialPage"/>
100 94 </div>
... ...
yudao-ui-admin/src/views/mp/components/wx-reply/main.vue
... ... @@ -235,7 +235,7 @@
235 235 "title":'',
236 236 "introduction":''
237 237 },
238   - actionUrl: process.env.VUE_APP_BASE_API +'/admin-api/mp/material/upload-temporary',
  238 + actionUrl: process.env.VUE_APP_BASE_API + '/admin-api/mp/material/upload-temporary',
239 239 headers: { Authorization: "Bearer " + getAccessToken() }, // 设置上传的请求头部
240 240 }
241 241 },
... ... @@ -279,7 +279,7 @@
279 279 this.uploadData.accountId = this.objData.accountId;
280 280 return true;
281 281 },
282   - beforeImageUpload(file){
  282 + beforeImageUpload(file) {
283 283 // 校验格式
284 284 const isType = file.type === 'image/jpeg'
285 285 || file.type === 'image/png'
... ...
yudao-ui-admin/src/views/mp/draft/index.vue
... ... @@ -64,9 +64,6 @@ SOFTWARE.
64 64 </div>
65 65 </div>
66 66 <!-- 分页记录 -->
67   - <div v-if="list.length <= 0 && !loading" class="el-table__empty-block">
68   - <span class="el-table__empty-text">暂无数据</span>
69   - </div>
70 67 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
71 68 @pagination="getList"/>
72 69  
... ... @@ -218,7 +215,6 @@ export default {
218 215 this.accounts = response.data;
219 216 // 默认选中第一个
220 217 if (this.accounts.length > 0) {
221   - this.queryParams.accountId = this.accounts[0].id;
222 218 this.setAccountId(this.accounts[0].id);
223 219 }
224 220 // 加载数据
... ... @@ -241,7 +237,7 @@ export default {
241 237 }
242 238  
243 239 this.loading = true
244   - getDraftPage((this.queryParams)).then(response => {
  240 + getDraftPage(this.queryParams).then(response => {
245 241 // 将 thumbUrl 转成 picUrl,保证 wx-news 组件可以预览封面
246 242 response.data.list.forEach(item => {
247 243 const newsItem = item.content.newsItem;
... ...
yudao-ui-admin/src/views/mp/freePublish/index.vue
... ... @@ -51,9 +51,6 @@ SOFTWARE.
51 51 </div>
52 52 </div>
53 53 <!-- 分页组件 -->
54   - <div v-if="list.length <=0 && !loading" class="el-table__empty-block">
55   - <span class="el-table__empty-text">暂无数据</span>
56   - </div>
57 54 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
58 55 @pagination="getList"/>
59 56 </div>
... ...
yudao-ui-admin/src/views/mp/material/index.vue 0 → 100644
  1 +<!--
  2 +MIT License
  3 +
  4 +Copyright (c) 2020 www.joolun.com
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy
  7 +of this software and associated documentation files (the "Software"), to deal
  8 +in the Software without restriction, including without limitation the rights
  9 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 +copies of the Software, and to permit persons to whom the Software is
  11 +furnished to do so, subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22 +SOFTWARE.
  23 +-->
  24 +<template>
  25 + <div class="app-container">
  26 + <!-- 搜索工作栏 -->
  27 + <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
  28 + <el-form-item label="公众号" prop="accountId">
  29 + <el-select v-model="queryParams.accountId" placeholder="请选择公众号">
  30 + <el-option v-for="item in accounts" :key="parseInt(item.id)" :label="item.name" :value="parseInt(item.id)" />
  31 + </el-select>
  32 + </el-form-item>
  33 + <el-form-item>
  34 + <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
  35 + <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
  36 + </el-form-item>
  37 + </el-form>
  38 +
  39 + <el-tabs v-model="type" @tab-click="handleClick">
  40 + <!-- tab 1:图片 -->
  41 + <el-tab-pane name="image">
  42 + <span slot="label"><i class="el-icon-picture"></i> 图片</span>
  43 + <div class="add_but" v-hasPermi="['mp:material:upload-permanent']">
  44 + <el-upload :action="actionUrl" :headers="headers" multiple :limit="1" :file-list="fileList" :data="uploadData"
  45 + :before-upload="beforeImageUpload" :on-success="handleUploadSuccess">
  46 + <el-button size="mini" type="primary">点击上传</el-button>
  47 + <sapn slot="tip" class="el-upload__tip" style="margin-left: 5px">支持 bmp/png/jpeg/jpg/gif 格式,大小不超过 2M</sapn>
  48 + </el-upload>
  49 + </div>
  50 + <div class="waterfall" v-loading="loading">
  51 + <div class="waterfall-item" v-for="item in list" :key='item.id'>
  52 + <a target="_blank" :href="item.url">
  53 + <img class="material-img" :src="item.url">
  54 + <div class="item-name">{{item.name}}</div>
  55 + </a>
  56 + <el-row class="ope-row">
  57 + <el-button type="danger" icon="el-icon-delete" circle @click="handleDelete(item)"
  58 + v-hasPermi="['mp:material:delete']"/>
  59 + </el-row>
  60 + </div>
  61 + </div>
  62 + <!-- 分页组件 -->
  63 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  64 + @pagination="getList"/>
  65 + </el-tab-pane>
  66 + <el-tab-pane name="voice">
  67 + <span slot="label"><i class="el-icon-microphone"></i> 语音</span>
  68 + <div class="add_but">
  69 + <el-upload
  70 + :action="actionUrl"
  71 + :headers="headers"
  72 + multiple
  73 + :limit="1"
  74 + :on-success="handleUploadSuccess"
  75 + :file-list="fileList"
  76 + :before-upload="beforeVoiceUpload"
  77 + :data="uploadData">
  78 + <el-button size="mini" type="primary">点击上传</el-button>
  79 + <div slot="tip" class="el-upload__tip">
  80 + 格式支持mp3/wma/wav/amr,文件大小不超过2M,播放长度不超过60s
  81 + </div>
  82 + </el-upload>
  83 + </div>
  84 + <el-table
  85 + :data="list"
  86 + stripe
  87 + border
  88 + v-loading="loading">
  89 + <el-table-column
  90 + prop="mediaId"
  91 + label="media_id">
  92 + </el-table-column>
  93 + <el-table-column
  94 + prop="name"
  95 + label="名称">
  96 + </el-table-column>
  97 + <el-table-column
  98 + prop="updateTime"
  99 + label="更新时间">
  100 + </el-table-column>
  101 + <el-table-column
  102 + fixed="right"
  103 + label="操作">
  104 + <template slot-scope="scope">
  105 + <el-button type="text"
  106 + icon="el-icon-download"
  107 + size="small"
  108 + plain
  109 + @click="handleDown(scope.row)">下载</el-button>
  110 + <el-button type="text"
  111 + icon="el-icon-delete"
  112 + size="small"
  113 + plain
  114 + @click="handleDelete(scope.row)">删除</el-button>
  115 + </template>
  116 + </el-table-column>
  117 + </el-table>
  118 + <el-pagination
  119 + @size-change="sizeChange"
  120 + @current-change="currentChange"
  121 + :current-page.sync="queryParams.currentPage"
  122 + :page-sizes="[10, 20]"
  123 + :page-size="queryParams.pageSize"
  124 + layout="total, sizes, prev, pager, next, jumper"
  125 + :total="queryParams.total"
  126 + class="pagination"
  127 + >
  128 + </el-pagination>
  129 + </el-tab-pane>
  130 + <el-tab-pane name="video">
  131 + <span slot="label"><i class="el-icon-video-play"></i> 视频</span>
  132 + <div class="add_but">
  133 + <el-button size="mini" type="primary" @click="handleAddVideo">新建</el-button>
  134 + </div>
  135 + <el-dialog title="新建视频" :visible.sync="dialogVideoVisible" v-loading="addMaterialLoading">
  136 + <el-upload
  137 + ref="uploadVideo"
  138 + :action="actionUrl"
  139 + :headers="headers"
  140 + multiple
  141 + :limit="1"
  142 + :on-success="handleUploadSuccess"
  143 + :file-list="fileList"
  144 + :before-upload="beforeVideoUpload"
  145 + :auto-upload="false"
  146 + :data="uploadData">
  147 + <el-button slot="trigger" size="mini" type="primary">选择视频</el-button>
  148 + <div class="el-upload__tip">
  149 + 格式支持MP4,文件大小不超过10MB
  150 + </div>
  151 + </el-upload>
  152 + <el-form :model="uploadData"
  153 + :rules="uploadRules"
  154 + ref="uploadForm">
  155 + <el-form-item label="标题" prop="title">
  156 + <el-input v-model="uploadData.title" placeholder="标题将展示在相关播放页面,建议填写清晰、准确、生动的标题"></el-input>
  157 + </el-form-item>
  158 + <el-form-item label="描述" prop="introduction">
  159 + <el-input :rows="3" type="textarea" v-model="uploadData.introduction" placeholder="介绍语将展示在相关播放页面,建议填写简洁明确、有信息量的内容"></el-input>
  160 + </el-form-item>
  161 + </el-form>
  162 + <div slot="footer" class="dialog-footer">
  163 + <el-button @click="dialogVideoVisible = false">取 消</el-button>
  164 + <el-button type="primary" @click="subVideo">提 交</el-button>
  165 + </div>
  166 + </el-dialog>
  167 + <el-table
  168 + :data="list"
  169 + stripe
  170 + border
  171 + v-loading="loading">
  172 + <el-table-column
  173 + prop="mediaId"
  174 + label="media_id">
  175 + </el-table-column>
  176 + <el-table-column
  177 + prop="name"
  178 + label="名称">
  179 + </el-table-column>
  180 + <el-table-column
  181 + prop="updateTime"
  182 + label="更新时间">
  183 + </el-table-column>
  184 + <el-table-column
  185 + fixed="right"
  186 + label="操作">
  187 + <template slot-scope="scope">
  188 + <el-button type="text"
  189 + icon="el-icon-view"
  190 + size="small"
  191 + plain
  192 + @click="handleInfo(scope.row)">查看</el-button>
  193 + <el-button type="text"
  194 + icon="el-icon-delete"
  195 + size="small"
  196 + plain
  197 + @click="handleDelete(scope.row)">删除</el-button>
  198 + </template>
  199 + </el-table-column>
  200 + </el-table>
  201 + <el-pagination
  202 + @size-change="sizeChange"
  203 + @current-change="currentChange"
  204 + :current-page.sync="queryParams.currentPage"
  205 + :page-sizes="[10, 20]"
  206 + :page-size="queryParams.pageSize"
  207 + layout="total, sizes, prev, pager, next, jumper"
  208 + :total="queryParams.total"
  209 + class="pagination"
  210 + >
  211 + </el-pagination>
  212 + </el-tab-pane>
  213 + </el-tabs>
  214 + </div>
  215 +</template>
  216 +
  217 +<script>
  218 +import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue';
  219 +import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue';
  220 +import { getSimpleAccounts } from "@/api/mp/account";
  221 +import { getMaterialPage, deletePermanentMaterial } from "@/api/mp/material";
  222 +import { getAccessToken } from '@/utils/auth'
  223 +
  224 +export default {
  225 + name: 'mpMaterial',
  226 + components: {
  227 + WxVoicePlayer,
  228 + WxVideoPlayer
  229 + },
  230 + data() {
  231 + return {
  232 + type: 'image',
  233 + // 遮罩层
  234 + loading: false,
  235 + // 显示搜索条件
  236 + showSearch: true,
  237 + // 总条数
  238 + total: 0,
  239 + // 数据列表
  240 + list: [],
  241 + // 查询参数
  242 + queryParams: {
  243 + pageNo: 1,
  244 + pageSize: 10,
  245 + accountId: undefined,
  246 + },
  247 +
  248 + actionUrl: process.env.VUE_APP_BASE_API + '/admin-api/mp/material/upload-permanent',
  249 + headers: { Authorization: "Bearer " + getAccessToken() }, // 设置上传的请求头部
  250 + fileList:[],
  251 + dialogVideoVisible:false,
  252 + dialogNewsVisible:false,
  253 + addMaterialLoading:false,
  254 + uploadData: {
  255 + "type": 'image',
  256 + "title":'',
  257 + "introduction":''
  258 + },
  259 + uploadRules:{
  260 + title: [
  261 + { required: true, message: '请输入标题', trigger: 'blur' }
  262 + ],
  263 + introduction: [
  264 + { required: true, message: '请输入描述', trigger: 'blur' }
  265 + ],
  266 + },
  267 +
  268 + // 公众号账号列表
  269 + accounts: [],
  270 + }
  271 + },
  272 + created() {
  273 + getSimpleAccounts().then(response => {
  274 + this.accounts = response.data;
  275 + // 默认选中第一个
  276 + if (this.accounts.length > 0) {
  277 + this.setAccountId(this.accounts[0].id);
  278 + }
  279 + // 加载数据
  280 + this.getList();
  281 + })
  282 + },
  283 + methods: {
  284 + // ======================== 列表查询 ========================
  285 + /** 设置账号编号 */
  286 + setAccountId(accountId) {
  287 + console.log('奥特曼!')
  288 + this.queryParams.accountId = accountId;
  289 + this.uploadData.accountId = accountId;
  290 + },
  291 + /** 查询列表 */
  292 + getList() {
  293 + // 如果没有选中公众号账号,则进行提示。
  294 + if (!this.queryParams.accountId) {
  295 + this.$message.error('未选中公众号,无法查询草稿箱')
  296 + return false
  297 + }
  298 +
  299 + this.loading = true
  300 + getMaterialPage({
  301 + ...this.queryParams,
  302 + type: this.type
  303 + }).then(response => {
  304 + this.list = response.data.list
  305 + this.total = response.data.total
  306 + }).finally(() => {
  307 + this.loading = false
  308 + })
  309 + },
  310 + /** 搜索按钮操作 */
  311 + handleQuery() {
  312 + this.queryParams.pageNo = 1
  313 + // 默认选中第一个
  314 + if (this.queryParams.accountId) {
  315 + this.setAccountId(this.queryParams.accountId)
  316 + }
  317 + this.getList()
  318 + },
  319 + /** 重置按钮操作 */
  320 + resetQuery() {
  321 + this.resetForm('queryForm')
  322 + // 默认选中第一个
  323 + if (this.accounts.length > 0) {
  324 + this.setAccountId(this.accounts[0].id)
  325 + }
  326 + this.handleQuery()
  327 + },
  328 + handleClick(tab, event) {
  329 + // 设置 type
  330 + this.uploadData.type = tab.name
  331 + // 从第一页开始查询
  332 + this.handleQuery();
  333 + },
  334 +
  335 + // ======================== 文件上传 ========================
  336 +
  337 + handleInfo(row){
  338 + this.loading = true
  339 + getMaterialVideo({
  340 + mediaId:row.mediaId
  341 + }).then((response) => {
  342 + this.loading = false
  343 + if(response.code == 200){
  344 + let downUrl = response.data.downUrl
  345 + window.open(downUrl, '_blank');
  346 + }else{
  347 + this.$message.error('获取微信视频素材出错:' + response.data.msg)
  348 + }
  349 + }).catch(() => {
  350 + this.loading = false
  351 + })
  352 + },
  353 + handleDown(row){
  354 + this.loading = true
  355 + getMaterialOther({
  356 + mediaId:row.mediaId,
  357 + fileName:row.name
  358 + }).then(response => {
  359 + this.loading = false
  360 + let url = window.URL.createObjectURL(new Blob([response.data]))
  361 + let link = document.createElement('a')
  362 + link.style.display = 'none'
  363 + link.href = url
  364 + link.setAttribute('download', row.name)
  365 + document.body.appendChild(link)
  366 + link.click()
  367 + }).catch(() => {
  368 + this.loading = false
  369 + })
  370 + },
  371 + subVideo(){
  372 + this.$refs['uploadForm'].validate((valid) => {
  373 + if (valid) {
  374 + this.$refs.uploadVideo.submit()
  375 + } else {
  376 + return false
  377 + }
  378 + })
  379 + },
  380 + handleAddVideo(){
  381 + this.dialogVideoVisible = true
  382 + },
  383 + beforeImageUpload(file) {
  384 + const isType = file.type === 'image/jpeg'
  385 + || file.type === 'image/png'
  386 + || file.type === 'image/gif'
  387 + || file.type === 'image/bmp'
  388 + || file.type === 'image/jpg';
  389 + if (!isType) {
  390 + this.$message.error('上传图片格式不对!')
  391 + this.loading = false
  392 + return false;
  393 + }
  394 + const isLt = file.size / 1024 / 1024 < 2
  395 + if (!isLt) {
  396 + this.$message.error('上传图片大小不能超过 2M!')
  397 + this.loading = false
  398 + return false;
  399 + }
  400 + this.loading = true
  401 + return true;
  402 + },
  403 + beforeVoiceUpload(file){
  404 + const isType = file.type === 'audio/mp3' || file.type === 'audio/wma' || file.type === 'audio/wav' || file.type === 'audio/amr';
  405 + const isLt = file.size / 1024 / 1024 < 2
  406 + if (!isType) {
  407 + this.$message.error('上传语音格式不对!')
  408 + }
  409 + if (!isLt) {
  410 + this.$message.error('上传语音大小不能超过2M!')
  411 + }
  412 + this.loading = false
  413 + return isType && isLt;
  414 + },
  415 + beforeVideoUpload(file){
  416 + this.addMaterialLoading = true
  417 + const isType = file.type === 'video/mp4'
  418 + const isLt = file.size / 1024 / 1024 < 10
  419 + if (!isType) {
  420 + this.$message.error('上传视频格式不对!')
  421 + }
  422 + if (!isLt) {
  423 + this.$message.error('上传视频大小不能超过10M!')
  424 + }
  425 + this.addMaterialLoading = false
  426 + return isType && isLt;
  427 + },
  428 + handleUploadSuccess(response, file, fileList) {
  429 + this.loading = false
  430 + this.addMaterialLoading = false
  431 + if (response.code !== 0) {
  432 + this.$message.error('上传出错:' + response.msg)
  433 + return false;
  434 + }
  435 +
  436 + // 清空上传时的各种数据
  437 + this.dialogVideoVisible = false
  438 + this.fileList = []
  439 + this.uploadData.title = ''
  440 + this.uploadData.introduction = ''
  441 +
  442 + // 加载数据
  443 + this.getList()
  444 + },
  445 +
  446 + // ======================== 其它操作 ========================
  447 + handleDelete(item) {
  448 + const id = item.id
  449 + this.$modal.confirm('此操作将永久删除该文件, 是否继续?').then(function() {
  450 + return deletePermanentMaterial(id);
  451 + }).then(() => {
  452 + this.getList();
  453 + this.$modal.msgSuccess("删除成功");
  454 + }).catch(() => {});
  455 + },
  456 + }
  457 +}
  458 +</script>
  459 +
  460 +<style lang="scss" scoped>
  461 +/*瀑布流样式*/
  462 +.waterfall {
  463 + width: 100%;
  464 + column-gap:10px;
  465 + column-count: 5;
  466 + margin-top: 10px; /* 芋道源码:增加 10px,避免顶着上面 */
  467 +}
  468 +.waterfall-item {
  469 + padding: 10px;
  470 + margin-bottom: 10px;
  471 + break-inside: avoid;
  472 + border: 1px solid #eaeaea;
  473 +}
  474 +.material-img {
  475 + width: 100%;
  476 +}
  477 +p {
  478 + line-height: 30px;
  479 +}
  480 +@media (min-width: 992px) and (max-width: 1300px) {
  481 + .waterfall {
  482 + column-count: 3;
  483 + }
  484 + p {
  485 + color:red;
  486 + }
  487 +}
  488 +@media (min-width: 768px) and (max-width: 991px) {
  489 + .waterfall {
  490 + column-count: 2;
  491 + }
  492 + p {
  493 + color: orange;
  494 + }
  495 +}
  496 +@media (max-width: 767px) {
  497 + .waterfall {
  498 + column-count: 1;
  499 + }
  500 +}
  501 +/*瀑布流样式*/
  502 +</style>
... ...