|
@@ -0,0 +1,896 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <view class="box">
|
|
|
|
|
+
|
|
|
|
|
+ <view class="zdyNavBox">
|
|
|
|
|
+ <view class="status_bar" :style="{height: iStatusBarHeight + 'px'}"></view>
|
|
|
|
|
+ <view class="zdyNav">
|
|
|
|
|
+ <view class="zdyNavLeft">
|
|
|
|
|
+ <div @click="goback" class="uni-page-head-btn"><i class="uni-btn-icon"
|
|
|
|
|
+ style="color: rgb(0, 0, 0); font-size: 27px;"></i></div>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="xx" style="position: absolute;left:100rpx;color: black;font-size: 23px;" @click="goToSelectCarModel">X</view>
|
|
|
|
|
+ <view class="zdyNavTitle" @click="changeIsShow()">
|
|
|
|
|
+ <view class="title">{{chlildObj.title}}</view>
|
|
|
|
|
+ <view class="sanjiao" v-if="isShowAll == 1">▲</view>
|
|
|
|
|
+ <view class="sanjiao" v-if="isShowAll == 0">▼</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view style="width: 120rpx;"></view>
|
|
|
|
|
+
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="title-box" v-if="isShowAll == 1" style="z-index: 999;">
|
|
|
|
|
+ <view class="item" v-for="(item,index) in allChildrenObj" :key="index" @click="clickTitle(item)">
|
|
|
|
|
+ <view class="item-image">
|
|
|
|
|
+ <image :src="item.image" mode="aspectFit" style="width: 100%;height: 180rpx;"></image>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="item-title" >
|
|
|
|
|
+ {{item.title}}
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view v-if="isShowAll == 1" style="height: 100vh;;z-index: 998;" @click="closeTitleTab()"></view>
|
|
|
|
|
+ <view v-if="isShowAll == 1" style="height: 100vh;;z-index: 998;" @click="closeTitleTab()"></view>
|
|
|
|
|
+ <view v-if="isShowAll == 1" style="height: 100vh;;z-index: 998;" @click="closeTitleTab()"></view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <view class="box-image-big" v-if="showType == 0">
|
|
|
|
|
+ <view class="image-big">
|
|
|
|
|
+ <image :src="chlildObj.image" mode="aspectFit" style="width: 100%;height: 80vh"></image>
|
|
|
|
|
+ <canvas canvas-id="big-this-image" class="drawing-canvas" id="big-this-image" type="2d"
|
|
|
|
|
+ @touchstart="handleTouchStartBig"
|
|
|
|
|
+ @touchmove="handleTouchMoveBig"
|
|
|
|
|
+ @touchend="handleTouchEndBig"></canvas>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="box-btn">
|
|
|
|
|
+ <view class="leftBtn" @click="getOther(-1)"><</view>
|
|
|
|
|
+ <view class="rightBtn"@click="getOther(1)">></view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="box-image-small" v-if="showType == 1" @tap="handleImageClick">
|
|
|
|
|
+ <view class="small-image" >
|
|
|
|
|
+ <image class="small-this-image" :src="chlildObj.image" mode="aspectFill" ></image>
|
|
|
|
|
+ <!-- Canvas遮罩层 -->
|
|
|
|
|
+ <canvas
|
|
|
|
|
+ canvas-id="mask-canvas"
|
|
|
|
|
+ class="mask-canvas"
|
|
|
|
|
+ :style="{
|
|
|
|
|
+ position: 'absolute',
|
|
|
|
|
+ top: 0,
|
|
|
|
|
+ left: 0,
|
|
|
|
|
+ width: '100%',
|
|
|
|
|
+ height: '100%',
|
|
|
|
|
+ zIndex: 1,
|
|
|
|
|
+ pointerEvents: 'none'
|
|
|
|
|
+ }"
|
|
|
|
|
+ ></canvas>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <view class="box-jiantou">
|
|
|
|
|
+ <view class="jian-span " :class="{'jian-down':isRotated}" @click="changeIsRotated()">》</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="box-lab">
|
|
|
|
|
+ <scroll-view scroll-x=true enable-flex=true show-scrollbar=false class="box-lab-scr" style="white-space: nowrap;height: 90rpx;" :scroll-into-view="scrollIntoId">
|
|
|
|
|
+ <view class="lab-titles" :class="{'clickLab':labtitile==index}" :id="'item-' + index" @click="labTitile(item,index)" v-for="(item,index) in chlildObj.children" :key="index">
|
|
|
|
|
+ {{item.title}}
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </scroll-view>
|
|
|
|
|
+
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="lab-grid" v-if="showType == 1">
|
|
|
|
|
+ <view class="lab-child" v-for="(item,index) in labChildObj" :key="index" @click="labChildClick(item)">
|
|
|
|
|
+ <view class="lab-child-image">
|
|
|
|
|
+ <image :src="item.image" mode="aspectFit" style="width: 160rpx;height: 150rpx;"></image>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="lab-child-title">
|
|
|
|
|
+ {{item.title}}
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ </view>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+ export default {
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ toke:"",
|
|
|
|
|
+ param:"",
|
|
|
|
|
+ access_time:"",
|
|
|
|
|
+ epc_id:"",
|
|
|
|
|
+ brand_id:"",
|
|
|
|
|
+ iStatusBarHeight: '',
|
|
|
|
|
+ chlildObj:null,
|
|
|
|
|
+ allChildrenObj:null,
|
|
|
|
|
+ isShowAll:0,
|
|
|
|
|
+ isRotated: false,
|
|
|
|
|
+ labtitile: 0,
|
|
|
|
|
+ labChildObj:null,
|
|
|
|
|
+ showType:0, //0大图1小图
|
|
|
|
|
+ ctxBig: null, //大画布
|
|
|
|
|
+ pointsBig: [], // 存储所有点的坐标数组
|
|
|
|
|
+ isDrawingBig: false, // 是否正在绘制的标志
|
|
|
|
|
+ currentPathBig: [], // 当前路径的点数组
|
|
|
|
|
+ ctxMask: null, //小画布
|
|
|
|
|
+ pointsSmall: [], // 存储所有点的坐标数组
|
|
|
|
|
+ isDrawingSmall: false, // 是否正在绘制的标志
|
|
|
|
|
+ currentPathSmall: [], // 当前路径的点数组
|
|
|
|
|
+ hitChild:[],//圈选中对象
|
|
|
|
|
+ thisWidth: 0,//当前屏幕宽度
|
|
|
|
|
+ scrollIntoId: '', //工东严肃定位
|
|
|
|
|
+
|
|
|
|
|
+ specifiedAreas: [], //预定义位置
|
|
|
|
|
+ unmaskAreas: [], // 已取消遮罩的区域
|
|
|
|
|
+ unmaskSize: 80,
|
|
|
|
|
+
|
|
|
|
|
+ brand_name:'',
|
|
|
|
|
+ caption:'',
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ onLoad(opt) {
|
|
|
|
|
+ this.iStatusBarHeight = uni.getSystemInfoSync().statusBarHeight;
|
|
|
|
|
+ //当前对象
|
|
|
|
|
+ this.chlildObj = uni.getStorageSync('epcChildren');
|
|
|
|
|
+ //全部对象
|
|
|
|
|
+ this.allChildrenObj = uni.getStorageSync('epcAllChildren');
|
|
|
|
|
+ //当前详细
|
|
|
|
|
+ this.labChildObj = this.chlildObj.children[this.labtitile].children;
|
|
|
|
|
+ this.token = opt.token;
|
|
|
|
|
+ this.param = opt.param;
|
|
|
|
|
+ this.access_time = opt.access_time;
|
|
|
|
|
+ this.epc_id = opt.epc_id;
|
|
|
|
|
+ this.brand_id = opt.brand_id;
|
|
|
|
|
+ this.brand_name = opt.brand_name;
|
|
|
|
|
+ this.caption = opt.caption;
|
|
|
|
|
+ this.getSmileDate();
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+ onReady(){
|
|
|
|
|
+ this.initCanvas();
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+ onShow() {
|
|
|
|
|
+ this.initCanvas(); // 确保重新加载数据
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ goback() {
|
|
|
|
|
+ uni.navigateBack({})
|
|
|
|
|
+ },
|
|
|
|
|
+ //返回选品牌
|
|
|
|
|
+ goToSelectCarModel(){
|
|
|
|
|
+ uni.navigateTo({url:'SelectCarModel'});
|
|
|
|
|
+ },
|
|
|
|
|
+ //标题title点击事件
|
|
|
|
|
+ changeIsShow(){
|
|
|
|
|
+ this.isShowAll = this.isShowAll == 0 ? 1 : 0;
|
|
|
|
|
+ },
|
|
|
|
|
+ //上下箭头点击事件
|
|
|
|
|
+ changeIsRotated(){
|
|
|
|
|
+ this.isRotated = !this.isRotated;
|
|
|
|
|
+ this.showType = this.isRotated ? 1:0;
|
|
|
|
|
+
|
|
|
|
|
+ if (this.showType == 1) {
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ this.initSpecifiedAreasPush();
|
|
|
|
|
+ });
|
|
|
|
|
+ }else{
|
|
|
|
|
+ this.clearUnmaskAreas()
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ //左右按钮点击
|
|
|
|
|
+ getOther(typeNum){
|
|
|
|
|
+ //获取顺序
|
|
|
|
|
+ let index = 0;
|
|
|
|
|
+ for (var i = 0; i < this.allChildrenObj.length; i++) {
|
|
|
|
|
+ let item = this.allChildrenObj[i]
|
|
|
|
|
+ if (item.id == this.chlildObj.id){
|
|
|
|
|
+ index = i;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if(typeNum ==-1){
|
|
|
|
|
+ index = index-1 < 0 ? this.allChildrenObj.length-1 : index-1 ;
|
|
|
|
|
+ }else{
|
|
|
|
|
+ index = index+1 > this.allChildrenObj.length-1 ? 0 : index+1 ;
|
|
|
|
|
+ }
|
|
|
|
|
+ this.chlildObj = this.allChildrenObj[index];
|
|
|
|
|
+ this.labChildObj = this.chlildObj.children[index].children;
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+ //标题下拉图片点击
|
|
|
|
|
+ clickTitle(item){
|
|
|
|
|
+ this.chlildObj = item;
|
|
|
|
|
+ this.isShowAll = 0;
|
|
|
|
|
+ this.showType = 0;
|
|
|
|
|
+ this.initCanvas();
|
|
|
|
|
+ this.getSmileDate();
|
|
|
|
|
+ this.initSpecifiedAreasPush();
|
|
|
|
|
+ },
|
|
|
|
|
+ //labtitiel的点击事件
|
|
|
|
|
+ labTitile(item,index){
|
|
|
|
|
+ this.showType = 1;
|
|
|
|
|
+ this.isRotated = true;
|
|
|
|
|
+ this.labtitile = index;
|
|
|
|
|
+ this.labChildObj = this.chlildObj.children[this.labtitile].children;
|
|
|
|
|
+ this.scrollIntoId = 'item-' + index;
|
|
|
|
|
+ //set 小图坐标
|
|
|
|
|
+ //this.specifiedAreasPush(item);
|
|
|
|
|
+ //延时等待渲染效果
|
|
|
|
|
+ setTimeout(()=>{
|
|
|
|
|
+ this.initSpecifiedAreasPush();
|
|
|
|
|
+ },100)
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+ //下布局grid点击图片事件
|
|
|
|
|
+ labChildClick(item){
|
|
|
|
|
+ uni.navigateTo({
|
|
|
|
|
+ url: 'SimpleOemSearch?brand=' + undefined + '&token=' + this.token + '¶m=' +
|
|
|
|
|
+ this.param + '&access_time=' + this.access_time + '&title=' + item.title+'&epc_id='+this.epc_id+"&brand_name="+this.brand_name
|
|
|
|
|
+ +"&caption="+this.caption
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ //关闭title 下拉
|
|
|
|
|
+ closeTitleTab(){
|
|
|
|
|
+ this.isShowAll = 0;
|
|
|
|
|
+ },
|
|
|
|
|
+ //初始化画布
|
|
|
|
|
+ initCanvas(){
|
|
|
|
|
+ this.ctxBig = uni.createCanvasContext('big-this-image',this);
|
|
|
|
|
+ //this.ctxSmall = uni.createCanvasContext('small-this-image',this);
|
|
|
|
|
+
|
|
|
|
|
+ this.ctxMask = uni.createCanvasContext('mask-canvas', this);
|
|
|
|
|
+
|
|
|
|
|
+ // 设置线条颜色
|
|
|
|
|
+ this.ctxBig.setStrokeStyle("red");
|
|
|
|
|
+ // 设置线宽
|
|
|
|
|
+ this.ctxBig.setLineWidth(5);
|
|
|
|
|
+ // 设置线条末端为圆形
|
|
|
|
|
+ this.ctxBig.setLineCap("round");
|
|
|
|
|
+ // 设置线条连接处为圆形
|
|
|
|
|
+ this.ctxBig.setLineJoin("round");
|
|
|
|
|
+ this.ctxBig.setLineDash([]); // 确保不是虚线
|
|
|
|
|
+ // 设置更高的绘制质量
|
|
|
|
|
+ this.ctxBig.setGlobalAlpha(1);
|
|
|
|
|
+ this.ctxBig.setShadow(0, 0, 0, 'transparent'); // 清除阴影避免性能问题
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ this.drawFullMask();
|
|
|
|
|
+ },
|
|
|
|
|
+ //小图遮罩初始化显示 正前
|
|
|
|
|
+ initSpecifiedAreasPush(){
|
|
|
|
|
+ let id = 0;
|
|
|
|
|
+ //获取这是第几个labtitle
|
|
|
|
|
+ const element = document.querySelector('.clickLab');
|
|
|
|
|
+ if (element) {
|
|
|
|
|
+ id = element.id.split("-")[1];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let tetxx = this.chlildObj.children[id].title;
|
|
|
|
|
+ let isAreas = {"title":tetxx};
|
|
|
|
|
+ this.specifiedAreasPush(isAreas);
|
|
|
|
|
+ },
|
|
|
|
|
+ // 处理触摸开始事件
|
|
|
|
|
+ handleTouchStartBig(e) {
|
|
|
|
|
+ // 获取触摸点的x,y坐标
|
|
|
|
|
+ const x = e.touches[0].x;
|
|
|
|
|
+ const y = e.touches[0].y;
|
|
|
|
|
+
|
|
|
|
|
+ // 设置正在绘制标志
|
|
|
|
|
+ this.isDrawingBig = true;
|
|
|
|
|
+ // 初始化当前路径数组,并添加第一个点
|
|
|
|
|
+ this.currentPathBig = [{x, y}];
|
|
|
|
|
+
|
|
|
|
|
+ // 开始新路径
|
|
|
|
|
+ this.ctxBig.beginPath();
|
|
|
|
|
+ // 移动画笔到起始点
|
|
|
|
|
+ this.ctxBig.moveTo(x, y);
|
|
|
|
|
+ },
|
|
|
|
|
+ // 处理触摸移动事件
|
|
|
|
|
+ handleTouchMoveBig(e) {
|
|
|
|
|
+ // 如果不是绘制状态则返回
|
|
|
|
|
+ if (!this.isDrawingBig) return;
|
|
|
|
|
+
|
|
|
|
|
+ // 获取当前触摸点的坐标
|
|
|
|
|
+ const x = e.touches[0].x;
|
|
|
|
|
+ const y = e.touches[0].y;
|
|
|
|
|
+
|
|
|
|
|
+ // 将当前点添加到当前路径数组
|
|
|
|
|
+ this.currentPathBig.push({x, y});
|
|
|
|
|
+
|
|
|
|
|
+ // 当有足够点数时使用贝塞尔曲线
|
|
|
|
|
+ if (this.currentPathBig.length >= 3) {
|
|
|
|
|
+ this.drawSmoothLine();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.drawStraightLine();
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ // 绘制平滑曲线
|
|
|
|
|
+ drawSmoothLine() {
|
|
|
|
|
+ const points = this.currentPathBig;
|
|
|
|
|
+ const len = points.length;
|
|
|
|
|
+
|
|
|
|
|
+ if (len < 3) return;
|
|
|
|
|
+
|
|
|
|
|
+ this.ctxBig.beginPath();
|
|
|
|
|
+ this.ctxBig.moveTo(points[0].x, points[0].y);
|
|
|
|
|
+
|
|
|
|
|
+ // 使用二次贝塞尔曲线平滑连接
|
|
|
|
|
+ for (let i = 1; i < len - 2; i++) {
|
|
|
|
|
+ const controlX = (points[i].x + points[i + 1].x) / 2;
|
|
|
|
|
+ const controlY = (points[i].y + points[i + 1].y) / 2;
|
|
|
|
|
+ this.ctxBig.quadraticCurveTo(points[i].x, points[i].y, controlX, controlY);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 处理最后两个点
|
|
|
|
|
+ if (len >= 3) {
|
|
|
|
|
+ this.ctxBig.quadraticCurveTo(
|
|
|
|
|
+ points[len - 2].x,
|
|
|
|
|
+ points[len - 2].y,
|
|
|
|
|
+ points[len - 1].x,
|
|
|
|
|
+ points[len - 1].y
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.ctxBig.stroke();
|
|
|
|
|
+ this.ctxBig.draw(true);
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制直线(点数不足时)
|
|
|
|
|
+ drawStraightLine() {
|
|
|
|
|
+ if (this.currentPathBig.length < 2) return;
|
|
|
|
|
+
|
|
|
|
|
+ this.ctxBig.beginPath();
|
|
|
|
|
+ this.ctxBig.moveTo(this.currentPathBig[0].x, this.currentPathBig[0].y);
|
|
|
|
|
+ this.ctxBig.lineTo(this.currentPathBig[1].x, this.currentPathBig[1].y);
|
|
|
|
|
+ this.ctxBig.stroke();
|
|
|
|
|
+ this.ctxBig.draw(true);
|
|
|
|
|
+ },
|
|
|
|
|
+ // 处理触摸结束事件
|
|
|
|
|
+ handleTouchEndBig() {
|
|
|
|
|
+ // 如果不是绘制状态则返回
|
|
|
|
|
+ if (!this.isDrawingBig) return;
|
|
|
|
|
+
|
|
|
|
|
+ // 将当前路径的所有点合并到总点数组中
|
|
|
|
|
+ this.pointsBig = [...this.pointsBig, ...this.currentPathBig];
|
|
|
|
|
+ // 清空当前路径
|
|
|
|
|
+ //this.currentPathBig = [];
|
|
|
|
|
+ // 重置绘制状态
|
|
|
|
|
+ this.isDrawingBig = false;
|
|
|
|
|
+ //清空圈选对象
|
|
|
|
|
+ this.hitChild = [];
|
|
|
|
|
+ setTimeout(()=>{
|
|
|
|
|
+ const width = this.ctxBig.width || 1024; // 如果没有设置width属性,使用默认值
|
|
|
|
|
+ const height = this.ctxBig.height || 1024;
|
|
|
|
|
+ this.ctxBig.clearRect(0,0,width,height);
|
|
|
|
|
+ this.ctxBig.draw(true);
|
|
|
|
|
+ this.isDrawingBig = true;
|
|
|
|
|
+ this.toDetailByCanvas();
|
|
|
|
|
+ },1000)
|
|
|
|
|
+ },
|
|
|
|
|
+ //筛选圈选的位置
|
|
|
|
|
+ toDetailByCanvas(){
|
|
|
|
|
+ //坐标集合
|
|
|
|
|
+ let zuobiao = this.currentPathBig,
|
|
|
|
|
+ //当前对象
|
|
|
|
|
+ chlildObj = this.labChildObj;
|
|
|
|
|
+ //击中对象
|
|
|
|
|
+ const oneSet = new Set();
|
|
|
|
|
+
|
|
|
|
|
+ zuobiao.forEach(x =>{
|
|
|
|
|
+ //判断当前坐标是否在当前位置
|
|
|
|
|
+ this.ifClickObj(x.x,x.y);
|
|
|
|
|
+ //跳转
|
|
|
|
|
+ uni.setStorageSync('epcChildrenTwo', this.hitChild);
|
|
|
|
|
+ uni.navigateTo({
|
|
|
|
|
+ url: 'epcSimpleDetailTwo?token='+this.token+'¶m='+this.param+'&access_time='+this.access_time+'&epc_id='+this.epc_id+"&title="+this.chlildObj.title
|
|
|
|
|
+ +'&brand_id='+this.brand_id+"&brand_name="+this.brand_name+"&caption="+this.caption
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @param {Object} x
|
|
|
|
|
+ * @param {Object} y
|
|
|
|
|
+ * 要遍历多次,第一次为外面的大类确定
|
|
|
|
|
+ * 第二次为大类里面的包含的小件
|
|
|
|
|
+ */
|
|
|
|
|
+ //根据坐标判断是否击中集合
|
|
|
|
|
+ ifClickObj(x,y){
|
|
|
|
|
+
|
|
|
|
|
+ let isDelete = 0;
|
|
|
|
|
+ let chlildObj = this.chlildObj; //顶级对象
|
|
|
|
|
+ this.thisWidth = uni.getSystemInfoSync().screenWidth;
|
|
|
|
|
+ chlildObj.children.forEach(item => {
|
|
|
|
|
+ let item_width = item.width,
|
|
|
|
|
+ item_top = item.top,
|
|
|
|
|
+ item_left = item.left,
|
|
|
|
|
+ item_height = item.height,
|
|
|
|
|
+ image_width = chlildObj.width,
|
|
|
|
|
+ image_height = chlildObj.height;
|
|
|
|
|
+
|
|
|
|
|
+ //计算实际坐标
|
|
|
|
|
+ let x1 = 0,//x头
|
|
|
|
|
+ x2 = 0,//x尾
|
|
|
|
|
+ y1 = 0,//y头
|
|
|
|
|
+ y2 = 0;//y尾
|
|
|
|
|
+ x1 = this.pxToX(item_left,image_width);
|
|
|
|
|
+ x2 = x1+this.pxToX(item_width,image_width);
|
|
|
|
|
+ y1 =this.pxToY(item_top,image_width,image_height);
|
|
|
|
|
+ y2 = y1+this.pxToY(item_height,image_width,image_height);
|
|
|
|
|
+ //命中父级组件
|
|
|
|
|
+ if(x>x1 && x<x2 && y>y1 && y<y2){
|
|
|
|
|
+ let childrenParent = this.hitChild.find(x1 => x1.title === item.title);
|
|
|
|
|
+ if(childrenParent==undefined || childrenParent.length == "" ){
|
|
|
|
|
+ childrenParent = {
|
|
|
|
|
+ "id":item.id,
|
|
|
|
|
+ "children":[],
|
|
|
|
|
+ "image":item.image,
|
|
|
|
|
+ "pid":item.pid,
|
|
|
|
|
+ "title":item.title,
|
|
|
|
|
+ "is_visible":item.is_visible,
|
|
|
|
|
+ "height":item.height,
|
|
|
|
|
+ "top":item.top,
|
|
|
|
|
+ "left":item.left,
|
|
|
|
|
+ "width":item.width
|
|
|
|
|
+ };
|
|
|
|
|
+ this.hitChild.push(childrenParent);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //判断命中小组建
|
|
|
|
|
+ item.children.forEach(childItem =>{
|
|
|
|
|
+ let child_width = childItem.width,
|
|
|
|
|
+ child_top = childItem.top,
|
|
|
|
|
+ child_left = childItem.left,
|
|
|
|
|
+ child_height = childItem.height,
|
|
|
|
|
+ child_x = 0,
|
|
|
|
|
+ child_x2 = 0,
|
|
|
|
|
+ child_y = 0,
|
|
|
|
|
+ child_y2 = 0;
|
|
|
|
|
+ child_x = this.pxToX(child_width,image_width);
|
|
|
|
|
+ child_x2 = child_x+this.pxToX(child_width,image_width);
|
|
|
|
|
+ child_y = this.pxToY(child_top,image_width,image_height);
|
|
|
|
|
+ child_y2 = child_y+this.pxToY(child_height,image_width,image_height);
|
|
|
|
|
+ //命中小组件
|
|
|
|
|
+ if(x>child_x && x<child_x2 && y>child_y && y<child_y2){
|
|
|
|
|
+ //判断是否存在
|
|
|
|
|
+ let hitchilditem = childrenParent.children.find(mm => mm.title === childItem.title);
|
|
|
|
|
+ if(hitchilditem == undefined || hitchilditem == ""){
|
|
|
|
|
+ childrenParent.children.push(childItem);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 像素等比例转换X轴
|
|
|
|
|
+ * @param {Object} px 标记像素
|
|
|
|
|
+ * @param {Object} widch 图片宽度
|
|
|
|
|
+ */
|
|
|
|
|
+ pxToX(px,width){
|
|
|
|
|
+ let pxx = Math.floor((px / width) * this.thisWidth);
|
|
|
|
|
+ return pxx;
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 像素等比例转换Y轴
|
|
|
|
|
+ * @param {Object} px 标记像素
|
|
|
|
|
+ * @param {Object} height 图片高度
|
|
|
|
|
+ */
|
|
|
|
|
+ pxToY(px,width,height){
|
|
|
|
|
+ //计算等比例高度
|
|
|
|
|
+ const scaledHeight = (this.thisWidth / width) * height;
|
|
|
|
|
+ let pxx = Math.floor(( px/ height) * scaledHeight);
|
|
|
|
|
+ return pxx;
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 清除所有取消遮罩的区域
|
|
|
|
|
+ getSmileDate(){
|
|
|
|
|
+ this.chlildObj.children.forEach(item => {
|
|
|
|
|
+ let chlildObj = this.chlildObj;
|
|
|
|
|
+ let item_width = item.width,
|
|
|
|
|
+ item_top = item.top,
|
|
|
|
|
+ item_left = item.left,
|
|
|
|
|
+ item_height = item.height,
|
|
|
|
|
+ image_width = chlildObj.width,
|
|
|
|
|
+ image_height = chlildObj.height;
|
|
|
|
|
+ let x1 = 0,
|
|
|
|
|
+ x2 = 0,
|
|
|
|
|
+ y1 = 0,
|
|
|
|
|
+ y2 = 0;
|
|
|
|
|
+
|
|
|
|
|
+ let oldx = item_left,
|
|
|
|
|
+ oldy = item_top,
|
|
|
|
|
+ oldx2 = item_width*1,
|
|
|
|
|
+ oldy2 = item_height*1;
|
|
|
|
|
+
|
|
|
|
|
+ x1 = oldy*1;
|
|
|
|
|
+ x2 = oldy*1 + oldy2*1;
|
|
|
|
|
+ y1 = image_width*1 - oldx*1;
|
|
|
|
|
+ y2 = image_width*1 - oldx*1 - oldx2*1;
|
|
|
|
|
+
|
|
|
|
|
+ // y1 = item_left;
|
|
|
|
|
+ // x1 = item_top;
|
|
|
|
|
+ // y2 = item_left*1 + item_width*1;
|
|
|
|
|
+ // x2 = item_top*1 + item_height*1;
|
|
|
|
|
+
|
|
|
|
|
+ let zb1 = this.shuToHeng(image_width,image_height,x1,y1);
|
|
|
|
|
+ let zb2 = this.shuToHeng(image_width,image_height,x2,y2);
|
|
|
|
|
+ this.specifiedAreas.push({
|
|
|
|
|
+ "x1":zb1.x,"y1":zb1.y,"x2":zb2.x,"y2":zb2.y,id:'area'+item.title
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+ //push 取消遮罩
|
|
|
|
|
+ specifiedAreasPush(item){
|
|
|
|
|
+ let allAreas = this.specifiedAreas;
|
|
|
|
|
+ //获取tab坐标
|
|
|
|
|
+ let isAreas = allAreas.find(x => x.id == "area"+item.title);
|
|
|
|
|
+ this.unmaskAreas = [];
|
|
|
|
|
+ this.unmaskAreas.push({
|
|
|
|
|
+ id: isAreas.id,
|
|
|
|
|
+ x1: isAreas.x1,
|
|
|
|
|
+ y1: isAreas.y1,
|
|
|
|
|
+ x2: isAreas.x2,
|
|
|
|
|
+ y2: isAreas.y2,
|
|
|
|
|
+ radius: this.unmaskSize/2
|
|
|
|
|
+ });
|
|
|
|
|
+ // 重绘Canvas遮罩
|
|
|
|
|
+ this.updateMaskCanvas();
|
|
|
|
|
+ },
|
|
|
|
|
+ //计算横置小图的坐标,竖坐标转化成横坐标,宽高也改变了
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @param {Object} width 图片宽度
|
|
|
|
|
+ * @param {Object} height 图片高度
|
|
|
|
|
+ * @param {Object} x 坐标
|
|
|
|
|
+ * @param {Object} y 坐标
|
|
|
|
|
+ * @param {Object} thisWidth 当前屏幕宽度
|
|
|
|
|
+ */
|
|
|
|
|
+ shuToHeng(width,height,x,y){
|
|
|
|
|
+ //转换后的宽度
|
|
|
|
|
+ let thisWidth = uni.getSystemInfoSync().screenWidth;
|
|
|
|
|
+ //选装的高度
|
|
|
|
|
+ let thisHeight = (thisWidth / height) * width;
|
|
|
|
|
+ //旋转后的y轴
|
|
|
|
|
+ let pxy = Math.floor(( y/ width) * thisHeight);
|
|
|
|
|
+ //旋转后的X轴
|
|
|
|
|
+ let pxx = Math.floor((x / height) * thisWidth);
|
|
|
|
|
+ return {"x":pxx,"y":pxy};
|
|
|
|
|
+ },
|
|
|
|
|
+ //start
|
|
|
|
|
+ handleImageClick(event) {
|
|
|
|
|
+ const query = uni.createSelectorQuery().in(this);
|
|
|
|
|
+ query.select('.small-image').boundingClientRect(data => {
|
|
|
|
|
+ if (data) {
|
|
|
|
|
+ const clickX = event.touches[0].clientX - data.left;
|
|
|
|
|
+ const clickY = event.touches[0].clientY - data.top;
|
|
|
|
|
+ // 检查是否点击在指定区域内
|
|
|
|
|
+ const hitArea = this.checkClickInSpecifiedArea(clickX, clickY);
|
|
|
|
|
+ if (hitArea) {
|
|
|
|
|
+ // 如果点击在指定区域内,取消该区域遮罩
|
|
|
|
|
+ this.addUnmaskArea(hitArea, clickX, clickY);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }).exec();
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 检查点击是否在指定区域内
|
|
|
|
|
+ checkClickInSpecifiedArea(clickX, clickY) {
|
|
|
|
|
+
|
|
|
|
|
+ for (let area of this.specifiedAreas) {
|
|
|
|
|
+ // 检查点击坐标是否在区域内
|
|
|
|
|
+ if (clickX >= area.x1 &&
|
|
|
|
|
+ clickX <= area.x2 &&
|
|
|
|
|
+ clickY >= area.y2 &&
|
|
|
|
|
+ clickY <= area.y1) {
|
|
|
|
|
+ return area;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 添加取消遮罩区域
|
|
|
|
|
+ addUnmaskArea(area, x, y) {
|
|
|
|
|
+ const exists = this.unmaskAreas.some(item => item.id === area.id);
|
|
|
|
|
+ if (!exists) {
|
|
|
|
|
+ this.unmaskAreas = [];
|
|
|
|
|
+ this.unmaskAreas.push({
|
|
|
|
|
+ id: area.id,
|
|
|
|
|
+ x1: area.x1,
|
|
|
|
|
+ y1: area.y1,
|
|
|
|
|
+ x2: area.x2,
|
|
|
|
|
+ y2: area.y2,
|
|
|
|
|
+ radius: this.unmaskSize/2
|
|
|
|
|
+ });
|
|
|
|
|
+ //lab标题获取焦点
|
|
|
|
|
+ let childrenFor = this.chlildObj.children;
|
|
|
|
|
+ let index = 0;
|
|
|
|
|
+ for (var i = 0; i < childrenFor.length; i++) {
|
|
|
|
|
+ let item = childrenFor[i];
|
|
|
|
|
+ if(item.title == area.id.split("area")[1]){
|
|
|
|
|
+ index = i;
|
|
|
|
|
+ this.labTitile(item,i);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 更新Canvas遮罩
|
|
|
|
|
+ updateMaskCanvas() {
|
|
|
|
|
+
|
|
|
|
|
+ const ctx = this.ctxMask;
|
|
|
|
|
+ // 1. 清除画布(动态获取尺寸)
|
|
|
|
|
+ const { windowWidth, windowHeight } = uni.getSystemInfoSync();
|
|
|
|
|
+ ctx.clearRect(0, 0, windowWidth, windowHeight);
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 绘制全屏半透明遮罩
|
|
|
|
|
+ ctx.setFillStyle('rgba(255, 255, 255, 0.5)');
|
|
|
|
|
+ ctx.fillRect(0, 0, windowWidth, windowHeight);
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 关键!设置合成模式为“擦除”
|
|
|
|
|
+ ctx.globalCompositeOperation = 'destination-out';
|
|
|
|
|
+ ctx.setFillStyle('rgba(0, 0, 0, 1)'); // 颜色不重要,alpha通道生效
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 绘制取消遮罩的区域(矩形示例)
|
|
|
|
|
+ this.unmaskAreas.forEach(area => {
|
|
|
|
|
+ ctx.beginPath();
|
|
|
|
|
+ ctx.moveTo(area.x1, area.y1);
|
|
|
|
|
+ ctx.lineTo(area.x2, area.y1);
|
|
|
|
|
+ ctx.lineTo(area.x2, area.y2);
|
|
|
|
|
+ ctx.lineTo(area.x1, area.y2);
|
|
|
|
|
+ ctx.closePath();
|
|
|
|
|
+ ctx.fill();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 恢复默认合成模式
|
|
|
|
|
+ ctx.globalCompositeOperation = 'source-over';
|
|
|
|
|
+
|
|
|
|
|
+ // 6. 提交绘制(微信小程序需调用 draw)
|
|
|
|
|
+ ctx.draw(true); // 注意:微信小程序中需传 true 表示异步绘制
|
|
|
|
|
+ },
|
|
|
|
|
+ // 清除所有取消遮罩的区域
|
|
|
|
|
+ clearUnmaskAreas() {
|
|
|
|
|
+ this.unmaskAreas = [];
|
|
|
|
|
+ const ctx = this.ctxMask;
|
|
|
|
|
+ const { windowWidth, windowHeight } = uni.getSystemInfoSync();
|
|
|
|
|
+ // 1. 清除画布(使用实际尺寸)
|
|
|
|
|
+ ctx.clearRect(0, 0, windowWidth * 2, windowHeight * 2); // 考虑retina屏幕
|
|
|
|
|
+ ctx.draw(false, () => {
|
|
|
|
|
+ uni.hideLoading(); // 如果之前有loading可以隐藏
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制全屏遮罩
|
|
|
|
|
+ drawFullMask() {
|
|
|
|
|
+ const ctx = this.ctxMask;
|
|
|
|
|
+
|
|
|
|
|
+ // 获取实际屏幕尺寸(更精确的方式)
|
|
|
|
|
+ const { windowWidth, windowHeight } = uni.getSystemInfoSync();
|
|
|
|
|
+ // 1. 清除画布(使用实际尺寸)
|
|
|
|
|
+ ctx.clearRect(0, 0, windowWidth * 2, windowHeight * 2); // 考虑retina屏幕
|
|
|
|
|
+ // 2. 绘制全屏遮罩
|
|
|
|
|
+ ctx.setFillStyle('rgba(255, 255, 255, 0.5)');
|
|
|
|
|
+ ctx.fillRect(0, 0, windowWidth * 2, windowHeight * 2);
|
|
|
|
|
+ ctx.draw(false, () => {
|
|
|
|
|
+ uni.hideLoading(); // 如果之前有loading可以隐藏
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped>
|
|
|
|
|
+
|
|
|
|
|
+ .zdyNavBox {
|
|
|
|
|
+ width: 100vw;
|
|
|
|
|
+ background: #FFFFFF;
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ z-index: 9999999;
|
|
|
|
|
+ }
|
|
|
|
|
+ .zdyNav {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: 14rpx 6rpx;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .zdyNavLeft {
|
|
|
|
|
+ width: 120rpx;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .zdyNavTitle {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .zdyNavRight {
|
|
|
|
|
+ background: #FFFFFF;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ color: #3F90F7;
|
|
|
|
|
+ width: 120rpx;
|
|
|
|
|
+ }
|
|
|
|
|
+ .box{
|
|
|
|
|
+ background: #999999;
|
|
|
|
|
+ }
|
|
|
|
|
+ .title{
|
|
|
|
|
+ background: #FFFFFF;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ font-size: 32rpx;
|
|
|
|
|
+ color: #488CC3;
|
|
|
|
|
+ font-size: 25rpx;
|
|
|
|
|
+ }
|
|
|
|
|
+ .sanjiao{
|
|
|
|
|
+ font-size: 18rpx;
|
|
|
|
|
+ color: #488CC3;
|
|
|
|
|
+ padding: 5rpx;
|
|
|
|
|
+ /* right: 42%;
|
|
|
|
|
+ top: 40%; */
|
|
|
|
|
+ }
|
|
|
|
|
+ .title-box{
|
|
|
|
|
+ display: grid;
|
|
|
|
|
+ grid-template-columns: repeat(3,1fr);
|
|
|
|
|
+ gap: 5rpx;
|
|
|
|
|
+ padding-bottom: 20rpx;
|
|
|
|
|
+ .item{
|
|
|
|
|
+
|
|
|
|
|
+ margin: 30rpx 10rpx;
|
|
|
|
|
+ height: 220rpx;
|
|
|
|
|
+ .item-image{
|
|
|
|
|
+ border: solid 1rpx #999999;
|
|
|
|
|
+ border-radius: 10rpx;
|
|
|
|
|
+ padding-bottom: 10rpx;
|
|
|
|
|
+ }
|
|
|
|
|
+ .item-title{
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ .box-image-big{
|
|
|
|
|
+ background: #ffffff;
|
|
|
|
|
+ height: 80vh;
|
|
|
|
|
+ .image-big{
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 80vh;
|
|
|
|
|
+ }
|
|
|
|
|
+ .drawing-canvas {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ z-index: 10;
|
|
|
|
|
+}
|
|
|
|
|
+ .box-btn{
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ top: -50%;
|
|
|
|
|
+ z-index: 99999;
|
|
|
|
|
+ .leftBtn{
|
|
|
|
|
+ width: 40rpx;
|
|
|
|
|
+ height: 100rpx;
|
|
|
|
|
+ background: #999999;
|
|
|
|
|
+ color: #ffffff;
|
|
|
|
|
+ font-size: 35rpx;
|
|
|
|
|
+ line-height: 100rpx;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ border-radius: 0 15rpx 15rpx 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ .rightBtn{
|
|
|
|
|
+ width: 40rpx;
|
|
|
|
|
+ height: 100rpx;
|
|
|
|
|
+ background: #999999;
|
|
|
|
|
+ color: #ffffff;
|
|
|
|
|
+ font-size: 35rpx;
|
|
|
|
|
+ line-height: 100rpx;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ border-radius: 15rpx 0 0 15rpx;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .box-image-small{
|
|
|
|
|
+ z-index: 999;
|
|
|
|
|
+ .small-image{
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 420rpx;
|
|
|
|
|
+ background: #ffffff;
|
|
|
|
|
+ position: relative; /* 关键:为遮罩层提供定位基准 */
|
|
|
|
|
+ .small-this-image{
|
|
|
|
|
+ transform: rotate(-90deg);
|
|
|
|
|
+ height: 750rpx;
|
|
|
|
|
+ width: 420rpx;
|
|
|
|
|
+ margin: -150rpx 165rpx;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ .image-mask {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.5);
|
|
|
|
|
+ pointer-events: none;
|
|
|
|
|
+ z-index: 1; /* 确保在取消区域之下 */
|
|
|
|
|
+ }
|
|
|
|
|
+ /* 双箭头核心实现 */
|
|
|
|
|
+ .box-jiantou {
|
|
|
|
|
+ background: #ffffff;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+
|
|
|
|
|
+ .jian-span{
|
|
|
|
|
+ width: 20rpx;
|
|
|
|
|
+ transform: rotate(-90deg);
|
|
|
|
|
+ transform-origin: center;
|
|
|
|
|
+ margin: 0 auto;
|
|
|
|
|
+ }
|
|
|
|
|
+ .jian-down{
|
|
|
|
|
+ transform: rotate(90deg);
|
|
|
|
|
+ transform-origin: center;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .box-lab{
|
|
|
|
|
+ background: #ffffff;
|
|
|
|
|
+ z-index: 999;
|
|
|
|
|
+ }
|
|
|
|
|
+ .box-lab-scr{
|
|
|
|
|
+ .uni-scroll-view-content{
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: row;
|
|
|
|
|
+ flex-wrap: nowrap;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .lab-titles{
|
|
|
|
|
+ width: 130rpx !important;
|
|
|
|
|
+ height: 60rpx;
|
|
|
|
|
+ font-size: 35rpx;
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+ padding-left: 5rpx;
|
|
|
|
|
+ margin: 10rpx;
|
|
|
|
|
+ padding-right: 8rpx;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ }
|
|
|
|
|
+ .clickLab{
|
|
|
|
|
+ color: #236DB1;
|
|
|
|
|
+ border-bottom: 4rpx solid #236DB1;
|
|
|
|
|
+ }
|
|
|
|
|
+ .lab-grid{
|
|
|
|
|
+ display: grid;
|
|
|
|
|
+ grid-template-columns: repeat(4,1fr);
|
|
|
|
|
+ background: #ffffff;
|
|
|
|
|
+ gap: 2rpx;
|
|
|
|
|
+ .lab-child{
|
|
|
|
|
+ padding: 10rpx;
|
|
|
|
|
+ .lab-child-image{
|
|
|
|
|
+ border: 1rpx solid #999999;
|
|
|
|
|
+ border-radius: 8rpx;
|
|
|
|
|
+ }
|
|
|
|
|
+ .lab-child-title{
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+</style>
|