|
|
@@ -0,0 +1,910 @@
|
|
|
+<template>
|
|
|
+ <view class="device-photo-page">
|
|
|
+ <!-- 顶部导航栏 -->
|
|
|
+ <view class="device-detail__header">
|
|
|
+ <u-icon
|
|
|
+ size="36"
|
|
|
+ class="arrow-left"
|
|
|
+ name="arrow-left"
|
|
|
+ @click="handleBack"
|
|
|
+ ></u-icon>
|
|
|
+ {{ title }}
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 日期选择器 -->
|
|
|
+ <view class="date-container">
|
|
|
+ <!-- <view class="select-year">
|
|
|
+ <view class="select-year-item" @click="showPicker = true">
|
|
|
+ {{ currentYear }}
|
|
|
+ <u-icon name="arrow-down" size="18" class="arrow-down"></u-icon>
|
|
|
+ </view>
|
|
|
+ </view> -->
|
|
|
+ <view class="date-picker" @click="show = true">
|
|
|
+ <view class="date-input">
|
|
|
+ <text class="date-label">{{ time_begin || '-' }}</text>
|
|
|
+ </view>
|
|
|
+ <!-- <view class="date-separator">-</view>
|
|
|
+ <view class="date-input">
|
|
|
+ <text class="date-label">{{ time_end || '-' }}</text>
|
|
|
+ </view> -->
|
|
|
+ <u-icon name="calendar" class="calendar"></u-icon>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <!-- 主图片区域 -->
|
|
|
+ <view class="main-photo" v-if="currentImg.addr">
|
|
|
+ <movable-area class="movable-area" :style="{ height: containerHeight }">
|
|
|
+ <movable-view
|
|
|
+ class="movable-view"
|
|
|
+ direction="all"
|
|
|
+ scale="true"
|
|
|
+ scale-min="1"
|
|
|
+ scale-max="5"
|
|
|
+ >
|
|
|
+ <view class="image-container">
|
|
|
+ <!-- 原图 -->
|
|
|
+ <image
|
|
|
+ :src="currentImg.addr"
|
|
|
+ class="main-photo-image"
|
|
|
+ mode="widthFix"
|
|
|
+ @load="onImageLoad"
|
|
|
+ />
|
|
|
+ <!-- 虫子标记层 -->
|
|
|
+ <view class="bug-markers" v-if="bugMarkers.length > 0">
|
|
|
+ <view
|
|
|
+ v-for="(marker, index) in bugMarkers"
|
|
|
+ :key="index"
|
|
|
+ class="bug-marker"
|
|
|
+ :style="{
|
|
|
+ left: marker.x + '%',
|
|
|
+ top: marker.y + '%',
|
|
|
+ width: marker.width + '%',
|
|
|
+ height: marker.height + '%',
|
|
|
+ borderColor: marker.color
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <view class="bug-label" :style="{ color: marker.color }">
|
|
|
+ {{ getPestName(marker.id) }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </movable-view>
|
|
|
+ </movable-area>
|
|
|
+ <view class="photo-timestamp">{{ formatDate(currentImg.addtime) }}</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 缩略图预览 -->
|
|
|
+ <view class="thumbnail-preview">
|
|
|
+ <view class="thumbnail-scroll">
|
|
|
+ <view
|
|
|
+ class="thumbnail-item"
|
|
|
+ v-for="(item, index) in thumbnails"
|
|
|
+ :key="index"
|
|
|
+ :class="{ active: img_id == item.ids }"
|
|
|
+ @click="selectThumbnail(item)"
|
|
|
+ >
|
|
|
+ <image
|
|
|
+ :src="item.addr"
|
|
|
+ class="thumbnail-image"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 识别结果 -->
|
|
|
+ <view class="recognition-result" v-if="pestList.length">
|
|
|
+ <view class="result-title">当前图片识别结果</view>
|
|
|
+ <!-- 一类害虫 -->
|
|
|
+ <view>
|
|
|
+ <view class="pest-category" v-for="(pest,index) in pestList" :key="index">
|
|
|
+ <view class="category-header">
|
|
|
+ <text class="category-title">{{ pest[0] }}</text>
|
|
|
+ <text class="category-count">数量</text>
|
|
|
+ </view>
|
|
|
+ <view class="pest-item" v-for="(p, i) in pest[1]" :key="i">
|
|
|
+ <view class="pest-info">
|
|
|
+ <view class="pest-color" :style="{ backgroundColor: getPestColor(p.pest_name) }"></view>
|
|
|
+ <text class="pest-name">{{ p.pest_name }}</text>
|
|
|
+ </view>
|
|
|
+ <text class="pest-count">{{ p.pest_num }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <!-- <view v-else>
|
|
|
+ <view class="pest-category" v-for="(pest,index) in pestList" :key="index">
|
|
|
+ <view class="pest-item">
|
|
|
+ <view class="pest-info">
|
|
|
+ <view class="pest-color" :style="{ backgroundColor: getPestColor(pest[1].text) }"></view>
|
|
|
+ <text class="pest-name">{{ pest[1].text }}</text>
|
|
|
+ </view>
|
|
|
+ <text class="pest-count">{{ pest[1].value }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view> -->
|
|
|
+ </view>
|
|
|
+ <u-empty v-else text="暂无数据"></u-empty>
|
|
|
+ <u-calendar
|
|
|
+ v-model="show"
|
|
|
+ :mode="mode"
|
|
|
+ @change="handleChange"
|
|
|
+ range-color="#999"
|
|
|
+ btn-type="success"
|
|
|
+ active-bg-color="#0BBC58"
|
|
|
+ range-bg-color="rgba(11,188,88,0.13)"
|
|
|
+ :defaultDate="defaultDate"
|
|
|
+ ></u-calendar>
|
|
|
+ <u-picker v-model="showPicker" mode="selector" :range="selectorRange" range-key="id" :default-selector="[0]" @confirm="confirmHandler"></u-picker>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ show: false,
|
|
|
+ mode: 'date',
|
|
|
+ maxDate: this.formatTime(new Date()),
|
|
|
+ minDate: this.formatTime(new Date(new Date().getFullYear(), 0, 1)),
|
|
|
+ defaultDate: this.formatTime(new Date(new Date().getFullYear(), 0, 1)),
|
|
|
+ showPicker: false,
|
|
|
+ selectorRange: [],
|
|
|
+ title: '查看图片',
|
|
|
+ currentThumbnail: 2,
|
|
|
+ pestYype:{},
|
|
|
+ is_mark:0,
|
|
|
+ device_id: '',
|
|
|
+ time_begin: this.formatTime(new Date(new Date().getFullYear(), 0, 1)),
|
|
|
+ time_end: this.formatTime(new Date()),
|
|
|
+ img_id: '',
|
|
|
+ pest_list:[],
|
|
|
+ pestList:[],
|
|
|
+ colors:[
|
|
|
+ '#FF5951',
|
|
|
+ '#66EDED',
|
|
|
+ '#E67B3E',
|
|
|
+ '#6DE28B',
|
|
|
+ '#FFC97A',
|
|
|
+ '#E7EB4B',
|
|
|
+ '#1561F3',
|
|
|
+ '#FA73F5',
|
|
|
+ '#159AFF',
|
|
|
+ '#FA73F5'
|
|
|
+ ],
|
|
|
+ currentYear:'',
|
|
|
+ pest_list_arr:[],
|
|
|
+ thumbnails: [],
|
|
|
+ addtime:'',
|
|
|
+ currentImg:{},
|
|
|
+ bugMarkers: [],
|
|
|
+ imageWidth: 0,
|
|
|
+ imageHeight: 0,
|
|
|
+ imgOld_id:'',
|
|
|
+ containerHeight: '300px',
|
|
|
+ device_type_id:'',
|
|
|
+ cmd:'sy',
|
|
|
+ pestDict: {}, // 虫子字典 {id: name}
|
|
|
+ pestColorMap: {}, // 害虫颜色映射 {pestName: color}
|
|
|
+ };
|
|
|
+ },
|
|
|
+ async onLoad(options) {
|
|
|
+ const {cmd,img_id,currentYear,addtime,device_type_id,device_id} = options
|
|
|
+ this.device_id = device_id
|
|
|
+ this.imgOld_id = img_id
|
|
|
+ this.currentYear = currentYear
|
|
|
+ this.addtime = addtime;
|
|
|
+ this.device_type_id = device_type_id;
|
|
|
+ this.time_begin = this.addtime;
|
|
|
+ console.log(this.time_begin,'thistime_begin')
|
|
|
+ this.defaultDate = this.addtime;
|
|
|
+ this.time_end = this.addtime;
|
|
|
+ this.selectorRange = [];
|
|
|
+ this.cmd = cmd;
|
|
|
+ const nowYear = new Date().getFullYear();
|
|
|
+ for(let i = 0;i<50;i++){
|
|
|
+ const item = {
|
|
|
+ label: nowYear - i,
|
|
|
+ id: nowYear - i
|
|
|
+ }
|
|
|
+ this.selectorRange.push(item);
|
|
|
+ }
|
|
|
+ this.pestList = [];
|
|
|
+ await this.getPestDict();
|
|
|
+ await this.getPestLevelMap();
|
|
|
+ await this.getPestList();
|
|
|
+ // this.getDevicePhotoDetails();
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ getPestName(id){
|
|
|
+ if(this.is_mark == 0){
|
|
|
+ return this.pestDict[id] || id;
|
|
|
+ }
|
|
|
+ return id;
|
|
|
+ },
|
|
|
+ async confirmHandler(e){
|
|
|
+ this.currentYear = this.selectorRange[e].id;
|
|
|
+ if(this.currentYear == new Date().getFullYear()){
|
|
|
+ this.time_begin = this.formatTime(new Date(new Date().getFullYear(), 0, 1));
|
|
|
+ this.time_end = this.formatTime(new Date());
|
|
|
+ this.maxDate = this.formatTime(new Date());
|
|
|
+ this.minDate = this.formatTime(new Date(new Date().getFullYear(), 0, 1));
|
|
|
+ }else{
|
|
|
+ this.time_begin = this.formatTime(new Date(this.currentYear, 0, 1));
|
|
|
+ this.time_end = this.formatTime(new Date(this.currentYear, 11, 31));
|
|
|
+ this.maxDate = this.formatTime(new Date(this.currentYear, 11, 31));
|
|
|
+ this.minDate = this.formatTime(new Date(this.currentYear, 0, 1));
|
|
|
+ this.defaultDate = this.minDate;
|
|
|
+ }
|
|
|
+ this.showPicker = false;
|
|
|
+ this.pestList = [];
|
|
|
+ this.thumbnails = [];
|
|
|
+ await this.getPestList();
|
|
|
+ },
|
|
|
+ async handleChange(e){
|
|
|
+ console.log(e,'e')
|
|
|
+ this.time_begin = e.result;
|
|
|
+ this.time_end = e.result;
|
|
|
+ this.pestList = [];
|
|
|
+ await this.getPestList()
|
|
|
+ this.currentImg = {};
|
|
|
+ },
|
|
|
+ getPestColor(pestName) {
|
|
|
+ // 如果该害虫已有颜色,直接返回
|
|
|
+ if (this.pestColorMap[pestName]) {
|
|
|
+ return this.pestColorMap[pestName];
|
|
|
+ }
|
|
|
+ // 为新害虫分配颜色
|
|
|
+ const usedColors = Object.values(this.pestColorMap);
|
|
|
+ // 找一个未使用的颜色
|
|
|
+ let color;
|
|
|
+ for (const c of this.colors) {
|
|
|
+ if (!usedColors.includes(c)) {
|
|
|
+ color = c;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果所有颜色都用完了,使用哈希值确定颜色
|
|
|
+ if (!color) {
|
|
|
+ const hash = pestName.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
|
|
+ color = this.colors[hash % this.colors.length];
|
|
|
+ }
|
|
|
+ this.pestColorMap[pestName] = color;
|
|
|
+ return color;
|
|
|
+ },
|
|
|
+ getLevelDisplayName(level) {
|
|
|
+ const levelMap = {
|
|
|
+ '-1': '其他害虫',
|
|
|
+ 1: '一类害虫',
|
|
|
+ 2: '二类害虫',
|
|
|
+ 3: '三类害虫',
|
|
|
+ 4: '四类害虫',
|
|
|
+ 5: '五类害虫'
|
|
|
+ };
|
|
|
+ return levelMap[String(level)] || `${level}`;
|
|
|
+ },
|
|
|
+ formatMinute(date,type){
|
|
|
+ // 转成毫秒数
|
|
|
+ if(type == 'start'){
|
|
|
+ //转成开始时间的毫秒数
|
|
|
+ date.setHours(0, 0, 0, 0);
|
|
|
+ }else{
|
|
|
+ //转成结束时间的毫秒数
|
|
|
+ date.setHours(23, 59, 59, 999);
|
|
|
+ }
|
|
|
+ const minute = Math.floor(date.getTime() / 1000);
|
|
|
+ return minute;
|
|
|
+ },
|
|
|
+ async getPestList() {
|
|
|
+ const res = await this.$myRequest({
|
|
|
+ url: '/api/api_gateway?method=new_gateway.photo_info.photo_list',
|
|
|
+ method: 'POST',
|
|
|
+ data: {
|
|
|
+ page:1,
|
|
|
+ page_size:500,
|
|
|
+ id: this.device_id,
|
|
|
+ start: this.formatMinute(new Date(this.time_begin),'start'),
|
|
|
+ end: this.formatMinute(new Date(this.time_end),'end'),
|
|
|
+ device_type_id: this.device_type_id,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ this.thumbnails = res?.data || [];
|
|
|
+ this.currentImg = {};
|
|
|
+ //如果和旧的id相同,就用旧的id不然就用第一个
|
|
|
+ if(this.thumbnails.find(item => item.ids == this.imgOld_id)){
|
|
|
+ this.img_id = this.imgOld_id
|
|
|
+ }else{
|
|
|
+ this.img_id = this.thumbnails[0].ids
|
|
|
+ }
|
|
|
+ this.getDevicePhotoDetails();
|
|
|
+ },
|
|
|
+ formatTime(dateString) {
|
|
|
+ const date = new Date(dateString);
|
|
|
+ const year = date.getFullYear();
|
|
|
+ const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
|
+ const day = String(date.getDate()).padStart(2, '0');
|
|
|
+ return `${year}-${month}-${day}`;
|
|
|
+ },
|
|
|
+ async getPestLevelMap() {
|
|
|
+ const res = await this.$myRequest({
|
|
|
+ url: '/api/api_gateway?method=forecast.new_cbd.pest_level_map',
|
|
|
+ method: 'POST',
|
|
|
+ });
|
|
|
+ const pestYype = {}
|
|
|
+ for(let key in res){
|
|
|
+ pestYype[this.getLevelDisplayName(key)] = res[key]
|
|
|
+ }
|
|
|
+ this.pestYype = pestYype
|
|
|
+ },
|
|
|
+ // 获取虫子字典
|
|
|
+ async getPestDict() {
|
|
|
+ try {
|
|
|
+ const res = await this.$myRequest({
|
|
|
+ url: '/api/api_gateway?method=forecast.pest_info.pest_dict',
|
|
|
+ method: 'POST',
|
|
|
+ data:{
|
|
|
+ type_name: '1'
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.pestDict = res || {};
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取虫子字典失败:', error);
|
|
|
+ this.pestDict = {};
|
|
|
+ }
|
|
|
+ },
|
|
|
+ formatDate(dateString) {
|
|
|
+ const date = new Date(dateString*1000);
|
|
|
+ const year = date.getFullYear();
|
|
|
+ const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
|
+ const day = String(date.getDate()).padStart(2, '0');
|
|
|
+ const hour = String(date.getHours()).padStart(2, '0');
|
|
|
+ const minute = String(date.getMinutes()).padStart(2, '0');
|
|
|
+ const second = String(date.getSeconds()).padStart(2, '0');
|
|
|
+ return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
|
|
|
+ },
|
|
|
+ async getDevicePhotoDetails() {
|
|
|
+ const res = await this.$myRequest({
|
|
|
+ url: '/api/api_gateway?method=forecast.forecast_system.device_photo_details',
|
|
|
+ method: 'POST',
|
|
|
+ data: {
|
|
|
+ identify_model:'B',
|
|
|
+ cmd:this.cmd,
|
|
|
+ img_id: this.img_id,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ this.currentImg = res;
|
|
|
+ // 处理label参数生成bugMarkers
|
|
|
+ this.processBugMarkers();
|
|
|
+ const pest_list = res.pest_list
|
|
|
+ const pestArr = new Map()
|
|
|
+ const pesAlltList = []
|
|
|
+ for(let key in this.pestYype){
|
|
|
+ for(let j in this.pestYype[key]){
|
|
|
+ const pestName = this.pestYype[key][j]
|
|
|
+ pesAlltList.push(pestName)
|
|
|
+ pest_list.forEach(item => {
|
|
|
+ if(item.pest_name == pestName){
|
|
|
+ if(pestArr.has(key)){
|
|
|
+ pestArr.get(key).push(item)
|
|
|
+ }else{
|
|
|
+ pestArr.set(key, [item])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pest_list.forEach(item => {
|
|
|
+ if(!pesAlltList.includes(item.pest_name)){
|
|
|
+ if(pestArr.has('其他害虫')){
|
|
|
+ pestArr.get('其他害虫').push(item)
|
|
|
+ }else{
|
|
|
+ pestArr.set('其他害虫', [item])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ const pestList = []
|
|
|
+ for(let key of pestArr){
|
|
|
+ pestList.push(key)
|
|
|
+ }
|
|
|
+ if (this.currentImg.is_mark != 0) {
|
|
|
+ this.processBugMarkers();
|
|
|
+ }
|
|
|
+ this.pestList = pestList
|
|
|
+ },
|
|
|
+ onImageLoad(e) {
|
|
|
+ this.imageWidth = e.detail.width;
|
|
|
+ this.imageHeight = e.detail.height;
|
|
|
+
|
|
|
+ // 计算容器显示高度(根据屏幕宽度和图片宽高比)
|
|
|
+ const systemInfo = uni.getSystemInfoSync();
|
|
|
+ const screenWidth = systemInfo.windowWidth;
|
|
|
+ const containerWidth = screenWidth - 24; // 减去左右margin (24rpx ≈ 12px)
|
|
|
+ const displayHeight = (containerWidth / this.imageWidth) * this.imageHeight;
|
|
|
+
|
|
|
+ this.containerHeight = displayHeight + 'px';
|
|
|
+ console.log('图片尺寸:', this.imageWidth, this.imageHeight, '容器高度:', this.containerHeight);
|
|
|
+
|
|
|
+ // 图片加载完成后处理bugMarkers
|
|
|
+ this.processBugMarkers();
|
|
|
+ },
|
|
|
+
|
|
|
+ processBugMarkers() {
|
|
|
+ if (this.currentImg.is_mark === 0) {
|
|
|
+ if (!this.currentImg.label) {
|
|
|
+ console.log('没有label参数');
|
|
|
+ this.bugMarkers = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果没有图片尺寸,先设置默认值
|
|
|
+ if (!this.imageWidth || !this.imageHeight) {
|
|
|
+ console.log('没有图片尺寸,使用默认值');
|
|
|
+ this.imageWidth = 1000;
|
|
|
+ this.imageHeight = 1000;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 根据原图宽度计算缩放比例
|
|
|
+ let scaleRatio;
|
|
|
+ if (this.imageWidth >= 5000) {
|
|
|
+ scaleRatio = 1;
|
|
|
+ } else if (this.imageWidth >= 4000) {
|
|
|
+ scaleRatio = 1;
|
|
|
+ } else {
|
|
|
+ scaleRatio = 1;
|
|
|
+ }
|
|
|
+ // 处理label参数,将单引号替换为双引号
|
|
|
+ let labelStr = this.currentImg.label;
|
|
|
+ labelStr = labelStr.replace(/'/g, '"');
|
|
|
+ console.log(labelStr,'labelStrlabelStr')
|
|
|
+ const label = JSON.parse(labelStr);
|
|
|
+ const markers = [];
|
|
|
+
|
|
|
+ console.log('原图宽度:', this.imageWidth, '缩放比例:', scaleRatio);
|
|
|
+
|
|
|
+ label.forEach(item => {
|
|
|
+ for (let key in item) {
|
|
|
+ const [x1, y1, x2, y2] = item[key];
|
|
|
+ // 使用缩放比例计算标记位置和尺寸
|
|
|
+ const x = (x1 * scaleRatio / this.imageWidth) * 100;
|
|
|
+ const y = (y1 * scaleRatio / this.imageHeight) * 100;
|
|
|
+ const width = ((x2 - x1) * scaleRatio / this.imageWidth) * 100;
|
|
|
+ const height = ((y2 - y1) * scaleRatio / this.imageHeight) * 100;
|
|
|
+
|
|
|
+ // 从字典中获取虫子名字(尝试字符串和数字两种类型)
|
|
|
+ const pestName = this.pestDict[key] || this.pestDict[String(key)] || key;
|
|
|
+ const color = this.getPestColor(pestName);
|
|
|
+
|
|
|
+ markers.push({
|
|
|
+ id: pestName, // 显示虫子名字
|
|
|
+ x,
|
|
|
+ y,
|
|
|
+ width,
|
|
|
+ height,
|
|
|
+ color
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.bugMarkers = markers;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('处理label参数失败:', error);
|
|
|
+ this.bugMarkers = [];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // this.pestList = [];
|
|
|
+ const markers = [];
|
|
|
+ // 根据原图宽度计算缩放比例
|
|
|
+ let scaleRatio = 3.1;
|
|
|
+ // if (this.imageWidth >= 5000) {
|
|
|
+ // scaleRatio = 4;
|
|
|
+ // } else if (this.imageWidth >= 4000) {
|
|
|
+ // scaleRatio = 1;
|
|
|
+ // } else {
|
|
|
+ // scaleRatio = 2.5;
|
|
|
+ // }
|
|
|
+ // const pestArr = new Map()
|
|
|
+ this.currentImg.mark.map((item, index) => {
|
|
|
+ // if(pestArr.has(item.text)){
|
|
|
+ // pestArr.set(item.text,{
|
|
|
+ // value: pestArr.get(item.text).value+=1,
|
|
|
+ // text: item.text
|
|
|
+ // })
|
|
|
+ // }else{
|
|
|
+ // pestArr.set(item.text, {
|
|
|
+ // value: 1,
|
|
|
+ // text: item.text
|
|
|
+ // })
|
|
|
+ // }
|
|
|
+ // const pestList = []
|
|
|
+ // for(let key of pestArr){
|
|
|
+ // pestList.push(key)
|
|
|
+ // }
|
|
|
+ // this.pestList = pestList
|
|
|
+ this.is_mark = 1
|
|
|
+ const { startX, startY,text } = item;
|
|
|
+ // 使用缩放比例计算标记位置和尺寸
|
|
|
+ const x = item.width > 0 ? (startX * scaleRatio / this.imageWidth) * 105 : ((startX + item.width) * scaleRatio / this.imageWidth) * 105;
|
|
|
+ const y = item.height > 0 ? (startY * scaleRatio / this.imageHeight) * 105 : ((startY + item.height) * scaleRatio / this.imageHeight) * 105;
|
|
|
+ const width = (item.width > 0 ? item.width : -item.width) * scaleRatio / this.imageWidth * 100;
|
|
|
+ const height = (item.height > 0 ? item.height : -item.height) * scaleRatio / this.imageHeight * 100;
|
|
|
+
|
|
|
+ // 从字典中获取虫子名字(尝试字符串和数字两种类型)
|
|
|
+ const pestName = text;
|
|
|
+ const color = this.getPestColor(text);
|
|
|
+
|
|
|
+ markers.push({
|
|
|
+ id: pestName, // 显示虫子名字
|
|
|
+ x,
|
|
|
+ y,
|
|
|
+ width,
|
|
|
+ height,
|
|
|
+ color
|
|
|
+ });
|
|
|
+ });
|
|
|
+ this.bugMarkers = markers;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleBack() {
|
|
|
+ uni.navigateBack({
|
|
|
+ delta: 1
|
|
|
+ });
|
|
|
+ },
|
|
|
+ goBack() {
|
|
|
+ uni.navigateBack();
|
|
|
+ },
|
|
|
+ selectThumbnail(item) {
|
|
|
+ this.img_id = item.ids;
|
|
|
+ this.getDevicePhotoDetails();
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+::v-deep .u-calendar__action{
|
|
|
+ display:flex;
|
|
|
+ justify-content: space-between;
|
|
|
+}
|
|
|
+::v-deep .u-hover-class{
|
|
|
+ .u-calendar__content__item__inner{
|
|
|
+ color:#aaa !important;
|
|
|
+ }
|
|
|
+}
|
|
|
+.device-photo-page {
|
|
|
+ background-color: #F5F5F5;
|
|
|
+ min-height: 100vh;
|
|
|
+ width: 100%;
|
|
|
+ padding-top: 112rpx;
|
|
|
+ background: linear-gradient(180deg, #ffffff00 0%, #F5F6FA 23.64%, #F5F6FA 100%), linear-gradient(102deg, #BFEADD 6.77%, #B8F1E7 40.15%, #B9EEF5 84.02%);
|
|
|
+ .device-detail__header {
|
|
|
+ width: 100%;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #999;
|
|
|
+ color: #042118;
|
|
|
+ font-family: 'Source Han Sans CN VF';
|
|
|
+ font-weight: 700;
|
|
|
+ position: relative;
|
|
|
+ text-align: center;
|
|
|
+ .arrow-left {
|
|
|
+ position: absolute;
|
|
|
+ left: 32rpx;
|
|
|
+ margin-right: 12rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 顶部导航栏 */
|
|
|
+ .nav-bar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 24rpx;
|
|
|
+ background-color: #E6F7EF;
|
|
|
+
|
|
|
+ .nav-left {
|
|
|
+ .back-icon {
|
|
|
+ font-size: 36rpx;
|
|
|
+ color: #042118;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .nav-title {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #042118;
|
|
|
+ }
|
|
|
+
|
|
|
+ .nav-right {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ .more-icon {
|
|
|
+ font-size: 32rpx;
|
|
|
+ color: #042118;
|
|
|
+ margin-right: 24rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .eye-icon {
|
|
|
+ font-size: 32rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .date-container{
|
|
|
+ padding: 0 20rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ .select-year{
|
|
|
+ width: 150rpx;
|
|
|
+ height: 80rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-around;
|
|
|
+ color: #656565;
|
|
|
+ font-size: 26rpx;
|
|
|
+ line-height: 80rpx;
|
|
|
+ text-align: center;
|
|
|
+ border-radius: 48rpx;
|
|
|
+ background-color: #FFFFFF;
|
|
|
+ margin-right: 10rpx;
|
|
|
+ padding: 0 26rpx;
|
|
|
+ .select-year-item{
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-around;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* 日期选择器 */
|
|
|
+ .date-picker {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 20rpx 24rpx;
|
|
|
+ background-color: #FFFFFF;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+ width: 100%;
|
|
|
+ margin:20rpx auto;
|
|
|
+ border-radius: 48rpx;
|
|
|
+ position: relative;
|
|
|
+ .date-input {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ width: 100%;
|
|
|
+ text-align: center;
|
|
|
+ .date-label {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #999999;
|
|
|
+ margin-bottom: 8rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .date-value {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #042118;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .calendar {
|
|
|
+ position: absolute;
|
|
|
+ right: 24rpx;
|
|
|
+ top: 50%;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ font-size: 32rpx;
|
|
|
+ color: #999999;
|
|
|
+ }
|
|
|
+ .date-separator {
|
|
|
+ margin: 0 24rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #999999;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 主图片区域 */
|
|
|
+ .main-photo {
|
|
|
+ position: relative;
|
|
|
+ margin: 0 24rpx 24rpx;
|
|
|
+ background-color: #FFFFFF;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ padding: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ .movable-area {
|
|
|
+ width: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ .movable-view {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .image-container {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .main-photo-image {
|
|
|
+ width: 100%;
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 虫子标记层 */
|
|
|
+ .bug-markers {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ pointer-events: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 虫子标记 */
|
|
|
+ .bug-marker {
|
|
|
+ position: absolute;
|
|
|
+ border: 2rpx solid;
|
|
|
+ border-radius: 4rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 虫子标记标签 */
|
|
|
+ .bug-label {
|
|
|
+ position: absolute;
|
|
|
+ top: -24rpx;
|
|
|
+ left: 0;
|
|
|
+ padding: 2rpx 6rpx;
|
|
|
+ border-radius: 4rpx;
|
|
|
+ font-size: 20rpx;
|
|
|
+ color: white;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 虫子标记层 */
|
|
|
+ .bug-markers {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ pointer-events: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 虫子标记 */
|
|
|
+ .bug-marker {
|
|
|
+ position: absolute;
|
|
|
+ border: 2rpx solid;
|
|
|
+ border-radius: 4rpx;
|
|
|
+ pointer-events: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 虫子标记标签 */
|
|
|
+ .bug-label {
|
|
|
+ position: absolute;
|
|
|
+ top: -30rpx;
|
|
|
+ left: 0;
|
|
|
+ padding: 4rpx 8rpx;
|
|
|
+ border-radius: 4rpx;
|
|
|
+ font-size: 20rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+
|
|
|
+ .photo-timestamp {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0rpx;
|
|
|
+ left: 0rpx;
|
|
|
+ width:100%;
|
|
|
+ background-color: rgba(0, 0, 0, 0.6);
|
|
|
+ color: #FFFFFF;
|
|
|
+ padding: 8rpx 16rpx;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 缩略图预览 */
|
|
|
+ .thumbnail-preview {
|
|
|
+ margin: 0 24rpx 24rpx;
|
|
|
+
|
|
|
+ .thumbnail-scroll {
|
|
|
+ gap: 16rpx;
|
|
|
+ padding-bottom: 16rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow-x: auto;
|
|
|
+ overflow-y: hidden;
|
|
|
+ width: 100%;
|
|
|
+ // 隐藏滚动条
|
|
|
+ -ms-overflow-style: none;
|
|
|
+ scrollbar-width: none;
|
|
|
+ .thumbnail-item {
|
|
|
+ width: 120rpx;
|
|
|
+ height: 120rpx;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ overflow: hidden;
|
|
|
+ border: 2rpx solid transparent;
|
|
|
+ display: inline-block;
|
|
|
+ box-sizing: border-box;
|
|
|
+ margin-right: 10rpx;
|
|
|
+ &.active {
|
|
|
+ border-color: #0BBC58;
|
|
|
+ }
|
|
|
+
|
|
|
+ .thumbnail-image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: cover;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 识别结果 */
|
|
|
+ .recognition-result {
|
|
|
+ margin: 0 24rpx 24rpx;
|
|
|
+ background-color: #FFFFFF;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+
|
|
|
+ .result-title {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #042118;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 害虫类别 */
|
|
|
+ .pest-category {
|
|
|
+ margin-bottom: 32rpx;
|
|
|
+ border: 1px solid #E4E7ED;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .category-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+ background: #F6F8FC;
|
|
|
+ padding: 18rpx 24rpx;
|
|
|
+ .category-title {
|
|
|
+ font-size: 24rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #042118;
|
|
|
+ }
|
|
|
+
|
|
|
+ .category-count {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #999999;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .pest-item {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+ padding: 6rpx 24rpx;
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .pest-info {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ .pest-color {
|
|
|
+ width: 16rpx;
|
|
|
+ height: 16rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 12rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .pest-name {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #042118;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .pest-count {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #042118;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|