Commit df430779 by 李乾广

千喜鹤h5项目

1 parent 9e26f6e8
node_modules
.DS_Store .DS_Store
dist
dist-ssr
*.local
\ No newline at end of file \ No newline at end of file
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# project # vion-player
> A Vue.js project ## Project setup
```
## Build Setup yarn install
```
``` bash
# install dependencies
npm install
# serve with hot reload at localhost:8080 ### Compiles and hot-reloads for development
npm run dev ```
yarn serve
```
# build for production with minification ### Compiles and minifies for production
npm run build ```
yarn build
```
# build for production and view the bundle analyzer report ### Lints and fixes files
npm run build --report ```
yarn lint
``` ```
For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
#萤石播放视频截图功能需要找到源码,把下载动作拦截掉,方法是JS_CapturePicture(),重排代码后位置大概在48405行,z.oTool.downloadFile()方法注释掉
#如果萤石视频流切换路由时,视频流没有停掉,是因为js中代码一个判断报错,将代码21403行,方法hide中代码换成最简单的获取dom方法 document.getElementById(this.jSPlugin.id, "-ez-ptz-item").style = "display: none";
#h5端萤石视频截图报错,需要将预计59500多行的this.getPic方法中的var a中的 rect:this.stYUVRect 改为 rect: {...this.stYUVRect}
\ No newline at end of file \ No newline at end of file
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,viewport-fit=cover,initial-scale=1.0,maximum-scale=1.0, user-scalable=no">
<title>视频巡店</title>
</head>
<body>
<div id="app" class="fullPage"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
{ {
"name": "vite", "name": "vion-player",
"version": "0.0.0", "version": "0.1.0",
"private": true,
"scripts": { "scripts": {
"dev": "vite", "serve": "vue-cli-service serve",
"build": "vite build" "build": "vue-cli-service build",
"lint": "vue-cli-service lint"
}, },
"dependencies": { "dependencies": {
"@vitejs/plugin-vue-jsx": "^1.3.9", "core-js": "^3.8.3",
"axios": "^0.26.1", "element-ui": "^2.15.14",
"blueimp-md5": "^2.16.0", "vue": "^2.6.14",
"echarts": "^5.3.2", "vue-router": "^3.5.1"
"ezuikit-js": "^7.7.0",
"jquery": "^3.7.1",
"moment": "^2.29.4",
"postcss-px-to-viewport": "^1.1.1",
"rollup-plugin-copy": "^3.4.0",
"uglifyjs-webpack-plugin": "^1.1.1",
"url-param-parser": "^0.0.2",
"vant": "^3.6.12",
"vconsole": "^3.14.6",
"vue": "^3.0.6",
"weixin-js-sdk": "^1.6.0"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^1.2.2", "@babel/core": "^7.12.16",
"@vue/compiler-sfc": "^3.0.11", "@babel/eslint-parser": "^7.12.16",
"less": "^4.1.1", "@vue/cli-plugin-babel": "~5.0.0",
"vite": "^2.2.4", "@vue/cli-plugin-eslint": "~5.0.0",
"vite-plugin-style-import": "^0.10.0" "@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"@vue/eslint-config-standard": "^6.1.0",
"eslint": "^7.32.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-vue": "^8.0.3",
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"vue-template-compiler": "^2.6.14"
} }
} }
No preview for this file type
This diff could not be displayed because it is too large.
No preview for this file type
This diff could not be displayed because it is too large.
No preview for this file type
<template> <template>
<div class="fullPage touchmove"> <div id="app">
<div v-if="picUrl"> <router-view/>
<!-- <img mode="widthFix" style="position:relative;width:100vw;height: 50vwpx;" :src="picUrl"/> -->
<canvas id="painter" ref="captureCanvas"></canvas>
<div class="template-name-box">
<div class="template-name-content">
<span class="template-name-title">模板名称:</span>
<van-cell :title="templateNameDefault" @click="show = true" is-link />
<van-popup v-model:show="show" position="bottom">
<van-picker :columns="templateNameList" @confirm="onConfirm" @cancel="onCancel" />
</van-popup>
</div>
<van-button class="template-btn" plain type="primary" size="small" @click="templateClick"> + 问题项</van-button>
</div>
<div class="template-select-box" v-if="checkboxRefsShow.length > 0">
<div class="template-select-list">
<van-tag class="template-select-one" v-for="(item, index) in checkboxRefsShow" :key="index" closeable size="large" type="primary" @close="deleteTemplate(item,index)">
{{item.name}}
</van-tag>
</div>
</div>
<van-popup v-model:show="templateDialogShow" position="bottom" class="template-list-model" closeable round>
<div class="template-list-box">
<div class="template-list-title">添加问题项</div>
<div class="template-list">
<van-checkbox-group shape="square" v-model="checked" ref="checkboxGroup">
<van-cell-group inset>
<van-cell v-for="(item, index) in templateItemList" center clickable :key="index" :title="item.name" @click="toggle(index)" >
<template #right-icon>
<van-checkbox :name="item.id" :ref="el => checkboxRefs[index] = el" @click.stop />
</template>
</van-cell>
</van-cell-group>
</van-checkbox-group>
</div>
<van-button class="template-list-submit" round block type="primary" @click="templateSubmit">确认</van-button>
</div>
</van-popup>
<!-- <div class="itemList" id="itemList">
<van-checkbox-group v-model="checked">
<van-cell-group inset>
<van-cell v-for="(item, index) in templateItemList" clickable center :key="index" :title="'['+item.score+']'+item.name" :label="item.intro" @click="toggle(index)">
<template #right-icon>
<van-checkbox :name="item.id" :ref="el => checkboxRefs[index] = el" @click.stop />
</template>
</van-cell>
</van-cell-group>
</van-checkbox-group>
</div> -->
<div class="formBox">
<van-field v-model="message" rows="2" autosize label="备注" type="textarea" placeholder="请输入备注" />
<van-field name="radio" label="是否需要整改">
<template #input>
<van-radio-group v-model="isRectify" direction="horizontal">
<van-radio name="1">需要</van-radio>
<van-radio name="2">不需要</van-radio>
</van-radio-group>
</template>
</van-field>
<van-field
v-show="isRectify==1"
v-model="rectificationUserName"
is-link
readonly
name="picker"
label="整改人"
placeholder="点击选择整改人"
@click="showRectification = true"
/>
<van-popup v-model:show="showRectification" position="bottom">
<van-picker
:columns="userNameList"
@confirm="onUserConfirm"
@cancel="showRectification = false"
/>
</van-popup>
<div style="padding:15px;">
<van-button round block type="primary" @click="submitContent">提交</van-button>
</div>
</div>
</div>
<div v-else>
<livePlayer ref="livePlayerRef" :params="paramObj"></livePlayer>
<div class="tour-btns" v-if="paramObj.type=='titem'">
<van-button @click="navBackTour" type="primary">返回上一页</van-button>
<van-button @click="goCaptureImg" type="primary">确认并截图</van-button>
</div>
<div class="tour-btns" v-else-if="paramObj.type=='view'">
<van-button block @click="navBack" type="primary">查看其他监控点</van-button>
</div>
<div class="tour-btns1" v-else>
<div class="box">
<span @click="navBack">{{decodeURIComponent(paramObj.name)}}
<van-icon class="icon" name="play" />
</span>
</div>
<div class="box box1">
<span v-if="bookmark" @click="delCollectGate">
<van-icon class="iconMargin" color="#F7B500" name="star" />收藏
</span>
<span v-else @click="collectGate">
<van-icon class="iconMargin" name="star-o" />收藏
</span>
<span @click="goCaptureImg">
<van-icon class="iconMargin" name="photograph" />巡检
</span>
</div>
</div>
<!-- 监控点选择器 -->
<van-popup v-model:show="pointPopupShow" round position="bottom">
<van-picker
:title="paramObj.mallName"
:columns="pointList"
:option-height="40"
@confirm="pointConfirm"
@cancel="pointPopupShow = false"
/>
</van-popup>
</div>
</div> </div>
</template> </template>
<script setup>
import {
reactive,
ref,
onMounted,
getCurrentInstance
} from 'vue';
import {
Toast
} from 'vant';
import livePlayer from '@/components/livePlayer.vue';
import shopTour from '@/components/shopTour.vue';
//import vconsole from 'vconsole';
if (process.env.NODE_ENV !== 'production') {
//new vconsole();
}
/*获取 Url 参数 S*/
import parse from 'url-param-parser';
let url = 'https://store.keliuyun.com/video/?userId=8840&atoken=ab680ffc-2e74-482b-a180-ba27c70f2b56&type=undefined&id=91&channelid=660&platform=2&name=海康GB-01&mallId=9219&mallName=国标设备测试&bookmark=false&channelNo=1&deviceSerial=33011015992467054043:33010285991117359447&accountId=337'
const paramObj = parse(url).search || {}
// const paramObj = parse(window.location.href).search || {}
/********************************/
document.title = decodeURIComponent(paramObj.name);
window.localStorage.setItem('atoken', paramObj.atoken);
window.localStorage.setItem('lang', 'zh_CN');
/*获取 Url 参数 E*/
import tourApi from '@/api';
//var data = reactive(v);
const dataURLtoFile = (dataurl, filename, filetype)=> {
var arr = dataurl.split(","),
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {
type: filetype
});
}
const navBack = () => {
pointPopupShow.value = true
console.log(paramObj)
// wx.miniProgram.redirectTo({
// url: `/pages/tour/gate/index?type=${paramObj.type}&atoken=${paramObj.atoken}&userId=${paramObj.userId}&id=${paramObj.id}&channelid=${paramObj.channelid}&platform=${paramObj.platform}&mallId=${paramObj.mallId}&name=${paramObj.name}`
// });
};
// 获取检查项列表
const pointPopupShow = ref(false)
const pointList = ref([])
const reqPatrolGateList = () => {
tourApi.getPatrolGateList({
pageNum: 1,
pageSize: 99999,
mallId: paramObj.mallId,
}).then(res => {
console.log(res)
if (res.data.code == 200) {
let list = res.data.data&&res.data.data.list?res.data.data.list:[];
list.forEach((one)=>{
one.text = one.name
one.value = one.id
})
pointList.value = list;
console.log(list)
console.log(pointList.value)
}
})
}
const pointConfirm = (row) => {
console.log(row)
paramObj.channelid = row.channelId
paramObj.id = row.id
paramObj.name = row.name
paramObj.bookmark = row.bookmark
pointPopupShow.value = false
// livePlayerRef.value.playerEz.play();
livePlayerRef.value.loadTourVideo();
}
const navBackTour = () => {
wx.miniProgram.navigateBack();
}
const bookmark = ref(paramObj.bookmark)
const collectGate = () => {
tourApi.setBookmark({
userId: paramObj.userId,
patrolGateIds: [paramObj.id]
}).then(res => {
if (res.data.code == 200) {
bookmark.value = true;
return Toast.success('收藏成功');
}
})
}
const delCollectGate = () => {
tourApi.delBookmark({
userId: paramObj.userId,
patrolGateIds: [paramObj.id]
}).then(res => {
if (res.data.code == 200) {
bookmark.value = false;
return Toast.success('取消收藏成功');
}
})
}
const show = ref(false);
const showPopup = () => {
show.value = true;
};
const checked = ref([]);
const onConfirm = (value, index) => {
templateNameDefault.value = value;
checkboxRefsShow.value = [];
checkboxRefs.value = [];
checked.value = []
if (index > 0) {
getPatrolTemplateOne(templateList.value[index].id)
} else {
templateItemList.value = []
associateData.value.forEach(item => {
templateItemList.value.push(...item.sopProjects)
})
}
show.value = false;
};
const onCancel = () => {
show.value = false;
}
const checkboxRefs = ref([]);
const checkboxRefsShow = ref([]);
const templateClick = (val) => {
templateDialogShow.value = true;
}
const toggle = (index) => {
checkboxRefs.value[index].toggle();
}
const templateSubmit = (index) => {
templateDialogShow.value = false;
if(checked.value && checked.value.length>0){
checkboxRefsShow.value = []
checked.value.forEach(item=>{
let sopItem = templateItemList.value.find(childItem => item==childItem.id);
checkboxRefsShow.value.push({
"id": sopItem.id,
"name": sopItem.name,
})
})
}
}
const deleteTemplate = (item,index) => {
checkboxRefsShow.value.splice(index,1)
checked.value.splice(index,1)
}
const message = ref();
const isRectify = ref("1")
const showRectification = ref(false)
const rectificationUserName = ref('')
const onUserConfirm = (value) => {
showRectification.value = false;
rectificationUserName.value = value
};
const submitContent = () => {
let base64Str = dataURLtoFile(captureCanvas.value.toDataURL('image/jpeg'), new Date().getTime(), 'image/jpeg')
let formData = new FormData();
formData.append('accountId', paramObj.accountId)
formData.append('mallId', paramObj.mallId)
formData.append('gateId', paramObj.id)
formData.append('patrolType', 1)
let sops = []
if(checked.value && checked.value.length>0){
checked.value.forEach(item=>{
let sopItem = templateItemList.value.find(childItem => item==childItem.id);
sops.push({
"id": sopItem.id,
"status": 0,
"score": sopItem.score
})
})
formData.append('sops', JSON.stringify(sops))
}else{
return Toast.fail('请选择检查项');
}
if (message.value) {
formData.append('remark', message.value)
}
if(isRectify.value==1){
if(rectificationUserName.value){
let user = userList.value.find(item => item.name==rectificationUserName.value);
formData.append('handler', user.id)
}else{
return Toast.fail('请选择整改人');
}
} else {
formData.append('handler', '')
}
formData.append('pic', base64Str)
tourApi.confirmPatrolRecord(formData, {
headers: {
'Content-type': 'application/x-www-form-urlencoded;charset=utf-8' //multipart/form-data; charset=utf-8
}
}).then(res=>{
let result = res.data;
if (result.code == '200'){
Toast.success('提交成功');
setTimeout(()=>{
message.value = '';
rectificationUserName.value = '';
checked.value = [];
checkboxRefsShow.value = [];
checkboxRefs.value = [];
let context = captureCanvas.value.getContext("2d")
context.clearRect(0, 0, window.innerWidth, window.innerWidth/1.78)
picUrl.value = '';
console.log(livePlayerRef.value.playerEz)
livePlayerRef.value.playerEz.play();
},1000)
}else{
return Toast.fail(result.msg);
}
})
}
<script>
const userList = ref([]); export default {
const userNameList = ref([]); name: 'App',
const getUserList = () => { }
userList.value = []
userNameList.value = []
tourApi.getUsers({
mallId: paramObj.mallId
}).then(data => {
let result = data.data
if (result.data && result.data.length) {
result.data.forEach(item => {
item.name = item.realName + '(' + item.loginName + ')';
userNameList.value.push(item.realName + '(' + item.loginName + ')')
})
}
userList.value = result.data
})
}
const livePlayerRef = ref()
const picUrl = ref('')
const captureCanvas = ref('')
// 获取检查项
const templateList = ref([]);
const templateNameList = ref([]);
const templateNameDefault = ref();
const tempalteId = ref()
// 单个模板检查项
const templateItemList = ref([]);
// 检查项弹框显示
const templateDialogShow = ref(false);
const getPatrolTemplateList = () => {
tourApi.getPatrolTemplateListFun({
accountId: paramObj.accountId,
pageSize: 999,
}).then(res => {
let result = res.data;
if (result.code == 200) {
templateList.value = result.data.list;
if (templateList.value.length) {
tempalteId.value = templateList.value[0].id
getPatrolTemplateOne(templateList.value[0].id)
// templateList.value.unshift({
// name: '全部',
// id: ''
// })
templateNameList.value = []
templateList.value.forEach(item => {
templateNameList.value.push(item.name)
})
templateNameDefault.value = templateList.value[0].name;
}
}
})
}
// 获取单个模板检查项
const getPatrolTemplateOne = (val) => {
tourApi.getPatrolTemplateOne({
id: val,
}).then(res => {
let result = res.data;
if (result.code == 200) {
templateItemList.value = result.data.sopProjects || [];
}
})
}
// 获取关联的SOP
const associateData = ref([])
const getAssociateList = (record) => {
associateData.value = [];
tourApi.getPatrolSopTypeTree({
accountId: paramObj.accountId,
system: 0
}).then(data => {
let result = data.data;
if (result.code == '200') {
let tableData = result.data
tableData.forEach((item, index) => {
if (item.sopProjects.length > 0) {
item.key = 1000 + item.id
let sopProjects = JSON.parse(JSON.stringify(item.sopProjects))
item.sops = sopProjects
item.len = sopProjects.length
item.choiceNum = 0
associateData.value.push(item)
}
})
}
})
}
const pictureBtn = () => {
getPatrolTemplateList()
getAssociateList()
getUserList()
Toast.loading({
duration: 0,
message: '视频截图中···',
forbidClick: true,
});
tourApi.getCapture({id:paramObj.channelid}).then(res=>{
if(res.status!=200){
return Toast.fail(res.data.msg);
}
picUrl.value = res.data.data;
Toast.clear();
if(paramObj.type!='titem'){
// picUrl.value = 'https://store.keliuyun.com/images/patrol/capture/20230825/ecd2a635-84af-4968-bc30-1af130460d12.jpg'
livePlayerRef.value.playerEz.stop();
let image = new Image()
image.src = 'https://store.keliuyun.com/images/'+ picUrl.value;
image.style.width = window.innerWidth + 'px';
let heightC = window.innerWidth / 1.78
image.style.height = heightC + 'px'
image.crossOrigin = 'Anonymous'
image.onload = () => {
captureCanvas.value.width = window.innerWidth;
captureCanvas.value.height = heightC;
let ctx = captureCanvas.value.getContext("2d");
ctx.drawImage(image, 0, 0, window.innerWidth, heightC);
capture()
}
// wx.miniProgram.redirectTo({
// url: `/pages/tour/index/index?action=capture&picUrl=${picUrl}&id=${paramObj.id}&channelid=${paramObj.channelid}&mallId=${paramObj.mallId}&title=${paramObj.name}&atoken=${paramObj.atoken}&userId=${paramObj.userId}`
// });
}else{
/***********巡店详情截图****************/
wx.miniProgram.navigateTo({
url: `/pages/tour/titemDetail/index?action=capture&picUrl=${picUrl}&id=${paramObj.tid}`
});
}
})
};
const locHistory = ref([]);
const lastLoc = ref();
const isMouseDown = ref(false);
const windowToCanvas = function(x, y) {
var bbox = captureCanvas.value.getBoundingClientRect(); //获取canvas的位置信息
return {
x: Math.round(x - bbox.left),
y: Math.round(y - bbox.top)
} //返回当前鼠标相对于canvas的位置
}
const capture = function() {
// 绘制
var context = captureCanvas.value.getContext("2d");
captureCanvas.value.addEventListener('touchstart', function(e) {
e.preventDefault();
isMouseDown.value = true;
lastLoc.value = windowToCanvas(e.touches[0].clientX, e.touches[0].clientY)
locHistory.value.push({
x: lastLoc.value.x,
y: lastLoc.value.y,
})
console.log(locHistory.value)
})
captureCanvas.value.addEventListener('touchmove', function(e) {
e.preventDefault();
if (isMouseDown.value) {
moveStroke({
x: e.touches[0].clientX,
y: e.touches[0].clientY
}, context)
}
})
captureCanvas.value.addEventListener('touchend', function(e) {
locHistory.value.push({
x: lastLoc.value.x,
y: lastLoc.value.y,
})
isMouseDown.value = false;
})
}
const calcDistance = function(loc1, loc2) {
return Math.sqrt((loc1.x - loc2.x) * (loc1.x - loc2.x) + (loc1.y - loc2.y) * (loc1.y - loc2.y)) //通过起始结束坐标x,y值计算路程长度
}
const moveStroke = function(point, context) {
var curLoc = windowToCanvas(point.x, point.y)
var curTimestamp = new Date().getTime();
var s = calcDistance(curLoc, lastLoc.value)
var lineWidth = 3
//draw
context.beginPath()
context.moveTo(lastLoc.value.x, lastLoc.value.y)
context.lineTo(curLoc.x, curLoc.y)
locHistory.value.push({
x: curLoc.x,
y: curLoc.y,
})
context.lineWidth = 3
context.strokeStyle = '#FF0000';
context.lineCap = "round"
context.linJoin = "round"
context.stroke();
//每次过程结束时,将结束值赋给初始值,一直延续
lastLoc.value = curLoc
}
// 前端截图
const goCaptureImg = () => {
// livePlayerRef.value.captureImg(paramObj)
getPatrolTemplateList()
getAssociateList()
getUserList()
Toast.loading({
duration: 0,
message: '视频截图中···',
forbidClick: true,
});
var capturePicturePromise = livePlayerRef.value.playerEz.capturePicture('default',(data) => {
let imgData = data.base64
let reg = new RegExp('data:image/jpeg;base64,');
let pic = imgData.replace(reg,'')
tourApi.uploadScreenshot({gateId: paramObj.id,pic:pic}).then(res => {
console.log(res)
let result = res.data;
if (result.code == 200) {
Toast.success('截图成功');
pictureProcess(result.data.pic)
}else{
Toast.success(result.msg);
}
})
});
}
const pictureProcess = (imgUrl) => {
picUrl.value = imgUrl;
Toast.clear();
if(paramObj.type!='titem'){
// picUrl.value = 'https://store.keliuyun.com/images/patrol/capture/20230825/ecd2a635-84af-4968-bc30-1af130460d12.jpg'
livePlayerRef.value.playerEz.stop();
let image = new Image()
image.src = 'https://store.keliuyun.com/images/'+ picUrl.value;
image.style.width = window.innerWidth + 'px';
let heightC = window.innerWidth / 1.78
image.style.height = heightC + 'px'
image.crossOrigin = 'Anonymous'
image.onload = () => {
captureCanvas.value.width = window.innerWidth;
captureCanvas.value.height = heightC;
let ctx = captureCanvas.value.getContext("2d");
ctx.drawImage(image, 0, 0, window.innerWidth, heightC);
capture()
}
// this.$refs.livePlayerRef.value.playerEz.stop();
// wx.miniProgram.redirectTo({
// url: `/pages/tour/index/index?action=capture&picUrl=${picUrl}&id=${paramObj.id}&channelid=${paramObj.channelid}&mallId=${paramObj.mallId}&title=${paramObj.name}&atoken=${paramObj.atoken}&userId=${paramObj.userId}`
// });
}else{
/***********巡店详情截图****************/
wx.miniProgram.navigateTo({
url: `/pages/tour/titemDetail/index?action=capture&picUrl=${picUrl}&id=${paramObj.tid}`
});
}
};
onMounted(() => {
reqPatrolGateList()
})
</script> </script>
<style scoped lang="less">
.tour-btns {
display: flex;
justify-content: space-between;
padding: 20px 2vw 0;
--van-button-border-radius: 60px;
:deep(.van-button) {
margin-bottom: 20px;
border-radius: 60px;
width: 47vw;
&.van-button--block {
width: 100%;
}
}
}
.tour-btns1 {
display: flex;
background: #E6EDFF;
height: 15vw;
line-height: 15vw;
padding: 0 20px;
.box {
display: inline-block;
flex: 1;
}
.box1 {
text-align: right;
span {
margin-left: 20px;
}
}
.icon {
transform: rotate(90deg);
}
}
.iconMargin {
margin-right: 10px;
}
.itemList {
overflow: auto;
height: 50%;
}
:deep(.van-cell-group--inset) {
margin: 0;
}
.template-select-box{
background: #fff;
}
.template-select-list{
padding:30px 0px 10px;
margin:0 30px;
border-bottom: 1px solid var(--van-cell-border-color);
.template-select-one{
margin: 0 20px 20px 0;
padding: 1.8vw;
/deep/.van-tag__close{
margin-left: 10px;
}
}
}
.template-name-box{
display: flex;
align-items: center;
justify-content: space-between;
background:#fff;
padding: 0 30px;
border-bottom: 1px solid var(--van-cell-border-color);
}
.template-name-content{
display: flex;
align-items: center;
}
.template-name-title{
width: 5em;
min-width: 5em;
font-size: var(--van-cell-font-size);
color: var(--van-field-label-color);
}
.template-btn{
width: 6em;
}
.template-name-content /deep/.van-cell{
padding-left: 0px;
}
.template-list-model{
.template-list-box{
width: calc(100vw - 0px);
height: calc(80vh - 0px);
padding: 30px;
background: #fff;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
.template-list-title{
font-size: var(--van-font-size-lg);
line-height: var(--van-font-size-lg);
margin-bottom: 30px;
}
.template-list{
height: 62vh;
overflow: auto;
}
.template-list-submit{
margin-top: 30px;
}
}
}
<style>
html, body, #app {
height: 100%;
margin: 0px;
}
</style> </style>
import axios from 'axios'
import md5 from 'blueimp-md5'
import { param2 } from '@/utils'
import { Toast } from 'vant';
//const baseURL = 'https://store.keliuyun.com/report';
//const baseURL = 'https://mall.keliuyun.com';
const baseURL = 'https://store.keliuyun.com';
const Axios = axios.create({
baseURL: baseURL, // 因为我本地做了反向代理
timeout: 0,
// responseType: "json",
// changeOrigin: true,//允许跨域
withCredentials: true, // 是否允许带cookie这些
headers: {
"Content-Type": "application/json;charset=UTF-8"
// 'Content-Type': 'application/x-www-form-urlencoded'
}
})
let store = {
source: {
token: null,
cancel: null
}
}
// 请求拦截器
Axios.interceptors.request.use(
config => {
const suffix = '4c413628731691abc99eb2fca5f69aab'
const { method, params, data, url } = config
let language = localStorage.getItem('lang'),
aToken = localStorage.getItem('atoken');
if (language) {
let languageObj = {
'mall_CN': 'zh-CN,zh;q=0.9',
'zh_CN': 'zh-CN,zh;q=0.9',
'en_US': 'en-US,en;q=0.5',
'zh_TW': 'zh-TW,zh;q=0.3',
// 'zh_ar': 'zh-AR,zh;q=0.9'
}
languageObj[language] && (config.headers['Accept-Language'] = languageObj[language]);
}
aToken && (config.headers.Authorization = aToken);
config.cancelToken = store.source.token
const signalStr = method.toUpperCase() +
(params ? param2(params) : '') +
(data ? JSON.stringify(data) : '') +
suffix + (config.headers.Authorization ? config.headers.Authorization : '');
const hashSignature = md5(signalStr)
config.headers['signature'] = hashSignature
return config;
}, error => {
console.error(error);
return Promise.reject(error.data.msg)
}
)
Axios.interceptors.response.use(
res => {
if (res.data && !res.data.success) {
if (res.data.ecode && res.data.ecode != 200) {
Toast.fail(res.data.enote)
console.error(res.data.enote)
return ;
} else {
// 非标准返回体
if (res.status == 200) {
return res;
}
}
if (res.data.code == 500) {
console.error(res.data.msg)
}
return Promise.reject(res.data.msg);
} else if (!res.data && res.status == 200) {
return res;
} else if (res.data.success && res.config.method != 'get') {
//
}
return res;
}
)
export default function(method, url, data = null, config = null, bodyDelete) {
method = method.toLowerCase()
if (method == 'post') {
return Axios.post(url, data, config)
} else if (method == 'get') {
let defaultParam = {
_t: Date.parse(new Date()) / 1000
}
return Axios.get(url, { params: {...defaultParam, ...data }, config })
} else if (bodyDelete) {
return Axios.delete(url, { data: data }, config)
} else if (method == 'delete') {
return Axios.delete(url, { params: data }, config)
} else if (method == 'put') {
return Axios.put(url, data, config)
} else {
console.error('unknown method' + method)
return false
}
}
\ No newline at end of file \ No newline at end of file
import req from '@/api/http.js'
const tourApi = {
getLiveAddress(params,config) {
return req('get', `/patrol/patrolDeviceChannel/getLiveAddress/${params.id}`, params, config)
},
getLiveInfo(params,config){
return req('get', `/patrol/patrolDeviceChannel/getLiveInfo/${params.id}`, params, config)
},
// 截图
getCapture(params,config) {
return req('get', `/patrol/patrolDeviceChannel/capture/${params.id}`, params, config)
},
// 提交巡店记录
submitPatrolRecord(params,config) {
return req('post', `/patrol/patrolRecord`, params, config)
},
setBookmark(params,config) {
return req('post', `/patrol/patrolGate/bookmark`, params, config)
},
delBookmark(params,config) {
return req('post', `/patrol/patrolGate/unbookmark`, params, config)
},
// 获取监控点
getPatrolGateList(params,config) {
return req('get', `/patrol/patrolGate/list`, params, config)
},
uploadScreenshot(params,config){
return req('post', `/patrol/b-patrol-screenshot`, params, config)
},
// 获取抓拍图
getScreenshotList(params,config){
return req('GET', `/b-patrol-screenshot/list`, params, config)
},
// 巡店模板
getPatrolTemplateListFun(params,config){
return req('get', `/patrol/b-patrol-template/list`, params, config)
},
// 查询单个模板
getPatrolTemplateOne(params,config){
return req('get', `/patrol/b-patrol-template/${params.id}`, params, config)
},
getPatrolSopTypeTree(params,config) {
return req('get', `/patrol/patrolSopType/tree`, params, config)
},
getUsers(params,config) {
return req('get', `/patrol/s-user/mall/${params.mallId}`)
},
//提交巡店记录
confirmPatrolRecord(params,config) {
return req('post', `/patrol/patrolRecord`, params, config)
},
// 云控制
ptzStart(params,config) {
return req('PUT', `/patrol/patrolDeviceChannel/ptzStart`, params, config)
},
ptzStop(params,config) {
return req('PUT', `/patrol/patrolDeviceChannel/ptzStop`, params, config)
},
}
export default tourApi;
\ No newline at end of file \ No newline at end of file
<template>
<div class="videoWrap">
<div v-show="platform==1" class="video-box">
<canvas class="box" id="canvasVideo"></canvas>
</div>
<div v-show="platform==2" class="video-box">
<div class="box" id="my-video"></div>
<!-- <div class="cameraLeftTool" v-if="true||pantileIconShow">
<p class="scaleshot scaleBig" @mousedown='setControl(8,currObj)' @mouseup='stopControl(8,currObj)'><i class="el-icon-plus"></i></p>
<p class="scaleshot scaleSmall" @mousedown='setControl(9,currObj)' @mouseup='stopControl(9,currObj)'><i class="el-icon-minus"></i></p>
</div> -->
<div class="video-operate-box">
<div class="video-operate-one" :class="[videoType == 'shishi'?'video-operate-one-show':'']" @click="videoTypeChange('shishi')">实时</div>
<div class="video-operate-one" :class="[videoType == 'huifang'?'video-operate-one-show':'']" @click="videoTypeChange('huifang')">回放</div>
</div>
<div class="video-time-box" v-if="videoType == 'huifang'">
<span class="video-time-title">回放开始时间:</span>
<span class="video-time-text" @click="videoTimePopupShow = true">{{videoTimeShow}}</span>
<van-icon class="icon" name="play" />
</div>
<van-popup v-model:show="videoTimePopupShow" round position="bottom">
<van-datetime-picker v-model="videoTime" type="datetime" title="回放开始时间" :min-date="minDate" :max-date="maxDate" @confirm="videoTimeConfirm" @cancel="videoTimePopupShow = false"/>
</van-popup>
</div>
<!-- <div class="tour-btns" v-else>
<van-button block @click="navBack" type="primary">查看其他监控点</van-button>
</div> -->
</div>
</template>
<script>
import { defineComponent,reactive,toRefs} from 'vue'
import {Toast} from 'vant';
import EZUIKit from 'ezuikit-js'
import SLPlayer from '@/static/js/slplayer';
import tourApi from '@/api';
import moment from 'moment'
export default defineComponent({
props: {
params: Object
},
watch:{
params: {
handler: function(val) {
console.log(val)
this.loadTourVideo();
},
// deep: true
},
},
data() {
return {
minDate: new Date(2020, 0, 1),
maxDate: new Date(),
videoTime: new Date(moment().subtract(1, 'hours').format('YYYY-MM-DD HH:mm:00')),
videoTimeShow:moment().subtract(1, 'hours').format('YYYY-MM-DD HH:mm:00'),
palyUrl: '',
player: '',
playerIndex: 0,
playerEz: '',
videoType:'shishi',
videoInfo:{},
videoTimePopupShow:false,
pantileIconShow:false,
}
},
methods: {
createPlayer(row) {
this.playerIndex++;
let that = this;
that.Module = {
/* ************************************ */
// 定义视频画布
canvas: document.getElementById("canvasVideo"),
/* ************************************ */
// 设置相应的事件回调
onStart: function() {
console.log("onStart...")
},
onEnd: function() {
console.log("onEnd...")
},
onError: function(code, err) {
alert('error: ', code, err)
console.log('error: ', code, err);
},
onVideoStart: function() {
console.log('onVideoStart。。。');
},
// 录像回放中返回时间刻度
onPlayTime: function(ts) {
if (ts == 0) return;
var date = new Date(ts * 1000); //如果date为10位不需要乘1000
var Y = date.getFullYear() + '-';
var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
var D = (date.getDate() < 10 ? '0' + (date.getDate()) : date.getDate()) + ' ';
var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';
var m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':';
var s = (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds());
var timestamp = Y + M + D + h + m + s;
}
}
SLPlayer(that.Module).then(function(obj) {
that.loading = false
that.player = obj;
setTimeout(() => {
that.player.start(row);
Toast.clear();
}, 1000)
});
},
playerVideo(data) {
this.pantileIconShow = false
this.videoInfo = data
this.palyUrl = data.liveAddress;
let atoken = data.accessToken;
// 拾联视频
if (this.platform == 1) {
// 清除萤石云视频
if (this.playerEz) {
this.playerEz.stop()
let canvasVideo = document.getElementById('my-video')
canvasVideo.innerHTML = ''
}
if (this.playerIndex > 0) {
// 暂停上次播放并重新开始新的视频
this.player.stop();
setTimeout(() => {
this.player.start(this.palyUrl);
Toast.clear();
}, 100)
} else {
this.createPlayer(this.palyUrl);
}
} else {
// 萤石云视频
if (this.playerEz) {
this.playerEz.stop().then(()=>{
console.log(this.palyUrl)
this.playerEz.play(this.palyUrl);
});
}else{
// 回放:3ffaebe2ae04479cab85e6909c051878
// 开始萤石云视频
console.log(this.palyUrl)
this.playerEz = new EZUIKit.EZUIKitPlayer({
id: "my-video", // 视频容器ID
accessToken: atoken,
url: this.palyUrl,
template: '689f69d9f89a4c6db5b78a4169976aea', //simple - 极简版;standard-标准版;security - 安防版(预览回放);voice-语音版mobileLive-手机
autoplay: true,
width: window.innerWidth,
height:window.innerWidth*1080/1920,
})
setTimeout(()=>{
this.addBigSmallBtn()
},5000)
}
Toast.clear();
}
},
loadTourVideo() {
console.log(111)
Toast.loading({
duration:0,
message: '加载中···',
forbidClick: true,
});
console.log(this.params)
let {channelid,platform} = this.params;
console.log({ id: channelid, protocol:platform == 2 ? 1 : 2, quality: 1 })
tourApi.getLiveAddress({ id: channelid, protocol:platform == 2 ? 1 : 2, quality: 1 }).then(res => {
var data = res.data;
console.log(data)
if (data.code != 200) {
Toast.fail({
message: data.msg,
onClose() {
wx.miniProgram.navigateBack()
}
});
} else {
this.playerVideo(data.data);
}
})
},
// 获取截图
captureImg(obj){
console.log(obj)
if(this.playerEz){
var capturePicturePromise = this.playerEz.capturePicture(`${new Date().getTime()}`);
capturePicturePromise.then((data) => {
console.log(data)
let imgData = data.data.base64
let reg = new RegExp('data:image/jpeg;base64,');
let pic = imgData.replace(reg,'')
tourApi.uploadScreenshot({gateId: obj.id,pic:pic}).then(res => {
let result = res.data;
if (result.code == 200) {
Toast.success('截图成功');
let imgUrl = result.data.pic
}else{
Toast.success(result.msg);
}
})
})
}
},
// 获取截图列表
getCaptureImg(obj){
tourApi.getScreenshotList({
userId: obj.userId,
accountId: obj.accountId,
pageNum:1,
pageSize:99999,
}).then(res=>{
console.log(res)
let result = res.data;
if(result.code==200){
// this.screenImgTotal = result.data.total;
// this.screenImgList = result.data.list;
}
})
},
// 实时回放切换
videoTypeChange(val) {
this.videoType = val
this.getCurrTime(val == 'shishi')
},
getCurrTime(val){
this.pantileIconShow = false
if(this.playerEz){
if(val){
// if(document.getElementById('my-video-headControl')){
// document.getElementById('my-video-headControl').style.display='none'
// }
// document.getElementById('my-video-headControl').style.display='none'
// document.getElementById('my-video-ez-iframe-footer-container').style.display='none'
// 实时
this.playerEz.changePlayUrl({
type:'live',
template:'689f69d9f89a4c6db5b78a4169976aea',
url: this.palyUrl,
accessToken: this.videoInfo.accessToken,
autoplay: true,
width: window.innerWidth,
height:window.innerWidth*1080/1920,
}).then(()=>{
// this.playerEz.play()
this.playerEz.Theme.changeTheme("689f69d9f89a4c6db5b78a4169976aea")
});
} else {
// 回放
this.videoBack()
}
}
},
// 回放视频
videoBack() {
this.playerEz.changePlayUrl({
type:'rec',
autoplay: true,
template:'3ffaebe2ae04479cab85e6909c051878',
begin: moment(this.videoTime).format('YYYYMMDDHHmm00')
}).then(()=>{
// this.playerEz.play()
this.playerEz.Theme.changeTheme("3ffaebe2ae04479cab85e6909c051878");
});
},
videoTimeConfirm() {
this.videoTimeShow = moment(this.videoTime).format('YYYY-MM-DD HH:mm:00')
this.videoTimePopupShow = false
this.videoBack()
},
// 监听鼠标抬起事件
mouseUpListener(e) {
console.log(e)
if(e.target.id == 'my-video-pantile-icon'||e.target.parentElement.id == 'my-video-pantile-icon') {
this.pantileIconShow = !this.pantileIconShow
}
},
closeGridVideo(){
this.playerEz.stop()
this.playerEz = null
document.getElementById('my-video').innerHTML = ''
if(document.getElementById('my-video-headControl')){
document.getElementById('my-video-headControl').style.display='none'
}
document.getElementById('my-video-ez-iframe-footer-container').style.display='none'
this.pantileIconShow = false
},
// 动态添加放大缩小按钮
addBigSmallBtn() {
let box = document.getElementById('my-video-ez-ptz-item')
var list = document.createElement("div")
list.className = 'cameraLeftTool'
let bigHtml = document.createElement("p")
bigHtml.className = 'scaleshot scaleBig'
let bigIcon = document.createElement("i")
bigIcon.className = 'van-badge__wrapper van-icon van-icon-plus icon'
bigHtml.appendChild(bigIcon)
bigHtml.onmousedown = ()=>{
this.setControl(8)
}
bigHtml.onmouseup = ()=>{
this.stopControl(8)
}
list.appendChild(bigHtml)
let smallHtml = document.createElement("p")
smallHtml.className = 'scaleshot scaleSmall'
let smallIcon = document.createElement("i")
smallIcon.className = 'van-badge__wrapper van-icon van-icon-minus icon'
smallHtml.appendChild(smallIcon)
smallHtml.onmousedown = ()=>{
this.setControl(9)
}
smallHtml.onmouseup = ()=>{
this.stopControl(9)
}
list.appendChild(smallHtml)
box.appendChild(list)
console.log(box)
},
// 相机放大缩小
setControl(val){
console.log(val,this.params)
let parmas = {
'platform':2,
'deviceSerial':this.params.deviceSerial,
'channelNo':this.params.channelNo,
'direction':val,
'speed':1
}
tourApi.ptzStart(parmas).then(data => {
let result = data.data
if(result.code !=200){
Toast.fail(result.msg);
}
})
},
stopControl(val){
console.log(val,this.params)
let parmas = {
'platform':2,
'deviceSerial':this.params.deviceSerial,
'channelNo':this.params.channelNo,
'direction':val
}
tourApi.ptzStop(parmas).then(data => {
let result = data.data
if(result.code !=200){
Toast.fail(result.msg);
}
})
},
},
mounted() {
window.addEventListener('mouseup',this.mouseUpListener);
},
beforeDestroy() {
if(this.playerEz) {
this.closeGridVideo()
}
window.removeEventListener("mouseup", this.mouseUpListener);
},
created() {
this.loadTourVideo();
// this.updateTimeColumn()
},
destroyed(){
if (this.player) {
this.player.stop();
}
if (this.playerEz) {
this.playerEz.stop()
}
},
setup(props, context) {
const params = reactive(props.params);
return {
...toRefs(params)
}
}
})
</script>
<style scoped lang="less">
.videoWrap {
position: relative;
width: 100%;
.video-box {
position: relative;
.box {
position: relative;
width: 100%;
min-height: 420px;
background: #000;
}
.box-bg{
position: absolute;
top:0px;
left:0px;
width: 100%;
height: 100%;
background: #000;
}
.date-switch-container-wrap{
display: none!important;
}
.rec-type-container-wrap{
display: none!important;
}
.mobileRec-wrap{
display: none!important;
}
}
:deep(.head-message),:deep(.live-ptz-title),:deep(.mobile-ez-ptz-container){
display: none!important;
}
:deep(.date-switch-container-wrap),:deep(.rec-type-container-wrap),:deep(.mobileRec-wrap){
display: none!important;
}
:deep(.mobile-ez-ptz-container){
padding-top:20px;
}
/*,/deep/.mobile-ez-ptz-container{
display: none!important;
}*/
.video-operate-box{
width: 100%;
height: 12vw;
display: flex;
align-items: center;
background-color: rgba(0, 0, 0, 0.7);
.video-operate-one{
width: 50%;
// font-size: 40px;
height: 100%;
display: inline-flex;
align-items: center;
justify-content: center;
color: #606266;
}
.video-operate-one-show{
background-color: #000;
color: #ffffff;
}
}
.video-time-box{
height: 12vw;
background-color: rgba(0, 0, 0, 1);
color: #ffffff;
display: flex;
align-items: center;
padding-left: 20px;
border-top: 1px solid #666;
span{
display: inline-block;
line-height: 12vw;
}
.video-time-text{
margin-left: 20px;
}
.icon {
transform: rotate(90deg);
margin-left: 20px;
}
}
}
:deep(.footer-controls-right){
.theme-icon-item:nth-child(3),.theme-icon-item:nth-child(4){
display: none!important;
}
}
:deep(.cameraLeftTool){
position: absolute;
width: 24vw;
right: 5.9vw;
top: 100%;
// display: none;
z-index: 9999;
color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
.scaleshot{
display: inline-block;
width: 10vw;
height: 10vw;
background: rgba(255, 255, 255, 0.90);
line-height: 10vw;
text-align: center;
font-size: 7vw;
cursor: pointer;
border-radius: 10px;
color: #1890FF;
font-weight: 900;
&:active{
background-image: radial-gradient(circle at center, rgba(29, 141, 216,0.8) 0%, rgba(100, 143, 252, 0) 80%);
}
}
.scaleBig{
top: 42%;
}
.scaleSmall{
top: 43%;
margin-right: 0px;
}
.van-icon-minus:before {
content: "\e6ee";
display: inline-block;
}
.van-icon-plus:before {
content: "\e6fa";
display: inline-block;
}
}
</style>
\ No newline at end of file \ No newline at end of file
<template>
<div class="tour-btns1">
<div class="box">
<span @click="navBack">{{decodeURIComponent(paramObj.name)}}<van-icon class="icon" name="play" /></span>
</div>
<div class="box box1">
<span v-if="bookmark" @click="delCollectGate">
<van-icon class="iconMargin" color="#F7B500" name="star" />收藏
</span>
<span v-else @click="collectGate">
<van-icon class="iconMargin" name="star-o" />收藏
</span>
<span @click="pictureBtn">
<van-icon class="iconMargin" name="photograph" />开始巡检
</span>
</div>
</div>
</template>
<script setup>
import { reactive, ref, onMounted, getCurrentInstance } from 'vue';
import { Toast } from 'vant';
import tourApi from '@/api';
const navBack = () => {
wx.miniProgram.redirectTo({
url: `/pages/tour/gate/index?type=${paramObj.type}&atoken=${paramObj.atoken}&userId=${paramObj.userId}&id=${paramObj.id}&channelid=${paramObj.channelid}&platform=${paramObj.platform}&mallId=${paramObj.mallId}&name=${paramObj.name}`
});
};
const bookmark = ref(paramObj.bookmark)
const collectGate= ()=>{
tourApi.setBookmark({
userId:paramObj.userId,
patrolGateIds:[paramObj.id]
}).then(res=>{
if(res.data.code==200){
bookmark.value = true;
return Toast.success('收藏成功');
}
})
}
const delCollectGate= ()=>{
tourApi.delBookmark({
userId:paramObj.userId,
patrolGateIds:[paramObj.id]
}).then(res=>{
if(res.data.code==200){
bookmark.value = false;
return Toast.success('取消收藏成功');
}
})
}
const pictureBtn = () => {
Toast.loading({
duration: 0,
message: '视频截图中···',
forbidClick: true,
});
// tourApi.getCapture({id:paramObj.channelid}).then(res=>{
// if(res.status!=200){
// return Toast.fail(res.data.msg);
// }
// let picUrl = res.data.data;
// Toast.clear();
// if(paramObj.type!='titem'){
// wx.miniProgram.redirectTo({
// url: `/pages/tour/index/index?action=capture&picUrl=${picUrl}&id=${paramObj.id}&channelid=${paramObj.channelid}&mallId=${paramObj.mallId}&title=${paramObj.name}&atoken=${paramObj.atoken}&userId=${paramObj.userId}`
// });
// }else{
// /***********巡店详情截图****************/
// wx.miniProgram.navigateTo({
// url: `/pages/tour/titemDetail/index?action=capture&picUrl=${picUrl}&id=${paramObj.tid}`
// });
// }
// })
};
</script>
<style scoped lang="less">
.tour-btns1{
display: flex;
background: #E6EDFF;
height: 15vw;
line-height: 15vw;
padding: 0 20px;
.box{
display: inline-block;
flex: 1;
}
.box1{
text-align: right;
span{
margin-left: 20px;
}
}
.icon{
transform: rotate(90deg);
}
}
</style>
\ No newline at end of file \ No newline at end of file
import { createApp } from 'vue'; import Vue from 'vue'
import wx from 'weixin-js-sdk'; import App from './App.vue'
window.wx = wx; import router from './router'
import App from './App.vue';
import Vant from 'vant'; Vue.config.productionTip = false
import '@s/css/index.css';
import 'vant/lib/index.css'; new Vue({
const app = createApp(App); router,
app.use(Vant); render: h => h(App)
app.mount('#app') }).$mount('#app')
@charset "utf-8";
/*=====================================
reset
=====================================*/
html,
body,
h1,
h2,
h3,
h4,
h5,
h6,
table,
thead,
tfoot,
tbody,
form,
fieldset,
legend,
div,
p,
span,
dl,
dt,
dd,
ul,
ol,
li,
blockquote,
pre,
q,
cite,
code,
input,
select,
textarea{margin:0;padding:0;/* font-family:"fang"; */}
h1,
h2,
h3,
h4,
h5,
h6,
strong,
em,
cite,
address,
sup,
sub,
th{font-weight:normal;font-style:normal;vertical-align:auto;font-size:1em;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-tap-highlight-color:transparent;}
i{font-style:normal;}
/* @font-face{
font-family: fang;
src: url('http://h5.wufae.com/Chevrolet/upload/static/css/fang.ttf') format('truetype');
} */
*{/* font-family:"fang"; */box-sizing:border-box;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-tap-highlight-color:transparent;}
input,
textarea,
input:focus,
select:focus,
textarea:focus{/* font-family:"fang"; */border-width:0px;border-color:transparent;-webkit-tap-highlight-color:transparent;outline:transparent;}
ul,
ol{list-style-type:none;}
a:link,
a:visited{text-decoration:none;outline:0 none;}
a:hover,
a:active{text-decoration:underline;outline:0 none;}
fieldset,
a img{border:none;}
img{vertical-align:top;display:block;}
input,
textarea,
button{font-size:100%;}
button{cursor:pointer;}
textarea{resize:none;overflow:auto;}
table{border-collapse:collapse;border-spacing:0;}
select optgroup{font-style:normal;}
legend{display:none;}
input[type="radio"],
input[type="checkbox"],
textarea{vertical-align:middle;}
input,
select{background:transparent;border:0;outline:none;}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button{-webkit-appearance:none!important;margin:0;}
.iswin input[type="radio"],
.iswin input[type="checkbox"],
.iswin textarea{vertical-align:-3px;}
input[type="radio"],
input[type="checkbox"]{margin-right:3px;}
input[type="text"],
input[type="password"],
textarea{border:none;}
input[type="text"]:focus,
input[type="password"]:focus,
a,
img{tap-highlight-color:rgba(0,0,0,0);focus-ring-color:rgba(0,0,0,0);-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-focus-ring-color:rgba(0,0,0,0);-moz-tap-highlight-color:rgba(0,0,0,0);-moz-focus-ring-color:rgba(0,0,0,0);}
.application{position:absolute;left:0;top:0;bottom:0;right:0;}
/*=====================================
ȫ?? =====================================*/
html{height:100%;overflow:hidden;}
body{transition:opacity 0.25s;position:relative;margin:0 auto;width:100%;height:100%;}
body.succ{opacity:1;}
.root_gap{position:relative; /* width:96%; */margin:0 30px;}
.clearfix{zoom:1;}
.clearfix:after{content:"";display:block;height:0;font-size:0;clear:both;overflow:hidden;visibility:hidden;}
.fullPage{position:absolute;left:0;top:0;width: 100%;height: 100%;background-color: #f3f9ff;}
.touchmove{overflow:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;overflow-scrolling:touch;}
\ No newline at end of file \ No newline at end of file
This diff could not be displayed because it is too large.
No preview for this file type
This diff could not be displayed because it is too large.
No preview for this file type
/**
* @param {array} actual
* @returns {array}
*/
export function cleanArray(actual) {
const newArray = []
for (let i = 0; i < actual.length; i++) {
if (actual[i]) {
newArray.push(actual[i])
}
}
return newArray
}
/**
* @param {object} json
* @returns {string}
*/
export function param2(json) {
if (!json) return ''
return cleanArray(
Object.keys(json).map(key => {
if (json[key] === undefined ||
json[key] === null
) return ''
return encodeURIComponent(key) + '=' + json[key]
})
).join('&')
}
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import pxtovw from 'postcss-px-to-viewport'
import styleImport, { VantResolve } from 'vite-plugin-style-import';
const loder_pxtovw=pxtovw({
unitToConvert: "px", // 需要转换的单位,默认为"px"
viewportWidth: 750, // 设计稿的视口宽度
unitPrecision: 2, // 单位转换后保留的精度
propList: ["*"], // 能转化为vw的属性列表
viewportUnit: "vw", // 希望使用的视口单位
fontViewportUnit: "vw", // 字体使用的视口单位
selectorBlackList: ['ignore'], // 需要忽略的CSS选择器
exclude:[/node_module/],
})
import path from 'path';
import copy from 'rollup-plugin-copy'
export default defineConfig({
base:'./',
publicDir:'public',
plugins: [
vue(),
vueJsx(),
styleImport({
libs: [
{
libraryName: "vant",
esModule: true,
resolveStyle: (name) => `vant/es/${name}/style`,
},
],
}),
],
css: {
postcss:{
plugins: [loder_pxtovw]
}
},
resolve:{
alias:{
"@": path.resolve(__dirname, "./src"),
"@s": path.resolve(__dirname, "./src/static")
}
},
build:{
assetsDir:'static',
// rollupOptions:{
// plugins:[copy({
// targets: [
// { src: 'public/*', dest: 'dist/static' }
// ]
// })]
// }
}
})
This diff could not be displayed because it is too large.
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!