|
|
@@ -10,41 +10,129 @@
|
|
|
></album-draw-box>
|
|
|
</template>
|
|
|
</photo-provider> -->
|
|
|
- <div
|
|
|
- class="carousel-img"
|
|
|
- v-for="(photo, index) in images"
|
|
|
- :key="index"
|
|
|
- >
|
|
|
+ <div class="carousel-img" v-for="(photo, index) in images" :key="index">
|
|
|
<div class="label-text" v-if="labelText">{{ labelText }}</div>
|
|
|
<img class="img-dom" :index="index" @click="clickPhoto(photo)" :src="getPhotoSrc(photo)" alt="" />
|
|
|
- <div class="carousel-img-mask" v-if="!isAchievementImgs">
|
|
|
- <div class="mask-content">
|
|
|
- <div class="mask-line line-top">
|
|
|
- <span class="date-text">{{ imgData?.executeDate }}</span>
|
|
|
- <span class="line-separator">|</span>
|
|
|
- <span class="executor-text">执行人:{{ imgData?.executeName }}</span>
|
|
|
+
|
|
|
+ <div class="carousel-img-mask app-mask" v-if="!isAchievementImgs && imgType === 'app'">
|
|
|
+ <div class="mask-content app-mask-content">
|
|
|
+ <div class="app-mask-top">
|
|
|
+ <div class="app-mask-top-left">
|
|
|
+ <div class="app-year">{{ formatYear(imgData?.createTime || imgData?.updateTime) }}</div>
|
|
|
+ <div class="app-date-wrapper">
|
|
|
+ <div class="app-date-line"></div>
|
|
|
+ <div class="app-date">
|
|
|
+ {{ formatMonthDay(imgData?.createTime || imgData?.updateTime) }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="app-mask-top-right">
|
|
|
+ <div class="app-phenology">当前处于 {{ imgData?.phenologyName }}</div>
|
|
|
+ <div class="app-uploader">上传人:{{ imgData?.sourceDataJson?.userName }}</div>
|
|
|
+ </div>
|
|
|
+ <!-- 底部中间/右侧:天气信息和位置 -->
|
|
|
+ <div class="app-mask-bottom">
|
|
|
+ <div class="app-weather-info">
|
|
|
+ <div class="app-weather-item">
|
|
|
+ <img class="app-weather-icon" src="@/assets/watermark/temp.png" alt="" />
|
|
|
+ <span
|
|
|
+ >{{ imgData?.sourceDataJson?.suitability?.tempMin }}-{{
|
|
|
+ imgData?.sourceDataJson?.suitability?.tempMax
|
|
|
+ }}℃ {{ imgData?.sourceDataJson?.suitability?.tempSuitability }}</span
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ <div class="app-weather-item">
|
|
|
+ <img class="app-weather-icon" src="@/assets/watermark/shidu.png" alt="" />
|
|
|
+ <span>{{ imgData?.sourceDataJson?.suitability?.humiditySuitability }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="app-weather-item">
|
|
|
+ <img class="app-weather-icon" src="@/assets/watermark/fushe.png" alt="" />
|
|
|
+ <span>{{ imgData?.sourceDataJson?.suitability?.vindexSuitability }}</span>
|
|
|
+ </div>
|
|
|
+ <!-- <span class="app-weather-separator" v-if="imgData?.sourceDataJson?.address">-</span>
|
|
|
+ <span class="app-location">
|
|
|
+ {{ imgData?.sourceDataJson?.address }}
|
|
|
+ </span> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="mask-line line-middle">
|
|
|
- <span class="work-name">{{ imgData?.farmWorkName }}</span>
|
|
|
- <span class="line-separator">|</span>
|
|
|
- <span class="location-text">
|
|
|
- <img src="@/assets/watermark/address.png" alt="location" class="location-icon" />
|
|
|
- {{ imgData?.farmName }}
|
|
|
- </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="carousel-img-mask app-mask" v-else-if="!isAchievementImgs && imgType === 'dji'">
|
|
|
+ <div class="mask-content app-mask-content">
|
|
|
+ <div class="dji-mask-top">
|
|
|
+ <span>{{ imgData?.sourceDataJson?.resFilename?.[index]?.treeCode }}</span>
|
|
|
+ <span>蓬径:{{ imgData?.sourceDataJson?.resFilename?.[index]?.pengjing }}m</span>
|
|
|
+ <span>高度:{{ imgData?.sourceDataJson?.resFilename?.[index]?.height.toFixed(1) }}m</span>
|
|
|
+ <span>{{ imgData?.sourceDataJson?.resFilename?.[index]?.highYield === 1 ? '高产树' : '低产树' }}</span>
|
|
|
+ <span>{{ imgData?.sourceDataJson?.resFilename?.[index]?.pingzhong }}</span>
|
|
|
</div>
|
|
|
- <div class="mask-line line-bottom">
|
|
|
- <span class="prescription-text">药物处方:{{ prescriptionText }}</span>
|
|
|
+ <div class="app-mask-bottom">
|
|
|
+ <div class="app-weather-info">
|
|
|
+ <div class="app-weather-item">
|
|
|
+ <img class="app-weather-icon" src="@/assets/watermark/temp.png" alt="" />
|
|
|
+ <span
|
|
|
+ >{{ imgData?.sourceDataJson?.suitability?.tempMin }}-{{
|
|
|
+ imgData?.sourceDataJson?.suitability?.tempMax
|
|
|
+ }}℃ {{ imgData?.sourceDataJson?.suitability?.tempSuitability }}</span
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ <div class="app-weather-item">
|
|
|
+ <img class="app-weather-icon" src="@/assets/watermark/shidu.png" alt="" />
|
|
|
+ <span>{{ imgData?.sourceDataJson?.suitability?.humiditySuitability }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="app-weather-item">
|
|
|
+ <img class="app-weather-icon" src="@/assets/watermark/fushe.png" alt="" />
|
|
|
+ <span>{{ imgData?.sourceDataJson?.suitability?.vindexSuitability }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="garden-info">
|
|
|
+ <span class="drone-date">{{ imgData?.droneDate }}</span>
|
|
|
+ <span class="code van-ellipsis">{{ imgData?.sourceDataJson?.resFilename?.[index]?.longCode }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="base-map-wrapper" v-if="imgData?.sourceDataJson?.resFilename?.[index]?.baseMap">
|
|
|
+ <img
|
|
|
+ class="base-map-img"
|
|
|
+ :src="imgData?.sourceDataJson?.resFilename?.[index]?.baseMap"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="carousel-img-mask" v-if="isAchievementImgs && imgData?.reCheckText">
|
|
|
- <div class="mask-content">
|
|
|
- <div class="review-effect-text">复核成效</div>
|
|
|
- <div class="review-effect-content">
|
|
|
- <span class="review-effect-content-text">{{ imgData?.reCheckText }}</span>
|
|
|
+
|
|
|
+ <template v-else>
|
|
|
+ <div class="carousel-img-mask" v-if="!isAchievementImgs">
|
|
|
+ <div class="mask-content">
|
|
|
+ <div class="mask-line line-top">
|
|
|
+ <span class="date-text">{{ imgData?.executeDate }}</span>
|
|
|
+ <span class="line-separator">|</span>
|
|
|
+ <span class="executor-text">执行人:{{ imgData?.executeName }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="mask-line line-middle">
|
|
|
+ <span class="work-name">{{ imgData?.farmWorkName }}</span>
|
|
|
+ <span class="line-separator">|</span>
|
|
|
+ <span class="location-text">
|
|
|
+ <img src="@/assets/watermark/address.png" alt="location" class="location-icon" />
|
|
|
+ {{ imgData?.farmName }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="mask-line line-bottom">
|
|
|
+ <span class="prescription-text">药物处方:{{ prescriptionText }}</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ <div class="carousel-img-mask" v-if="isAchievementImgs && imgData?.reCheckText">
|
|
|
+ <div class="mask-content">
|
|
|
+ <div class="review-effect-text">复核成效</div>
|
|
|
+ <div class="review-effect-content">
|
|
|
+ <span class="review-effect-content-text">{{ imgData?.reCheckText }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
@@ -74,7 +162,6 @@
|
|
|
<img src="@/assets/watermark/address.png" alt="location" class="location-icon" />
|
|
|
{{ imgData?.farmName }}
|
|
|
</span>
|
|
|
-
|
|
|
</div>
|
|
|
<div class="mask-line line-bottom">
|
|
|
<span class="prescription-text">药物处方:{{ prescriptionText }}</span>
|
|
|
@@ -99,9 +186,7 @@
|
|
|
<!-- 底部操作按钮 -->
|
|
|
<div class="bottom-actions" @click.stop="showPopup = false">
|
|
|
<div class="action-buttons">
|
|
|
- <div class="action-btn text-btn">
|
|
|
- <<长按图片保存或转发>>
|
|
|
- </div>
|
|
|
+ <div class="action-btn text-btn"><<长按图片保存或转发>></div>
|
|
|
<!-- <div class="action-btn green-btn" @click.stop="handleWechat">
|
|
|
<div class="icon-circle">
|
|
|
<img src="@/assets/img/home/wechat.png" alt="" />
|
|
|
@@ -145,8 +230,16 @@ const props = defineProps({
|
|
|
type: Object,
|
|
|
default: () => {},
|
|
|
},
|
|
|
+ imgType: {
|
|
|
+ type: String,
|
|
|
+ default: "",
|
|
|
+ },
|
|
|
+ disableClick: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ },
|
|
|
});
|
|
|
-const { images, labelText, isAchievementImgs } = toRefs(props);
|
|
|
+const { images, labelText, isAchievementImgs, imgType, disableClick } = toRefs(props);
|
|
|
let timer = null;
|
|
|
const currentIndex = ref(0);
|
|
|
|
|
|
@@ -159,29 +252,49 @@ onUnmounted(() => {
|
|
|
clearInterval(timer);
|
|
|
});
|
|
|
|
|
|
-
|
|
|
-watch(() => props.imgData, (newVal) => {
|
|
|
- if (newVal && newVal.prescriptionList) {
|
|
|
- prescriptionText.value = buildPrescriptionText(newVal.prescriptionList);
|
|
|
+watch(
|
|
|
+ () => props.imgData,
|
|
|
+ (newVal) => {
|
|
|
+ if (newVal && newVal.prescriptionList) {
|
|
|
+ prescriptionText.value = buildPrescriptionText(newVal.prescriptionList);
|
|
|
+ }
|
|
|
}
|
|
|
-});
|
|
|
-
|
|
|
+);
|
|
|
|
|
|
const prescriptionText = ref("");
|
|
|
function buildPrescriptionText(list) {
|
|
|
- if (!list || !Array.isArray(list) || list.length === 0 || list[0]?.pesticideFertilizerList?.length === 0) {
|
|
|
+ if (!list || !Array.isArray(list) || list.length === 0) {
|
|
|
return "无处方";
|
|
|
}
|
|
|
try {
|
|
|
- return list
|
|
|
- .map((group) =>
|
|
|
- (group.pesticideFertilizerList || [])
|
|
|
- .map((p) => p.defaultName || p.pesticideFertilizerName || "")
|
|
|
- .filter(Boolean)
|
|
|
- .join("+")
|
|
|
- )
|
|
|
- .filter(Boolean)
|
|
|
- .join("+");
|
|
|
+ // 兼容原有格式:嵌套结构 [{ pesticideFertilizerList: [...] }]
|
|
|
+ if (list[0]?.pesticideFertilizerList) {
|
|
|
+ const result = list
|
|
|
+ .map((group) =>
|
|
|
+ (group.pesticideFertilizerList || [])
|
|
|
+ .map((p) => p.defaultName || p.pesticideFertilizerName || "")
|
|
|
+ .filter(Boolean)
|
|
|
+ .join("+")
|
|
|
+ )
|
|
|
+ .filter(Boolean)
|
|
|
+ .join("+");
|
|
|
+ return result || "无处方";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 兼容新格式:直接是字符串数组 ["药物1", "药物2"]
|
|
|
+ if (typeof list[0] === "string") {
|
|
|
+ return list.filter(Boolean).join("+") || "无处方";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 兼容新格式:对象数组 [{ defaultName: "xxx" }, { defaultName: "yyy" }]
|
|
|
+ if (list[0]?.defaultName || list[0]?.pesticideFertilizerName) {
|
|
|
+ return list
|
|
|
+ .map((p) => p.defaultName || p.pesticideFertilizerName || "")
|
|
|
+ .filter(Boolean)
|
|
|
+ .join("+") || "无处方";
|
|
|
+ }
|
|
|
+
|
|
|
+ return "无处方";
|
|
|
} catch {
|
|
|
return "无处方";
|
|
|
}
|
|
|
@@ -246,6 +359,9 @@ const previewCanvas = ref(null);
|
|
|
|
|
|
const currentImgRef = ref(null);
|
|
|
const clickPhoto = (photo) => {
|
|
|
+ if (disableClick.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
currentPhoto.value = getPhotoSrc(photo);
|
|
|
nextTick(async () => {
|
|
|
const canvas = await html2canvas(currentImgRef.value, {
|
|
|
@@ -269,7 +385,7 @@ const clickPhoto = (photo) => {
|
|
|
};
|
|
|
|
|
|
const handleSaveImage = () => {
|
|
|
- downloadImage(previewCanvas.value, '执行照片');
|
|
|
+ downloadImage(previewCanvas.value, "执行照片");
|
|
|
};
|
|
|
|
|
|
function downloadImage(dataUrl, filename) {
|
|
|
@@ -287,6 +403,24 @@ const getPhotoSrc = (photo) => {
|
|
|
// }
|
|
|
return base_img_url2 + (photo.cloudFilename ? photo.cloudFilename : photo);
|
|
|
};
|
|
|
+
|
|
|
+// 格式化年份
|
|
|
+const formatYear = (dateStr) => {
|
|
|
+ if (!dateStr) return "";
|
|
|
+ const date = new Date(dateStr);
|
|
|
+ if (Number.isNaN(date.getTime())) return "";
|
|
|
+ return date.getFullYear().toString();
|
|
|
+};
|
|
|
+
|
|
|
+// 格式化月/日
|
|
|
+const formatMonthDay = (dateStr) => {
|
|
|
+ if (!dateStr) return "";
|
|
|
+ const date = new Date(dateStr);
|
|
|
+ if (Number.isNaN(date.getTime())) return "";
|
|
|
+ const m = date.getMonth() + 1;
|
|
|
+ const d = date.getDate();
|
|
|
+ return `${m}/${d}`;
|
|
|
+};
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
@@ -368,11 +502,137 @@ const getPhotoSrc = (photo) => {
|
|
|
padding: 8px 12px;
|
|
|
box-sizing: border-box;
|
|
|
border-radius: 8px 8px 12px 12px;
|
|
|
+ &.app-mask {
|
|
|
+ padding: 0;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
.mask-content {
|
|
|
width: 100%;
|
|
|
color: #ffffff;
|
|
|
font-size: 10px;
|
|
|
line-height: 15px;
|
|
|
+ &.app-mask-content {
|
|
|
+ padding: 10px 8px;
|
|
|
+ font-size: 12px;
|
|
|
+ background: rgba(0, 0, 0, 0.2);
|
|
|
+ backdrop-filter: blur(4px);
|
|
|
+ .dji-mask-top {
|
|
|
+ background: rgba(0, 0, 0, 0.4);
|
|
|
+ backdrop-filter: blur(4px);
|
|
|
+ border-radius: 5px 0 5px 0;
|
|
|
+ padding: 6px 11px;
|
|
|
+ position: absolute;
|
|
|
+ top: -203px;
|
|
|
+ left: 0;
|
|
|
+ display: flex;
|
|
|
+ gap: 9px;
|
|
|
+ font-size: 10px;
|
|
|
+ }
|
|
|
+ .garden-info {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-top: 4px;
|
|
|
+ width: calc(100% - 125px);
|
|
|
+ .code {
|
|
|
+ font-size: 10px;
|
|
|
+ opacity: 0.5;
|
|
|
+ margin-left: 5px;
|
|
|
+ width: 100%;
|
|
|
+ display: inline-block;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .base-map-wrapper {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 4px;
|
|
|
+ right: 0;
|
|
|
+ width: 125px;
|
|
|
+ height: 94px;
|
|
|
+ z-index: 1;
|
|
|
+ .base-map-img {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ border-radius: 4px;
|
|
|
+ border: 1px solid #ffffff;
|
|
|
+ object-fit: cover;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .app-mask-top {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+ .app-mask-top-left {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: flex-start;
|
|
|
+ .app-year {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #ffffff;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ }
|
|
|
+ .app-date-wrapper {
|
|
|
+ position: relative;
|
|
|
+ .app-date-line {
|
|
|
+ position: absolute;
|
|
|
+ top: -2px;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ height: 1px;
|
|
|
+ background: #ffffff;
|
|
|
+ }
|
|
|
+ .app-date {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #ffffff;
|
|
|
+ position: relative;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .app-mask-top-right {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+ .app-phenology {
|
|
|
+ color: #f0d09c;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+ .app-uploader {
|
|
|
+ font-size: 10px;
|
|
|
+ color: #ffffff;
|
|
|
+ opacity: 0.5;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .app-mask-bottom {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ .app-weather-info {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 5px;
|
|
|
+ .app-weather-item {
|
|
|
+ color: #ffffff;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 2px;
|
|
|
+ .app-weather-icon {
|
|
|
+ width: 15px;
|
|
|
+ height: 15px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .app-weather-separator {
|
|
|
+ font-size: 10px;
|
|
|
+ color: #ffffff;
|
|
|
+ margin: 0 4px;
|
|
|
+ }
|
|
|
+ .app-location {
|
|
|
+ font-size: 10px;
|
|
|
+ color: #ffffff;
|
|
|
+ opacity: 0.5;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
.review-effect-text {
|
|
|
font-family: "PangMenZhengDao";
|