食谱制作页面的快捷列表关键字搜索

Merge pull request  from 德仔/xzj
This commit is contained in:
德仔 2021-06-17 19:13:50 +08:00 committed by Gitee
commit b574b1075b
18 changed files with 508 additions and 68 deletions
stdiet-admin/src/main/java/com/stdiet/web/controller/custom
stdiet-common/src/main/java/com/stdiet/common/utils
stdiet-custom/src/main
stdiet-ui/src
api/custom
components
FileUpload
UploadVideo
VideoSelectCover
store/modules
utils
views/custom
nutritionalVideo
recipesBuild
InfoView/ShortCutCom
RecipesView/RecipesCom

@ -71,6 +71,7 @@ public class SysDishesController extends BaseController {
public AjaxResult getMenuTypes(@PathVariable("id") Long id) {
JSONObject object = new JSONObject();
object.put("type", sysDishesService.getDishesMenuTypeById(id));
object.put("className", sysDishesService.getDishClassNameById(id));
return AjaxResult.success(object);
}

@ -8,6 +8,7 @@ import com.stdiet.common.core.page.TableDataInfo;
import com.stdiet.common.utils.AliyunVideoUtils;
import com.stdiet.common.utils.StringUtils;
import com.stdiet.common.utils.oss.AliyunOSSUtils;
import org.aspectj.weaver.loadtime.Aj;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@ -54,6 +55,8 @@ public class SysNutritionalVideoController extends BaseController
SysNutritionalVideo sysNutritionalVideos = sysNutritionalVideoService.selectSysNutritionalVideoById(id);
if(sysNutritionalVideos != null && StringUtils.isNotEmpty(sysNutritionalVideos.getCoverUrl())){
sysNutritionalVideos.setPreviewUrl(AliyunOSSUtils.generatePresignedUrl(sysNutritionalVideos.getCoverUrl()));
}else{
sysNutritionalVideos.setPreviewUrl(AliyunVideoUtils.getVideoCoverUrl(sysNutritionalVideos.getVideoId()));
}
return AjaxResult.success(sysNutritionalVideos);
}
@ -149,4 +152,47 @@ public class SysNutritionalVideoController extends BaseController
return AjaxResult.success(sysNutritionalVideos);
}
/**
* 根据视频videoId提交视频截图请求
*/
@PreAuthorize("@ss.hasPermi('custom:nutritionalVideo:add')")
@GetMapping("/submitVideoSnapshot")
public AjaxResult submitVideoSnapshot(@RequestParam("videoId")String videoId)
{
if(StringUtils.isEmpty(videoId)){
return AjaxResult.error("视频资源不存在");
}
AjaxResult result = AjaxResult.error("截图请求失败");
try {
if(AliyunVideoUtils.submitVideoSnapshot(videoId)){
result = AjaxResult.success();
}
}catch (Exception e){
e.printStackTrace();
}
return result;
}
/**
* 根据视频videoId获取视频截图
*/
@PreAuthorize("@ss.hasPermi('custom:nutritionalVideo:add')")
@GetMapping("/getVideoSnapshot")
public AjaxResult getVideoSnapshot(@RequestParam("videoId")String videoId)
{
if(StringUtils.isEmpty(videoId)){
return AjaxResult.error("视频资源不存在");
}
AjaxResult result = AjaxResult.error("截图不存在");
try {
List<String> videoSnapshotList = AliyunVideoUtils.getVideoSnapshot(videoId);
if(videoSnapshotList != null){
result = AjaxResult.success(videoSnapshotList);
}
}catch (Exception e){
e.printStackTrace();
}
return result;
}
}

@ -29,6 +29,9 @@ public class AliyunVideoUtils {
public static final String search_field = "VideoId,Title,CoverURL,CateName,Tags,Status,Description,CreationTime";
//默认截图模板
public static final String defaultSnapshotTemplateId = "f8ccc3b5113ca8ea356ef9adf8c573b2";
/**
* 初始化视频点播Client
* @return
@ -176,7 +179,7 @@ public class AliyunVideoUtils {
* @return
* @throws Exception
*/
public static String updateVideo(String videoId, String title, String tags, String description, Long cateId) throws Exception{
public static String updateVideo(String videoId, String title, String tags, String description, Long cateId, String coverUrl) throws Exception{
com.aliyun.vod20170321.Client client = AliyunVideoUtils.createClient();
if(StringUtils.isEmpty(videoId)){
return null;
@ -194,6 +197,30 @@ public class AliyunVideoUtils {
if(cateId != null && cateId.longValue() > 0){
updateVideoInfoRequest.setCateId(cateId);
}
if(StringUtils.isNotEmpty(coverUrl)){
updateVideoInfoRequest.setCoverURL(coverUrl);
}
UpdateVideoInfoResponse updateVideoInfoResponse = client.updateVideoInfo(updateVideoInfoRequest);
if(updateVideoInfoResponse != null){
return updateVideoInfoResponse.body.requestId;
}
return null;
}
/**
* 更新视频封面
* @param videoId 视频ID必须
* @param coverUrl 封面
* @return
* @throws Exception
*/
public static String updateVideoCoverUrl(String videoId, String coverUrl) throws Exception{
com.aliyun.vod20170321.Client client = AliyunVideoUtils.createClient();
if(StringUtils.isEmpty(videoId) || StringUtils.isEmpty(coverUrl)){
return null;
}
UpdateVideoInfoRequest updateVideoInfoRequest = new UpdateVideoInfoRequest().setVideoId(videoId);
updateVideoInfoRequest.setCoverURL(coverUrl);
UpdateVideoInfoResponse updateVideoInfoResponse = client.updateVideoInfo(updateVideoInfoRequest);
if(updateVideoInfoResponse != null){
return updateVideoInfoResponse.body.requestId;
@ -208,7 +235,7 @@ public class AliyunVideoUtils {
* @throws Exception
*/
public static String delVideo(String videoId) throws Exception{
return updateVideo(videoId, null,null,null, default_delete_cateId);
return updateVideo(videoId, null,null,null, default_delete_cateId, null);
}
/**
@ -261,10 +288,52 @@ public class AliyunVideoUtils {
return coverUrl;
}
/**
* 根据VideoId提交截图请求
* @param videoId
* @return
*/
public static boolean submitVideoSnapshot(String videoId){
try{
com.aliyun.vod20170321.Client client = AliyunVideoUtils.createClient();
SubmitSnapshotJobRequest submitSnapshotJobRequest = new SubmitSnapshotJobRequest()
.setSnapshotTemplateId(defaultSnapshotTemplateId)
.setVideoId(videoId);
SubmitSnapshotJobResponse response = client.submitSnapshotJob(submitSnapshotJobRequest);
return response != null && response.body != null && response.body.snapshotJob != null;
}catch (Exception e){
e.printStackTrace();
}
return false;
}
/**
* 根据VideoId获取普通截图信息
* @param videoId
* @return
*/
public static List<String> getVideoSnapshot(String videoId){
List<String> snapshotList = new ArrayList<>();
try{
com.aliyun.vod20170321.Client client = AliyunVideoUtils.createClient();
ListSnapshotsRequest listSnapshotsRequest = new ListSnapshotsRequest()
.setVideoId(videoId)
.setSnapshotType("NormalSnapshot");
ListSnapshotsResponse response = client.listSnapshots(listSnapshotsRequest);
if(response != null && response.body != null){
List<ListSnapshotsResponseBody.ListSnapshotsResponseBodyMediaSnapshotSnapshotsSnapshot> listSnapshots = response.body.mediaSnapshot.snapshots.snapshot;
if(listSnapshots != null && listSnapshots.size() > 0){
for (ListSnapshotsResponseBody.ListSnapshotsResponseBodyMediaSnapshotSnapshotsSnapshot snapshot : listSnapshots) {
snapshotList.add(snapshot.url);
}
}
}
}catch (Exception e){
e.printStackTrace();
}
return snapshotList;
}
}

@ -3,9 +3,11 @@ package com.stdiet.custom.mapper;
import com.stdiet.custom.domain.SysDishes;
import com.stdiet.custom.domain.SysDishesIngredient;
import com.stdiet.custom.domain.SysPhysicalSignsObj;
import org.apache.ibatis.annotations.Param;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 菜品Mapper接口
@ -80,4 +82,12 @@ public interface SysDishesMapper {
int deleteDishesNotRecByDishesId(Long dishesId);
/**
* 根据菜品ID查询大类小类名称
* @param dishId
* @return
*/
String getDishClassNameById(@Param("dishId")Long dishId);
}

@ -1,6 +1,8 @@
package com.stdiet.custom.service;
import java.util.List;
import java.util.Map;
import com.stdiet.custom.domain.SysDishes;
import com.stdiet.custom.domain.SysDishesIngredient;
import com.stdiet.custom.domain.SysIngredient;
@ -66,4 +68,11 @@ public interface ISysDishesService
public String getDishesMenuTypeById(Long id);
/**
* 根据菜品ID查询大类小类名称
* @param dishId
* @return
*/
String getDishClassNameById(Long dishId);
}

@ -10,6 +10,7 @@ import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 菜品Service业务层处理
@ -183,4 +184,15 @@ public class SysDishesServiceImpl implements ISysDishesService {
return sysDishesMapper.getDishesMenuTypeById(id);
}
/**
* 根据菜品ID查询大类小类名称
* @param dishId
* @return
*/
@Override
public String getDishClassNameById(Long dishId){
return sysDishesMapper.getDishClassNameById(dishId);
}
}

@ -106,6 +106,17 @@ public class SysNutritionalVideoServiceImpl implements ISysNutritionalVideoServi
public int insertSysNutritionalVideo(SysNutritionalVideo sysNutritionalVideo)
{
sysNutritionalVideo.setCreateTime(DateUtils.getNowDate());
//判断封面是上传的还是阿里云视频截图封面
if(isSnapshot(sysNutritionalVideo.getCoverUrl())){
//更新阿里云视频封面
try{
AliyunVideoUtils.updateVideoCoverUrl(sysNutritionalVideo.getVideoId(), sysNutritionalVideo.getCoverUrl());
}catch (Exception e){
e.printStackTrace();
return 0;
}
sysNutritionalVideo.setCoverUrl("");
}
return sysNutritionalVideoMapper.insertSysNutritionalVideo(sysNutritionalVideo);
}
@ -119,19 +130,23 @@ public class SysNutritionalVideoServiceImpl implements ISysNutritionalVideoServi
public int updateSysNutritionalVideo(SysNutritionalVideo sysNutritionalVideo)
{
sysNutritionalVideo.setUpdateTime(DateUtils.getNowDate());
sysNutritionalVideo.setCoverUrl(sysNutritionalVideo.getCoverUrl() == null ? "" : sysNutritionalVideo.getCoverUrl());
String coverUrl = sysNutritionalVideo.getCoverUrl();
//判断封面是上传的还是阿里云视频截图封面
sysNutritionalVideo.setCoverUrl(isSnapshot(coverUrl) ? "" : coverUrl);
int row = sysNutritionalVideoMapper.updateSysNutritionalVideo(sysNutritionalVideo);
if(row > 0){
updateAliyunVideo(sysNutritionalVideo.getId());
sysNutritionalVideo.setCoverUrl(isSnapshot(coverUrl) ? coverUrl : null);
updateAliyunVideo(sysNutritionalVideo);
}
return row;
}
@Async
public void updateAliyunVideo(Long id){
public void updateAliyunVideo(SysNutritionalVideo sysNutritionalVideo){
try{
SysNutritionalVideo sysNutritionalVideo = selectSysNutritionalVideoById(id);
if(sysNutritionalVideo != null && sysNutritionalVideo.getVideoId() != null){
AliyunVideoUtils.updateVideo(sysNutritionalVideo.getVideoId(), sysNutritionalVideo.getTitle(), sysNutritionalVideo.getTags(), sysNutritionalVideo.getDescription(), null);
AliyunVideoUtils.updateVideo(sysNutritionalVideo.getVideoId(), sysNutritionalVideo.getTitle(), sysNutritionalVideo.getTags(), sysNutritionalVideo.getDescription(), null, sysNutritionalVideo.getCoverUrl());
}
}catch (Exception e){
e.printStackTrace();
@ -270,4 +285,15 @@ public class SysNutritionalVideoServiceImpl implements ISysNutritionalVideoServi
return sysNutritionalVideoMapper.updateVideoPlayNum(videoId);
}
/**
* 判断是否为阿里点播的截图
* @param url
* @return
*/
private boolean isSnapshot(String url){
return StringUtils.isNotEmpty(url) && url.startsWith("http://outin");
}
}

@ -207,4 +207,12 @@
delete from sys_dishes_not_rec where dishes_id=#{dishesId}
</delete>
<!-- 根据菜品ID查询菜品对应大类小类名称 -->
<select id="getDishClassNameById" parameterType="Long" resultType="String">
select concat(IFNULL(big.dict_label,''),'/',IFNULL(small.dict_label,'')) as className from sys_dishes dish
LEFT JOIN (SELECT dict_label, dict_value FROM sys_dict_data WHERE dict_type = 'dish_class_big') AS big ON big.dict_value = dish.big_class
LEFT JOIN (SELECT dict_label, dict_value FROM sys_dict_data WHERE dict_type = 'dish_class_small') AS small ON small.dict_value = dish.small_class
where dish.id = #{dishId} and dish.del_flag = 0
</select>
</mapper>

@ -78,3 +78,23 @@ export function getVideoPlayUrlById(id) {
})
}
// 根据视频videoId提交视频截图请求
export function submitVideoSnapshot(id) {
return request({
url: '/custom/nutritionalVideo/submitVideoSnapshot',
method: 'get',
params: {'videoId': id}
})
}
//根据视频videoId获取视频截图
export function getVideoSnapshot(id) {
return request({
url: '/custom/nutritionalVideo/getVideoSnapshot',
method: 'get',
params: {'videoId': id}
})
}

@ -45,3 +45,17 @@ export function replaceMenuApi(data) {
data
});
}
/**
* 根据菜品ID查询大类小类名称
* @param dishId
*/
export function getDishClassNameById(dishId) {
return request({
url: "/custom/recipes/getDishClassNameById",
method: "get",
params: {'dishId':dishId}
});
}

@ -8,7 +8,7 @@
:accept="'.png,.jpg'"
:before-upload="beforeAvatarUpload">
<img v-if="imageUrl || coverUrl" :src="imageUrl || coverUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
<i v-else class="el-icon-plus avatar-uploader-icon" title="手动上传图片"></i>
<div class="el-upload__tip" slot="tip" style="color:#1890ff">
<el-button v-if="imageUrl || coverUrl" size="small" type="danger" @click="removeFile">移除</el-button>

@ -17,15 +17,11 @@
placeholder="请输入视频描述"
v-model.trim="videoFrom.description"
maxlength="1000"
rows="3"
rows="2"
show-word-limit
/>
</el-form-item>
<el-form-item label="视频封面" prop="coverUrl">
<UploadFile ref="uploadFile" :prefix="'videoCover'" @callbackMethod="handleCoverUrl" :tips="'视频未传封面图片时,会主动截取封面,但会存在延迟,请勿直接发布到小程序'"></UploadFile>
</el-form-item>
<div style="display:flex">
<div style="display:flex">
<el-form-item label="视频类别" prop="cateId" style="width:300px">
<treeselect
v-model="videoFrom.cateId"
@ -46,40 +42,47 @@
</el-select>
</el-form-item>
</div>
<el-form-item label="视频文件" prop="file">
<div>
<input type="file" accept=".mp4" ref="videoFile" id="videoFile" @change="fileChange($event)">
<div > <span>上传状态{{statusText}}</span><span style="margin-left:100px">进度{{authProgress}}%</span></div>
<div style="color:#1890ff">
1只能上传mp4文件上传大文件时请使用客户端上传防止上传超时
<el-button type="primary" @click="authUpload" :disabled="uploadDisabled" size="small" icon="el-icon-upload2">上传视频</el-button><span style="margin-left:20px">1只能上传mp4格式视频</span>
</div>
</div>
</el-form-item>
<el-form-item label="视频封面" prop="coverUrl">
<UploadFile ref="uploadFile" :prefix="'videoCover'" :coverUrl="videoFrom.previewUrl" @callbackMethod="handleCoverUrl" :tips="''"></UploadFile>
<el-button type="primary" size="small" icon="el-icon-film" @click="selectVideoCover" :disabled="!uploadVideoFlag" title="上传视频之后选择视频截图作为封面">选择封面</el-button>
</el-form-item>
<el-form-item label="展示状态" prop="wxShow">
<el-switch
v-model="videoFrom.wxShow"
active-text="小程序展示"
inactive-text="小程序不展示">
active-text="展示"
inactive-text="不展示">
</el-switch>
<div style="color:red">提示请保证内容正确再展示到小程序</div>
<div style="color:red">提示开启展示之后客户可看到该视频请保证内容正确再展示</div>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="authUpload" :disabled="uploadDisabled">开始上传</el-button>
<el-button type="primary" @click="submitVideoForm">保存</el-button>
<el-button @click="cancel"> </el-button>
</div>
<!-- 手动选择封面 -->
<VideoSelectCover ref="videoSelectCoverRef"></VideoSelectCover>
</el-dialog>
</template>
<script>
import axios from 'axios'
import {getUploadVideoAuth,addNutritionalVideo } from "@/api/custom/nutritionalVideo";
import {getUploadVideoAuth,addNutritionalVideo,getVideoSnapshot,submitVideoSnapshot } from "@/api/custom/nutritionalVideo";
import {getAllClassify } from "@/api/custom/videoClassify";
import UploadFile from "@/components/FileUpload/UploadFile";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import IconSelect from "@/components/IconSelect";
import VideoSelectCover from "@/components/VideoSelectCover";
export default {
name: "UploadVideo",
data () {
@ -122,6 +125,8 @@
statusText: '',
fileType:['mp4','MP4'],
uploading: false,
//
uploadVideoFlag: false
}
},
created(){
@ -142,7 +147,7 @@
},
components: {
UploadFile,Treeselect, IconSelect
UploadFile,Treeselect, IconSelect,VideoSelectCover
},
methods: {
showDialog(classifyList, callback){
@ -167,7 +172,8 @@
tags: null,
payLevel: this.defaultPayLevel ? parseInt(this.defaultPayLevel) : null,
videoId: null,
wxShow: false
wxShow: false,
previewUrl: null
};
if(this.$refs.uploadFile){
this.$refs.uploadFile.resetUpload();
@ -180,11 +186,53 @@
this.uploader = null;
this.statusText = '';
this.uploading = false;
this.uploadVideoFlag = false;
this.resetForm("videoFrom");
},
submitVideoForm(){
this.$refs["videoFrom"].validate((valid) => {
if (valid) {
//
if(this.videoFrom.cateId == 0){
this.$message({
message: "视频分类不能选择主分类",
type: "warning",
});
return;
}
if(this.uploading){
this.$message({
message: "视频正在上传,请勿取消",
type: "warning",
});
return;
}
if(!this.uploadVideoFlag){
this.$message({
message: "请先上传视频再保存",
type: "warning",
});
return;
}
this.videoFrom.showFlag = this.videoFrom.wxShow ? 1 : 0;
addNutritionalVideo(this.videoFrom).then(response => {
if (response.code === 200) {
this.msgSuccess("视频保存成功");
this.open = false;
this.callback && this.callback();
}
})
}
});
},
selectVideoCover(){
this.$refs.videoSelectCoverRef.showDialog(this.videoFrom,(url)=>{
//console.log(url);
this.videoFrom.previewUrl = url;
this.videoFrom.coverUrl = url;
});
},
/** 转换菜单数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
@ -205,7 +253,7 @@
cancel(){
if(this.uploading){
this.$message({
message: "文件正在上传,请勿取消",
message: "视频正在上传,请勿取消",
type: "warning",
});
return;
@ -219,7 +267,7 @@
if (valid) {
if(this.uploading){
this.$message({
message: "文件正在上传,请勿取消",
message: "视频正在上传,请勿取消",
type: "warning",
});
return;
@ -242,7 +290,7 @@
this.videoFrom.fileName = this.file.name;
if(this.videoFrom.fileName == null || this.videoFrom.fileName.length == 0 || this.videoFrom.fileName.lastIndexOf(".") == -1){
this.$message({
message: "当前文件名称错误",
message: "当前视频名称错误",
type: "warning",
});
return;
@ -250,7 +298,7 @@
let fileType = this.videoFrom.fileName.substring(this.videoFrom.fileName.lastIndexOf(".")+1);
if(this.fileType.indexOf(fileType) == -1){
this.$message({
message: "当前文件格式错误",
message: "当前视频格式错误",
type: "warning",
});
return;
@ -268,8 +316,8 @@
this.resumeDisabled = true
}
})
}
});
}
});
},
authUpload () {
// startUpload ,
@ -309,7 +357,7 @@
addFileSuccess: function (uploadInfo) {
self.uploadDisabled = false
self.resumeDisabled = false
self.statusText = '添加文件成功, 等待上传...'
self.statusText = '添加视频成功, 等待上传...'
console.log("addFileSuccess: " + uploadInfo.file.name)
},
//
@ -322,32 +370,32 @@
// uploadInfo.videoId , (https://help.aliyun.com/document_detail/55408.html)
// uploadInfo.videoId , (https://help.aliyun.com/document_detail/55407.html)
uploader.setUploadAuthAndAddress(uploadInfo, self.uploadAuth.uploadAuth, self.uploadAuth.uploadAddress, self.uploadAuth.videoId)
self.statusText = '文件开始上传...'
self.statusText = '视频开始上传...'
console.log("onUploadStarted:" + uploadInfo.file.name + ", endpoint:" + uploadInfo.endpoint + ", bucket:" + uploadInfo.bucket + ", object:" + uploadInfo.object)
},
//
onUploadSucceed: function (uploadInfo) {
console.log("onUploadSucceed: " + uploadInfo.file.name + ", endpoint:" + uploadInfo.endpoint + ", bucket:" + uploadInfo.bucket + ", object:" + uploadInfo.object)
self.statusText = '文件上传成功!'
self.statusText = '视频上传成功!'
},
//
onUploadFailed: function (uploadInfo, code, message) {
console.log("onUploadFailed: file:" + uploadInfo.file.name + ",code:" + code + ", message:" + message);
self.uploading = false;
self.statusText = '文件上传失败!'
self.statusText = '视频上传失败!'
},
//
onUploadCanceled: function (uploadInfo, code, message) {
console.log("Canceled file: " + uploadInfo.file.name + ", code: " + code + ", message:" + message)
self.statusText = '文件已暂停上传'
self.statusText = '视频已暂停上传'
},
// ,
onUploadProgress: function (uploadInfo, totalSize, progress) {
console.log("onUploadProgress:file:" + uploadInfo.file.name + ", fileSize:" + totalSize + ", percent:" + Math.ceil(progress * 100) + "%")
let progressPercent = Math.ceil(progress * 100)
self.authProgress = progressPercent
self.statusText = '文件上传中...'
self.statusText = '视频上传中...'
},
//
onUploadTokenExpired: function (uploadInfo) {
@ -360,23 +408,20 @@
uploader.resumeUploadWithAuth(uploadAuth)
console.log('upload expired and resume upload with uploadauth ' + uploadAuth)
})*/
self.statusText = '文件上传超时...';
self.statusText = '视频上传超时...';
self.uploading = false;
},
//
onUploadEnd: function (uploadInfo) {
self.statusText = '文件上传完毕'
self.statusText = '视频上传完毕'
self.uploading = false;
//self.msgSuccess("");
self.videoFrom.showFlag = self.videoFrom.wxShow ? 1 : 0;
addNutritionalVideo(self.videoFrom).then(response => {
if (response.code === 200) {
self.msgSuccess("视频上传成功");
self.open = false;
self.callback && self.callback();
self.uploadVideoFlag = true;
submitVideoSnapshot(self.videoFrom.videoId).then(response => {
if(response.code == 200){
console.log("-- 截图成功 --");
}
})
})
}
})
return uploader

@ -0,0 +1,69 @@
<template>
<el-dialog title="选择视频封面(每隔两秒一张截图,共十张)" :visible.sync="open" width="650px" style="height: 80%; overflow: auto;" :close-on-click-modal="true" :show-close="true" append-to-body>
<div v-if="!showFlag"><el-divider>{{showStatusText}}</el-divider></div>
<div v-else class="demo-image__lazy" style="margin-left:20px;">
<div v-for="url in videoSnapshotList" :key="url">
<el-image :src="url" lazy style="width:550px;height:300px;margin-top:10px;cursor:pointer" title="点击选择" @click="selectVideoSnapshot(url)"></el-image>
<el-divider></el-divider>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</template>
<script>
import axios from 'axios'
import {getVideoSnapshot } from "@/api/custom/nutritionalVideo";
export default {
name: "VideoSelectCover",
data () {
return {
open: false,
videoData: null,
callback: undefined,
showFlag: false,
showStatusText:"加载中...",
videoSnapshotList:[]
}
},
created(){
},
components: {
},
methods: {
showDialog(data,callback){
if(data && data.videoId != null){
this.videoSnapshotList = [];
this.showFlag = false;
this.showStatusText = "加载中...";
this.open = true;
this.videoData = data;
this.callback = callback;
this.getVideoSnapshot();
}
},
getVideoSnapshot(){
getVideoSnapshot(this.videoData.videoId).then(response => {
if(response.code == 200 && response.data.length > 0){
this.videoSnapshotList = response.data;
this.showFlag = true;
}else{
this.showStatusText = "暂无截图数据!"
}
})
},
selectVideoSnapshot(url){
this.callback && this.callback(url);
this.open = false;
},
cancel(){
this.open = false;
}
}
}
</script>

@ -555,6 +555,7 @@ const actions = {
id: new Date().getTime(),
name: tarDishes.name,
type: response.data.type.split(",").sort(),
className: response.data.className, //大类小类名称
data: tarDishes
}).then(() => {
window.postMessage(

@ -1,8 +1,19 @@
export function getShortCut() {
export function getShortCut(key) {
return new Promise((res, rej) => {
try {
const data = JSON.parse(localStorage.getItem("shortCut") || "[]");
res(data);
//关键字检索
if(key != undefined && key != null && key != ""){
const resultData = [];
data.forEach((item,index) => {
if(item.name.indexOf(key) != -1 || (item.className != undefined && item.className != null && item.className.indexOf(key) != -1)){
resultData.push(item);
}
});
res(resultData);
}else{
res(data);
}
} catch (error) {
rej(error);
}
@ -35,6 +46,19 @@ export async function removeShortCut(id) {
});
}
export async function removeMuchShortCut(ids) {
const shortCutList = await getShortCut();
return new Promise((res, rej) => {
try {
const newShortCutList = shortCutList.filter(obj => ids.indexOf(obj.id) == -1);
localStorage.setItem("shortCut", JSON.stringify(newShortCutList));
res();
} catch (error) {
rej(error);
}
});
}
export async function editShortCut(data) {
const shortCutList = await getShortCut();
return new Promise((res, rej) => {

@ -9,7 +9,7 @@
size="small"
/>
</el-form-item>
<el-form-item label="小程序展示状态" prop="showFlag" label-width="200">
<el-form-item label="展示状态" prop="showFlag" label-width="200">
<el-select
v-model="queryParams.showFlag"
placeholder="请选示状态"
@ -131,7 +131,7 @@
<!--<el-table-column label="标签" align="center" prop="tags" width="100"/>-->
<el-table-column label="分类" align="center" prop="cateName" width="100"/>
<el-table-column label="权限等级" align="center" prop="payLevelName" width="100"/>
<el-table-column label="小程序展示状态" align="center" prop="showFlag" width="200">
<el-table-column label="展示状态" align="center" prop="showFlag" width="200">
<template slot-scope="scope" >
<el-switch
v-model="scope.row.wxShow"
@ -208,20 +208,26 @@
show-word-limit
/>
</el-form-item>
<el-form-item label="视频封面" prop="coverUrl">
<UploadFile ref="uploadFile" v-if="open" :prefix="'videoCover'" :coverUrl="form.previewUrl" @callbackMethod="handleCoverUrl" :tips="'视频未传封面图片时,会主动截取封面,但会存在延迟,请勿直接发布到小程序'"></UploadFile>
</el-form-item>
<el-form-item label="视频类别" prop="cateId">
<el-select v-model="form.cateId" clearable filterable placeholder="请选择类别">
<div style="display:flex">
<el-form-item label="视频类别" prop="cateId" style="width:300px">
<!--<el-select v-model="form.cateId" clearable filterable placeholder="请选择类别">
<el-option
v-for="classify in classifyList"
:key="classify.id"
:label="classify.cateName"
:value="classify.id"
/>
</el-select>
</el-select>-->
<treeselect
v-model="form.cateId"
:options="classifyList"
:normalizer="normalizer"
:show-count="true"
placeholder="选择分类"
style="width:200px"
/>
</el-form-item>
<el-form-item label="视频权限" prop="payLevel">
<el-form-item label="视频权限" prop="payLevel" style="margin-left:40px">
<el-select v-model="form.payLevel" clearable filterable placeholder="请选择权限">
<el-option
v-for="dict in payVideoLevelList"
@ -231,13 +237,18 @@
/>
</el-select>
</el-form-item>
</div>
<el-form-item label="视频封面" prop="coverUrl">
<UploadFile ref="uploadFile" v-if="open" :prefix="'videoCover'" :coverUrl="form.previewUrl" @callbackMethod="handleCoverUrl" :tips="''"></UploadFile>
<el-button type="primary" size="small" icon="el-icon-film" @click="selectVideoCover" title="上传视频之后选择视频截图作为封面">选择封面</el-button>
</el-form-item>
<el-form-item label="展示状态" prop="wxShow">
<el-switch
v-model="form.wxShow"
active-text="小程序展示"
inactive-text="小程序不展示">
active-text="展示"
inactive-text="不展示">
</el-switch>
<div style="color:red">提示请保证内容正确再展示到小程序</div>
<div style="color:red">提示开启展示之后客户可看到该视频请保证内容正确再展示</div>
</el-form-item>
</el-form>
@ -255,6 +266,9 @@
<VideoClassify ref="videoClassifyRef"></VideoClassify>
</div>
</el-dialog>
<!-- 手动选择封面 -->
<VideoSelectCover ref="videoSelectCoverRef"></VideoSelectCover>
</div>
</template>
@ -268,6 +282,7 @@
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import IconSelect from "@/components/IconSelect";
import VideoSelectCover from "@/components/VideoSelectCover";
export default {
name: "NutritionalVideo",
data() {
@ -316,6 +331,8 @@
coverImageList:[],
//
classifyList:[],
//
allClassifyList:[],
//
payVideoLevelList:[],
//
@ -331,7 +348,7 @@
});
},
components: {
UploadVideo,UploadFile,VideoClassify,AutoHideMessage,Treeselect, IconSelect
UploadVideo,UploadFile,VideoClassify,AutoHideMessage,Treeselect, IconSelect,VideoSelectCover
},
methods: {
/** 查询营养视频列表 */
@ -350,6 +367,7 @@
getAllVideoClassify(){
getAllClassify().then(response => {
if(response.code == 200){
this.allClassifyList = response.data;
this.classifyList = [];
const classify = { id: 0, cateName: '主分类', children: [] };
classify.children = this.handleTree(response.data, "id");
@ -366,6 +384,7 @@
reset() {
this.form = {
id: null,
videoId:null,
cateId: null,
coverUrl: null,
title: null,
@ -373,10 +392,18 @@
tags: null,
payLevel:null,
showFlag: null,
wxShow: false
wxShow: false,
previewUrl: null
};
this.resetForm("form");
},
selectVideoCover(){
this.$refs.videoSelectCoverRef.showDialog(this.form,(url)=>{
//console.log(url);
this.form.previewUrl = url;
this.form.coverUrl = url;
});
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
@ -394,7 +421,7 @@
this.multiple = !selection.length
},
clickUploadVideo(){
this.$refs.uploadVideoRef.showDialog(this.classifyList, ()=>{
this.$refs.uploadVideoRef.showDialog(this.allClassifyList, ()=>{
this.getList();
});
},
@ -443,6 +470,14 @@
this.$refs["form"].validate(valid => {
if (valid) {
this.form.showFlag = this.form.wxShow ? 1 : 0;
//
if(this.form.cateId == 0){
this.$message({
message: "视频分类不能选择主分类",
type: "warning",
});
return;
}
if (this.form.id != null) {
updateNutritionalVideo(this.form).then(response => {
if (response.code === 200) {

@ -1,14 +1,32 @@
<template>
<div class="short_cut_com_wrapper">
<div class="header">
<el-button icon="el-icon-refresh" size="mini" @click="getList" circle />
</div>
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="关键词" prop="key" >
<el-input
v-model.trim="queryParams.key"
placeholder="请输入名称/种类"
clearable
@clear="getList"
@keyup.native="getList"
size="small"
/>
</el-form-item>
<el-form-item>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="getList">搜索</el-button>
</el-form-item>
</el-form>
<div class="header">
<el-button icon="el-icon-search" size="mini" @click="showSearch = !showSearch" circle :title="showSearch ? '隐藏搜索' : '显示搜索'"/>
<el-button icon="el-icon-refresh" size="mini" @click="getList" circle title="刷新"/>
<el-button icon="el-icon-delete" size="mini" circle :title="'清空快捷列表'" @click="handleOnMuchDelete"/>
</div>
<el-table
:data="dataList"
ref="shortCutTable"
highlight-current-row
@current-change="handleOnCurrentChange"
height="800"
height="700"
>
<el-table-column prop="name" label="对象" align="center">
<template slot-scope="scope">
@ -95,6 +113,7 @@ import {
getShortCut,
removeShortCut,
editShortCut,
removeMuchShortCut
} from "@/utils/shortCutUtils";
import AutoHideInfo from "@/components/AutoHideInfo";
import { createNamespacedHelpers } from "vuex";
@ -113,6 +132,10 @@ export default {
return {
dataList: [],
modifingId: 0,
showSearch: false,
queryParams:{
key: null
}
};
},
created() {
@ -147,8 +170,12 @@ export default {
}
},
getList(setCurrent) {
getShortCut().then((data) => {
getShortCut(this.queryParams.key).then((data) => {
this.dataList = data;
//10
if(this.dataList && this.dataList.length > 5 && !this.showSearch){
this.showSearch = true;
}
// console.log(this.dataList);
if (setCurrent) {
this.$refs.shortCutTable.setCurrentRow(data[0]);
@ -163,6 +190,27 @@ export default {
}
});
},
handleOnMuchDelete() {
if(this.dataList && this.dataList.length > 0){
let ids = [];
this.dataList.forEach((item,index) => {
ids.push(item.id);
});
this.$confirm("是否确定清除当前 "+ids.length+" 条快捷数据?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(function () {
return removeMuchShortCut(ids);
}).then((response) => {
this.getList();
if (ids.indexOf(this.curShortCutObj.id) != -1) {
this.setCurShortCutObj({});
}
})
.catch(function () {});
}
},
handleOnCurrentChange(data) {
this.setCurShortCutObj({ data });
},

@ -342,6 +342,9 @@
</div>
</template>
<script>
import {
getDishClassNameById
} from "@/api/custom/recipes";
import { createNamespacedHelpers } from "vuex";
const {
mapActions,