Commit e2ced02a authored by miaojiale's avatar miaojiale

分片

parent e906e461
NODE_ENV = 'development'
VUE_APP_URL = 'https://zcas.wzswsj.gov.cn:8079/screening-api/'
VUE_APP_IMG = 'https://inno.sh-sict.com/wjy-mobile/'
VUE_APP_IMG = 'https://inno.sh-sict.com/gastric/'
This diff is collapsed.
......@@ -15,6 +15,7 @@
"fastclick": "^1.0.6",
"js-base64": "^2.4.9",
"js-file-download": "^0.4.1",
"js-md5": "^0.7.3",
"lodash": "^4.17.4",
"marked": "^0.3.19",
"mescroll.js": "^1.4.0",
......@@ -25,6 +26,7 @@
"qs": "^6.5.2",
"v-distpicker": "^1.0.16",
"vant": "^2.12.45",
"video.js": "^7.20.3",
"vue": "^2.6.11",
"vue-carousel": "^0.6.5",
"vue-product-zoomer": "^2.0.10",
......
<template>
<div id="app">
<transition :name="routerAnimate">
<keep-alive>
<router-view
class="app-content"
v-if="$route.meta.keepAlive"
></router-view>
<keep-alive :include="keepAlive">
<router-view class="app-content"></router-view>
</keep-alive>
</transition>
<transition :name="routerAnimate">
<router-view
class="app-content"
v-if="!$route.meta.keepAlive"
></router-view>
</transition>
</div>
</template>
......@@ -22,14 +13,28 @@ export default {
name: 'app',
data () {
return {
aliveRoute: [],
routerAnimate: ''
routerAnimate: '',
keepAlive: [],
aliveRoute: ['peopleList']
}
},
watch: {
// 监听 $route 为内页设置不同的过渡效果
"$route" (to, from) {
/*动态设置路由缓存 start*/
//?需要缓存的组件
if (this.aliveRoute.includes(to.name)) {
to.meta.keepAlive = true
}
// console.log(to.path + '---' + to.meta.keepAlive);
let aliveRoute = this.$router.options.routes.filter(e => e.meta && e.meta.keepAlive).map(e => e.name)
this.keepAlive = aliveRoute
/*动态设置路由缓存 end*/
// console.log(aliveRoute);
if (to.meta.index === from.meta.index) {
this.routerAnimate = ""
return;
// this.routerAnimate = "slide-left"
}
......
......@@ -13,24 +13,20 @@ const v1 = `/gastric-cancer${process.env.VUE_APP_MOD || ""}-user`;
const ewellDefectData = `/gastric-cancer${process.env.VUE_APP_MOD || ""}-data`;
const im = `/gastric-cancer${process.env.VUE_APP_MOD || ""}-im`;
export const API = {
//居民端跳转
postCToken: (data) => {
return post(`${v1}/app/customer/forward`, data);
//登录
login: (data) => {
return post(`${v1}/user/login`, data);
},
/*******************
* 患者端-首页 *
*******************/
//文章推荐
postArticle: (data) => {
return post(`${ewellDefectData}/app/index/article/list`, data);
getPeopleList: (data) => {
return post(`${ewellDefectData}/report/hospital`, data);
},
//! 筛查档案
reportInfo: (data) => {
getVideoList: (data) => {
return get(
`${ewellDefectData}/app/customer/screen/report?patientId=${data.patientId}`,
`${ewellDefectData}/app/report/video/mine?pageNum=${data.pageNum}&pageSize=${data.pageSize}&dataId=${data.dataId}`,
data
);
},
fileUpload: (data) => {
return post(`${ewellDefectData}/app/report/video/upload`, data);
}
};
......@@ -8,32 +8,26 @@ let CommonAlert = function (msg) {
if (msg.length > 0) {
return Toast({
message: msg,
duration: 1500,
duration: 1500
});
}
};
// axios.defaults.timeout = 5000;
if (process.env.NODE_ENV == "development") {
// axios.defaults.baseURL = 'https://inno.sh-sict.com/screening-api/';
axios.defaults.baseURL = "https://inno.sh-sict.com/gastric-api/";
} else {
axios.defaults.baseURL = process.env.VUE_APP_URL;
}
window.baseURL = axios.defaults.baseURL;
//http request 拦截器
axios.create({
withCredentials: true,
withCredentials: true
});
axios.interceptors.request.use(
(config) => {
config.data = config.data;
config.headers["user-cookie"] = localStorage.getItem("token");
if (config.url === "/ewell-tumors-user/province/list") {
//坐下判断如果是获取省市接口则不做拦截
}
// else if(!localStorage.getItem("token")){
// toLogin()
// }
config.headers["user-cookie"] = localStorage.getItem("vd_token");
return config;
},
(error) => {
......@@ -47,10 +41,7 @@ axios.interceptors.request.use(
*/
const toLogin = () => {
router.replace({
path: "/register",
query: {
redirect: router.currentRoute.fullPath,
},
path: "/login"
});
};
......@@ -60,8 +51,8 @@ axios.interceptors.response.use(
if (response.data.code === 0 || response.data.code === -1) {
CommonAlert(response.data.message);
} else if (response.data.code === -100) {
localStorage.removeItem('token')
window.location.hash = "/register";
localStorage.removeItem("vd_token");
window.location.hash = "/login";
}
return response;
},
......@@ -159,7 +150,7 @@ export function post(url, data = {}, params = {}) {
return new Promise((resolve, reject) => {
axios
.post(url, data, {
params,
params
})
.then(
(response) => {
......@@ -176,8 +167,8 @@ export function postForm(url, data = {}) {
axios
.post(url, qs.stringify(data), {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
"Content-Type": "application/x-www-form-urlencoded"
}
})
.then(
(response) => {
......@@ -197,8 +188,8 @@ export function expoertExcel(url, data = {}) {
.post(url, qs.stringify(data), {
responseType: "blob",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
"Content-Type": "application/x-www-form-urlencoded"
}
})
.then(
(response) => {
......@@ -217,20 +208,20 @@ export function downloadExcel(url, data = {}, title = "筛查信息导出表") {
method: "post",
url: url,
data: data,
responseType: "blob",
responseType: "blob"
})
.then((res) => {
if ("msSaveOrOpenBlob" in navigator) {
//兼容ie
let blob = new Blob([res.data], {
type: "application/vnd.ms-excel",
type: "application/vnd.ms-excel"
});
window.navigator.msSaveOrOpenBlob(blob, `${title}.xlsx`);
return;
} else {
const link = document.createElement("a");
let blob = new Blob([res.data], {
type: "application/vnd.ms-excel",
type: "application/vnd.ms-excel"
});
link.style.display = "none";
link.href = URL.createObjectURL(blob);
......
......@@ -17,6 +17,8 @@ import "vant/lib/index.css";
import "vant/lib/index.less";
import "../src/styles/vantTheme.less";
import 'video.js/dist/video-js.min.css'
import clipboard from "clipboard";
Vue.prototype.clipboard = clipboard;
Vue.use(Scroll);
......
......@@ -12,8 +12,8 @@
<van-form @submit="onSubmit">
<div class="title">登录</div>
<van-field
v-model="username"
name="username"
v-model="userName"
name="userName"
label=""
placeholder="用户名"
:rules="[{ required: true, message: '请填写用户名' }]"
......@@ -30,10 +30,10 @@
<van-button
round
block
:loading='loading'
type="info"
class="btn"
native-type="submit"
@click="$router.push('/peopleList')"
>提交</van-button>
</div>
</van-form>
......@@ -41,18 +41,48 @@
</div>
</template>
<script>
import { encryption } from "../utils/encryption.js";
export default {
name: 'login',
data () {
return {
username: '',
loading: false,
userName: '',
password: '',
};
},
methods: {
onSubmit (values) {
// 成功的回调函数
this.loading = true
console.log('submit', values);
let data = {
userName: encryption.encrypt(this.userName),
password: encryption.encrypt(this.password),
validateText: '',
validateKey: +new Date()
};
this.$API.login(data).then(res => {
this.loading = false
if (res.code == 1) {
localStorage.setItem('vd_token', res.result)
this.$toast.success({
type: 'success',
forbidClick: true,
message: '登录成功',
onClose: () => {
this.$router.push('/peopleList')
},
duration: 1500
})
}
})
},
},
mounted () {
if (localStorage.getItem('vd_token')) {
this.$router.push('/peopleList')
}
}
};
</script>
......@@ -66,15 +96,15 @@ export default {
position: absolute;
top: 30%;
transform: translateY(-50%);
.title{
.title {
text-align: center;
font-size: 20px;
margin: 20px 0;
}
.van-field{
.van-field {
// height: 44px;
}
.btn{
.btn {
height: 44px;
border-radius: 22px !important;
}
......
......@@ -9,16 +9,14 @@
:has-footer="false"
>
<!-- 列表 -->
<div
<van-list
class="list_content"
ref="scroller"
>
<van-list
v-model="loading"
:immediate-check='false'
:finished="finished"
finished-text="没有更多了"
:offset='100'
offset="100"
@load="loadMore"
>
<van-cell-group
......@@ -67,7 +65,6 @@
</van-cell>
</van-cell-group>
</van-list>
</div>
</v-content>
</div>
</template>
......@@ -94,56 +91,47 @@ export default {
pageSize: this.pageSize
}
this.finished = false;
setTimeout(() => {
this.$API.getPeopleList(data).then(res => {
this.loading = false
this.totalCount = 40
this.setNum(this.pageSize)
this.totalCount = res.object.totalCount
this.peopleList = [...this.peopleList, ...res.object.list]
if (this.peopleList.length >= this.totalCount) {
this.finished = true
}
}, 1000);
})
},
loadMore () {
this.pageNum++
this.getList()
},
setNum (num) {
for (let i = 0; i < num; i++) {
this.peopleList.push(
{
name: "test06271021",
followUpTime: '2022-08-88',
diseaseType: 'sj_wzz',
id: "62b90d53e4b0123121be58a8",
patientInfo: {
sex: 'a',
birthday: '1976-08-11',
address: '上海'
},
riskRank: 'c'
}
)
}
}
},
created () {
this.peopleList = []
this.getList()
},
activated () {
const scrollTop = this.$route.meta.scrollTop;
const $wrapper = document.querySelector('.list_content');
if (scrollTop && $wrapper) {
document.querySelector('.list_content').scrollTop = scrollTop;
const scrollTops = this.$route.meta.scrollTop;
const $content = document.querySelector('.list_content');
if (scrollTops && $content) {
this.$nextTick(() => {
var scrollTop = this.$el.querySelector('.list_content')
scrollTop.scrollTop = scrollTops - 1
})
}
},
beforeRouteLeave (to, from, next) {
const $content = document.querySelector('.list_content'); // 列表的外层容器
const scrollTop = $content ? $content.scrollTop : 0;
from.meta.scrollTop = scrollTop;
next()
},
mounted () {
},
watch: {},
filters: {
vtol (v) {
if (v) {
return [{
let item = [{
label: "无症状早癌筛查流程",
value: "sj_wzz",
},
......@@ -154,11 +142,15 @@ export default {
{
label: "院内胃癌筛查流程",
value: "sj_nj",
}].filter(e => e.value == v)[0].label
}].filter(e => e.value == v)
if (item.length > 0) {
return item[0].label
} else {
return '--'
}
} else {
return '--'
}
}
},
};
......@@ -169,10 +161,8 @@ export default {
color: #127bff;
}
.content {
}
.list_content {
height: calc(100vh - 44px);
height: 100%;
overflow: auto;
padding: 20px 0;
}
......
<template>
<div>
<van-loading
v-if="uploadLoading"
type="spinner"
class="loading_box"
vertical
text-color="#fff"
text-size='16'
>
上传中,请勿退出...
</van-loading>
<x-header :left-options="{backText: '',showBack:true}">
内镜视频
<div
class="uploadBtn"
slot="right"
>
<van-uploader>
<van-uploader
:after-read="afterRead"
:max-count='1'
accept='video/*'
>
<van-button type="text">上传文件</van-button>
</van-uploader>
</div>
......@@ -17,7 +31,16 @@
has-header
:has-footer="false"
>
<div class="list_content">
<van-list
:immediate-check='false'
class="list_content"
ref="scroller"
v-model="loading"
:finished="finished"
finished-text="没有更多了"
:offset="100"
@load="onLoad"
>
<van-row
type="flex"
justify="space-between"
......@@ -27,38 +50,41 @@
:key="index"
class="col"
>
<!-- 视频 -->
<video
<!-- 图片 -->
<div class="img_box">
<van-image
id="video"
controls
preload="auto"
loop="loop"
x5-video-player-fullscreen="true"
x5-video-orientation="portraint"
playsinline="true"
x5-video-player-type="h5"
style="object-fit:fill"
>
<!-- :poster="'https://img1.baidu.com/it/u=3009731526,373851691&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500'" -->
<source src="../assets/img/video.mp4">
</video>
:src="'https://inno.sh-sict.com/gastric/gastric-resources/' + item.coverUrl"
/>
<div class="start_icon">
<van-icon
name="play-circle-o"
size="50"
color='#e6e6e6'
@click="showVideo(item.videoName)"
/>
</div>
<div class="label">
{{item.name}}
</div>
<div class="label">
{{item.time}}
<div
class="van-ellipsis"
style="font-size:12px;"
>
{{item.videoName}}
</div>
<div class="label">
<div class="label van-ellipsis">
{{item.createTime}}
</div>
<div class="label van-ellipsis">
<a>诊断详情</a>
<a
style="color:#127BFF;"
@click="showPop(item.describe)"
@click="showPop(item)"
>点击查看</a>
</div>
</van-col>
</van-row>
</div>
</van-list>
</v-content>
<van-popup
v-model="show"
......@@ -72,7 +98,7 @@
诊断日期:
</div>
<div class="value">
{{ describe.date }}
{{ describe.diagnosisTime || '--' }}
</div>
</div>
<div class="item">
......@@ -80,7 +106,7 @@
诊断所见:
</div>
<div class="value">
{{ describe.see }}
{{ describe.finding || '--' }}
</div>
</div>
<div class="item">
......@@ -88,7 +114,7 @@
诊断结果:
</div>
<div class="value">
{{ describe.result }}
{{ describe.diagnosis || '--' }}
</div>
</div>
</div>
......@@ -96,72 +122,101 @@
</div>
</template>
<script>
// 引入
import { uploadByPieces } from '../utils/upload'
export default {
name: 'videoList',
data () {
return {
show: false,
describe: {},//诊断详情
videoList: [
{
name: '视频',
url: 'https://docs.egret.com/engine/img/engine2d.mp4',
time: '2022-01-04',
describe: {
date: '2022-01-08',
see: '大肿瘤',
result: '倒计时20天'
videoList: [],
loading: false,
finished: false,
pageNum: 1,
pageSize: 10,
totalCount: 0,
uploadLoading: false
}
},
{
name: '视频',
url: 'https://docs.egret.com/engine/img/engine2d.mp4',
time: '2022-01-04',
describe: {
date: '2022-01-08',
see: '大肿瘤',
result: '倒计时20天'
}
},
{
name: '视频',
url: 'https://docs.egret.com/engine/img/engine2d.mp4',
time: '2022-01-04',
describe: {
date: '2022-01-08',
see: '大肿瘤',
result: '倒计时20天'
methods: {
onLoad () {
if (!this.finished) {
this.pageNum++
this.getVideoList()
}
},
{
name: '视频',
url: 'https://docs.egret.com/engine/img/engine2d.mp4',
time: '2022-01-04',
describe: {
date: '2022-01-08',
see: '大肿瘤',
result: '倒计时20天'
getVideoList () {
let data = {
pageNum: this.pageNum,
pageSize: this.pageSize,
dataId: this.$route.query.id
}
this.$API.getVideoList(data).then(res => {
this.loading = false
if (res.code == 1) {
this.totalCount = res.object.totalCount
this.videoList = [...this.videoList, ...res.object.list]
}
],
if (this.videoList.length >= this.totalCount) {
this.finished = true
}
},
methods: {
jumpTo () {
console.log('双穿视屏');
})
},
showPop (data) {
this.show = true
this.describe = data
},
showVideo (url) {
this.$router.push(`/videoShow?src=${url}`)
},
afterRead (file) {
this.uploadLoading = true
// console.log(file);
uploadByPieces({
randoms: '', // 随机数,这里作为给后端处理分片的标识 根据项目看情况 是否要加
file: file.file, // 视频实体
pieceSize: 10, // 分片大小
dataId: this.$route.query.id,
success: data => {
console.log('分片上传视频成功', data)
this.uploadLoading = false
this.pageNum = 1
this.videoList = []
this.getVideoList()
},
error: e => {
console.log('分片上传视频失败', e)
}
})
},
beforeRouteEnter (to, from, next) {
from.meta.keepAlive = true
next()
},
mounted () {
this.videoList = []
this.getVideoList()
},
activated () {
const scrollTop = this.$route.meta.scrollTop;
const $content = document.querySelector('.list_content');
if (scrollTop && $content) {
this.$nextTick(() => {
console.log(scrollTop);
document.querySelector('.list_content').scrollTop = scrollTop;
})
}
},
watch: {}
beforeRouteLeave (to, from, next) {
if (to.path != '/videoShow') {
from.meta.keepAlive = false
} else
if (to.path == '/videoShow') {
from.meta.keepAlive = true
const $content = document.querySelector('.list_content'); // 列表的外层容器
const scrollTop = $content ? $content.scrollTop : 0;
from.meta.scrollTop = scrollTop;
}
next()
}
}
</script>
<style lang="scss" scoped>
......@@ -170,7 +225,8 @@ export default {
}
.list_content {
padding: 14px 14px;
height: 100%;
overflow: auto;
.col {
width: 48%;
padding: 10px;
......@@ -186,11 +242,30 @@ export default {
#video {
width: 100%;
height: 150px;
img {
display: block;
margin: 0;
padding: 0;
}
}
.uploadBtn {
transform: translateY(-16px) translatex(12px);
color: #fff;
}
.img_box {
position: relative;
.start_icon {
height: 150px;
position: absolute;
left: 0;
top: 0;
width: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
}
}
.pop_content {
padding: 20px;
.item {
......@@ -204,4 +279,17 @@ export default {
}
}
}
.loading_box {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
background: rgba(0, 0, 0, 0.5);
color: #fff;
}
</style>
\ No newline at end of file
<template>
<div class="video_box">
<div class="top">
<van-icon
name="cross"
class="closeIcon"
@click="closeVideo"
/>
</div>
<div class="video">
<video
ref="videoPlayer"
class="video-js"
id="videoplayer"
></video>
</div>
</div>
</template>
<script>
import videojs from 'video.js';
export default {
data () {
return {
player: null,
}
},
computed: {
src () {
return this.$route.query.src
}
},
methods: {
// 实例化播放器
createVideo () {
let options = {
autoplay: false,
controls: true,
sources: [
{
src: 'https://inno.sh-sict.com/gastric-api/gastric-cancer-data/file/show?videoName=' + this.src,
}
]
}
this.player = videojs('videoplayer', options, function onPlayerReady () {
console.log('onPlayerReady', this);
})
},
closeVideo () {
this.$router.go(-1)
}
},
mounted () {
this.$nextTick(() => {
this.createVideo()
})
this.$once('hook:beforeDestroy', () => {
this.player.dispose();
})
},
}
</script>
<style lang="scss" scoped>
.video_box {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
position: relative;
.top {
height: 40px;
background: #000;
text-align: right;
color: #fff;
font-size: 20px;
padding: 5px 10px 0 0;
}
.video {
flex: 1;
}
}
#videoplayer {
width: 100%;
height: 100%;
}
::v-deep .video-js .vjs-big-play-button {
font-size: 0.5rem;
width: 1.5rem;
height: 0.8rem;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
}
</style>
\ No newline at end of file
......@@ -15,15 +15,21 @@ const page = [
},
{
path: "/peopleList",
meta: { index: 1, keepAlive: true, scrollTop: 0 },
meta: { index: 2, keepAlive: true, scrollTop: 0 },
name: "peopleList",
component: () => import("@/pages/peopleList")
},
{
path: "/videoList",
meta: { index: 2 },
meta: { index: 3, keepAlive: true, scrollTop: 0 },
name: "videoList",
component: () => import("@/pages/videoList")
},
{
path: "/videoShow",
meta: { index: 3, keepAlive: false },
name: "videoShow",
component: () => import("@/pages/videoShow")
}
];
......
import md5 from "js-md5"; //引入MD5加密
import { API } from "@/axios/api"; // 这里指前端调用接口的api方法
export const uploadByPieces = ({
randoms,
file,
pieceSize = 10,
progress,
dataId,
success,
error
}) => {
// 如果文件传入为空直接 return 返回
// if (!file || !file.length) return;
console.log(file);
let fileMD5 = ""; // 总文件列表
const chunkSize = pieceSize * 1024 * 1024; // 5MB一片
const chunkCount = Math.ceil(file.size / chunkSize); // 总片数
// 获取md5
const readFileMD5 = () => {
// 读取视频文件的md5
console.log("获取文件的MD5值");
let fileRederInstance = new FileReader();
console.log("file", file);
fileRederInstance.readAsBinaryString(file);
fileRederInstance.addEventListener("load", (e) => {
let fileBolb = e.target.result;
fileMD5 = md5(fileBolb);
console.log("fileMD5", fileMD5);
console.log("文件未被上传,将分片上传");
readChunkMD5();
});
};
const getChunkInfo = (file, currentChunk, chunkSize) => {
let start = currentChunk * chunkSize;
let end = Math.min(file.size, start + chunkSize);
let chunk = file.slice(start, end);
return { start, end, chunk };
};
// 针对每个文件进行chunk处理
const readChunkMD5 = () => {
// 针对单个文件进行chunk上传
for (var i = 0; i < chunkCount; i++) {
const { chunk } = getChunkInfo(file, i, chunkSize);
console.log("总片数" + chunkCount);
console.log("分片后的数据---测试:" + i);
console.log(chunk);
uploadChunk({ chunk, currentChunk: i, chunkCount });
}
};
const uploadChunk = (chunkInfo) => {
// progressFun()
let config = {
headers: {
"Content-Type": "multipart/form-data"
}
};
// 创建formData对象,下面是结合不同项目给后端传入的对象。
let fetchForm = new FormData();
fetchForm.append("identifier", randoms);
fetchForm.append("chunkNumber", chunkInfo.currentChunk + 1);
fetchForm.append("chunkSize", chunkSize);
fetchForm.append("currentChunkSize", chunkInfo.chunk.size);
fetchForm.append("file", chunkInfo.chunk);
fetchForm.append("filename", file.name);
fetchForm.append("totalChunks", chunkInfo.chunkCount);
fetchForm.append("totalSize", chunkSize);
fetchForm.append("dataId", dataId);
// fetchForm.append('md5', fileMD5)
API.fileUpload(fetchForm, config)
.then((res) => {
console.log("分片上传返回信息:" + res);
if (res.code == 1) {
// 结合不同项目 将成功的信息返回出去,这里可变的是指 res.data[0]
success();
// 下面如果在项目中没有用到可以不用打开注释
// if (chunkInfo.currentChunk < chunkInfo.chunkCount - 1) {
// console.log("分片上传成功")
// } else {
// // 当总数大于等于分片个数的时候
// if ((chunkInfo.currentChunk + 1) == chunkInfo.chunkCount) {
// console.log("文件开始------合并成功")
// success(res.data[0])
// }
// }
} else {
console.log(res.message);
}
})
.catch((e) => {
error && error(e);
});
};
readFileMD5(); // 开始执行代码
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment