提交 258ed913 作者: 宇宙超人

样式修改

上级 ab875674
......@@ -31,6 +31,20 @@ export default {
return
}
// 处理tooltip formatter函数序列化问题
if (option.tooltip && option.tooltip.formatter) {
const formatterStr = option.tooltip.formatter
if (typeof formatterStr === 'string') {
try {
// 使用eval在视图层重新构建函数
// 支持箭头函数和普通函数
option.tooltip.formatter = eval('(' + formatterStr + ')')
} catch (e) {
// renderjs视图层不支持console,静默处理错误
}
}
}
this.option = merge(this.option, option)
if (typeof window.echarts === 'object' && typeof window.echarts.init === 'function') {
this.init()
......@@ -40,5 +54,16 @@ export default {
})
}
},
// 添加update方法,在这里重新定义tooltip的formatter
update() {
// 确保图表实例存在
if (this.chart) {
// 重新设置option,确保tooltip formatter正确绑定
if (this.option && this.option.tooltip && typeof this.option.tooltip.formatter === 'function') {
// 重新绑定formatter函数
this.chart.setOption(this.option, true);
}
}
}
},
}
}
\ No newline at end of file
......@@ -15,6 +15,12 @@
},
methods: {
setOption(option) {
// 处理tooltip formatter函数序列化
if (option.tooltip && typeof option.tooltip.formatter === 'function') {
// 将函数转换为字符串,在视图层重新构建
option.tooltip.formatter = option.tooltip.formatter.toString()
}
this.option = {
id: this.id,
...option,
......
......@@ -80,8 +80,8 @@ export function useMapbox<T extends MapboxInstance, P extends MapboxConfig>(
getInstance()?.setLayoutProperty(layerId, name, value),
setFilter: (layerId: string, filter: any[]) => getInstance()?.setFilter(layerId, filter),
flyTo: (options: mapboxgl.FlyToOptions) => getInstance()?.flyTo(options),
addMarker: (id: string, lnglat: [number, number], popup?: string, popupDefaultOpen?: boolean) =>
getInstance()?.addMarker(id, lnglat, popup, popupDefaultOpen),
addMarker: (id: string, lnglat: [number, number], popup?: string, popupDefaultOpen?: boolean, imageUrl?: string, iconSize?: [number, number]) =>
getInstance()?.addMarker(id, lnglat, popup, popupDefaultOpen, imageUrl, iconSize),
removeMarker: (id: string) => getInstance()?.removeMarker(id),
removePopup: () => getInstance()?.removePopup(),
loadImage: (url: string, callback: (error: Error | null, image: HTMLImageElement) => void) =>
......
......@@ -828,9 +828,11 @@ export interface MapboxInstance {
* @param lngLat 经纬度
* @param popup 弹窗内容
* @param popupDefaultOpen 是否默认打开弹窗
* @param imageUrl 自定义图标图片URL
* @param iconSize 图标大小 [width, height]
* @link https://docs.mapbox.com/mapbox-gl-js/api/markers/#marker
*/
addMarker(id: string, lngLat: number[], popup?: string, popupDefaultOpen?: boolean): void
addMarker(id: string, lngLat: number[], popup?: string, popupDefaultOpen?: boolean, imageUrl?: string, iconSize?: [number, number]): void
/**
* 移除 Marker
* @param id Marker ID
......
......@@ -372,7 +372,7 @@
this.tryTriggerChange()
},
addMarker(id, lngLat, popup, popupDefaultOpen) {
addMarker(id, lngLat, popup, popupDefaultOpen, imageUrl, iconSize) {
// 加入到 change 事件队列中
this.changeOptionsQueue.push({
fn: 'addMarker',
......@@ -380,6 +380,8 @@
lngLat,
popup,
popupDefaultOpen,
imageUrl,
iconSize,
})
// 尝试触发 change 事件
......
......@@ -73,6 +73,18 @@ window.onPopupContentEventHandle = function (e) {
}
}
// 全局暴露 navigateToDetail 方法,供 popup 中的按钮调用
window.navigateToDetail = function (data) {
if ($vm) {
// 调用逻辑层方法,通过 onEventHandle 传递事件
$vm.$ownerInstance.callMethod('onEventHandle', {
type: 'custom',
name: 'navigateToDetail',
data,
})
}
}
const defaultEmptyGeoJSON = {
type: 'FeatureCollection',
features: [],
......@@ -543,12 +555,32 @@ export default {
},
changeAddMarkerOptions(options) {
if (this.checkOnChangeValidity(options)) {
const { id, lngLat, popup, popupDefaultOpen, ...rest } = options
const { id, lngLat, popup, popupDefaultOpen, element, imageUrl, iconSize, ...rest } = options
if (this.markers[id]) {
this.markers[id].remove()
}
const marker = new window.mapboxgl.Marker({ scale: 0.8, ...rest }).setLngLat(lngLat).addTo(this.map)
let markerElement = element
// 如果提供了图片URL,创建自定义元素
if (imageUrl && !element) {
markerElement = document.createElement('div')
markerElement.className = 'custom-marker'
markerElement.style.backgroundImage = `url(${imageUrl})`
markerElement.style.width = iconSize ? `${iconSize[0]}px` : '40px'
markerElement.style.height = iconSize ? `${iconSize[1]}px` : '40px'
markerElement.style.backgroundSize = 'cover'
markerElement.style.borderRadius = '50%'
markerElement.style.cursor = 'pointer'
markerElement.style.border = '2px solid white'
markerElement.style.boxShadow = '0 2px 8px rgba(0,0,0,0.3)'
}
// 如果有自定义元素,使用它;否则使用默认配置
const marker = markerElement
? new window.mapboxgl.Marker(markerElement).setLngLat(lngLat).addTo(this.map)
: new window.mapboxgl.Marker({ scale: 0.8, ...rest }).setLngLat(lngLat).addTo(this.map)
if (popup) {
const popupComponent = new window.mapboxgl.Popup({ options: { closeButton: true } }).setHTML(popup)
marker.setPopup(popupComponent)
......
......@@ -3,6 +3,13 @@
function onApplyClick() {
Message.alert('申请功能暂不可用,敬请期待~', '温馨提示')
}
// 查看大图
function onViewImage(imageUrl) {
uni.previewImage({
urls: [imageUrl]
})
}
</script>
<template>
......@@ -167,11 +174,13 @@
<view class="codefun-mt-18 codefun-flex-row equal-division_2">
<view
class="codefun-flex-col codefun-justify-start codefun-items-center image-wrapper equal-division-item_2"
@click="onViewImage('/static/images/codefun/e10c098c837a0091dfe41ecd14dbaff5.png')"
>
<image class="image_7" src="/static/images/codefun/e10c098c837a0091dfe41ecd14dbaff5.png" />
</view>
<view
class="codefun-flex-col codefun-justify-start codefun-items-center image-wrapper equal-division-item_2 ml-15"
@click="onViewImage('/static/images/codefun/7ad157344b66cce4731d077aa759c0f9.png')"
>
<image class="image_7" src="/static/images/codefun/7ad157344b66cce4731d077aa759c0f9.png" />
</view>
......
<!-- 农场详情 -->
<script setup lang="ts">
import RegisterDialog from './register-dialog.vue'
import * as turf from '@turf/turf'
import type { Page } from './config'
import Navigate from '@/utils/page/navigate'
......@@ -56,6 +57,12 @@ const model = reactive({
longitude: uni.getStorageSync('location').lon,
latitude: uni.getStorageSync('location').lat,
},
// 选中的用工信息
selectedEmployment: null,
showEmploymentPopup: false,
searchText: '',
// 标记点击事件是否已绑定
clickEventBound: false,
})
onLoad((options) => {
......@@ -70,52 +77,12 @@ onLoad((options) => {
// 地图组件
const center: [number, number] = [uni.getStorageSync('location').lon, uni.getStorageSync('location').lat]
const registerDialogRef = ref()
const [registerMap, map] = useMapbox({
style: { center, zoom: 12 },
onLoaded: (data) => {
// 渲染用户当前位置
const userLocationPoint = turf.point([
model.userLocation.longitude,
model.userLocation.latitude
], {
name: '我的位置',
description: '当前位置',
icon: 'GD',
popup: `我的位置`,
})
addDefaultGeoJSONSource(map, `${page.id}-user-location`, [userLocationPoint])
addDefaultSymbolLayer(map, `${page.id}-user-location`, {
layout: {
'text-field': '',
'icon-image': ['get', 'icon'],
'icon-size': 1.2,
'icon-allow-overlap': true,
},
paint: {
'icon-color': '#FF4444',
},
})
const employments = []
// 渲染设备数据
model.employmentList.forEach((item) => {
employments.push(
turf.point([item.longitude, item.latitude], {
name: item.name,
description: item.content,
icon: 'GD',
popup: `{{name}}`,
}),
)
})
addDefaultGeoJSONSource(map, `${page.id}-text`, employments)
addDefaultSymbolLayer(map, `${page.id}-text`, {
layout: {
'text-field': '',
'icon-image': ['get', 'icon'],
'icon-size': 1,
},
})
renderUserLocation()
},
onSourceRequestHandle: () => {
page.requests--
......@@ -126,7 +93,166 @@ const [registerMap, map] = useMapbox({
onSourceRequestErrorHandle: () => {
Message.hideLoading()
},
onMapEvent: (event) => {
// 处理来自 renderjs 层的自定义事件
if (event.type === 'custom' && event.name === 'navigateToDetail') {
console.log('接收到导航事件,id:', event)
registerDialogRef.value.open({ id: event.data })
// Navigate.to(`/pages/linghuoyonggong/detail/index?id=${event.data}`)
}
},
})
// 创建弹框HTML内容
function createPopupHTML(employment) {
if (!employment) return ''
const distance = getDistanceText(employment)
console.log('employment', employment)
return `
<div style="
max-width: 280px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
">
<div style="display: flex; gap: 6px; margin-bottom: 12px;">
<!-- 左侧图标 -->
<div style="
width: 48px;
height: 48px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
">
<img src="${employment.picture}" style="width: 48px; height: 48px; border-radius: 50%;" />
</div>
<!-- 右侧内容 -->
<div style="flex: 1; min-width: 0;">
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;">
<div style="
font-size: 16px;
font-weight: 600;
color: #333333;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
">${employment.name}</div>
<div style="
background: #E8F5E9;
color: #4CAF50;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
white-space: nowrap;
margin-left: 8px;
">📍 ${distance}</div>
</div>
<div style="display: flex; gap: 12px; font-size: 13px; color: #666666; margin-bottom: 8px;">
<span>⏱ 时长${
employment.daysDiff || getDaysDiff(employment.starttime, employment.estimatedendtime)
}天</span>
<span>👥 需${employment.workers || 0}人</span>
<span>💰 ${employment.price || 0}元/天</span>
</div>
</div>
</div>
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="display: flex; align-items: center; gap: 4px;">
<span style="color: #FF9800; font-size: 16px;">★★★★</span>
<span style="color: #E0E0E0; font-size: 16px;">★</span>
<span style="font-size: 13px; color: #666666; margin-left: 4px;">4</span>
</div>
<a href="#" onclick="window.navigateToDetail('${employment.id}'); return false;" style="
display: inline-block;
padding: 6px 20px;
background: linear-gradient(135deg, #5DB66F 0%, #4CAF50 100%);
color: white;
text-decoration: none;
border-radius: 16px;
font-size: 14px;
font-weight: 500;
outline: none;
border: none;
transition: opacity 0.2s;">
我想去
</a>
</div>
</div>
`
}
// 渲染用户位置
function renderUserLocation() {
const markerId = `my-local`
// 修复 App 端图片路径问题
const imageUrl = '/static/images/local-map.png'
let finalImageUrl = imageUrl
// #ifdef APP-PLUS
// 在 App 端使用绝对路径
finalImageUrl = `./static/images/local-map.png`
// #endif
const iconSize: [number, number] = [40, 40] // 图标大小
// 使用 addMarker 添加到地图,带上 popup 和自定义图标
map.addMarker(
markerId,
[model.userLocation.longitude, model.userLocation.latitude],
'',
false, // 不默认打开
finalImageUrl, // 自定义图标图片URL
iconSize, // 图标大小
)
}
// 渲染用工标记
function renderEmploymentMarkers() {
if (!map) {
console.warn('地图未初始化')
return
}
console.log('渲染用工标记数量:', model.employmentList.length)
console.log('用工数据:', model.employmentList)
// 使用 Marker 方式渲染带自定义图标的标记
model.employmentList.forEach((item) => {
if (item.longitude && item.latitude) {
const markerId = `employment-marker-${item.id}`
let imageUrl = item.picture || '/static/images/linghuoyonggong/default-icon.png'
const iconSize: [number, number] = [40, 40] // 图标大小
// #ifdef APP-PLUS
// 处理 App 端图片路径
if (imageUrl.startsWith('/static/')) {
imageUrl = `.${imageUrl}`
}
// #endif
// 使用 addMarker 添加到地图,带上 popup 和自定义图标
map.addMarker(
markerId,
[item.longitude, item.latitude],
createPopupHTML(item),
false, // 不默认打开
imageUrl, // 自定义图标图片URL
iconSize, // 图标大小
)
}
})
// 绑定点击事件标记
if (!model.clickEventBound) {
console.log('标记点击事件已绑定')
model.clickEventBound = true
}
}
// 分类标签点击事件
function onCategoryTabClick(tab: any) {
model.search.type = tab.id
......@@ -169,6 +295,11 @@ function getEmploymentList() {
}
model.total = total
// 数据加载完成后渲染地图标记
nextTick(() => {
renderEmploymentMarkers()
})
})
} catch (error) {
console.error('获取用工列表失败:', error)
......@@ -211,7 +342,7 @@ function backToUserLocation() {
uni.showToast({
title: '已回到当前位置',
icon: 'none',
duration: 1500
duration: 1500,
})
} else {
// 重新获取用户位置
......@@ -228,33 +359,13 @@ function backToUserLocation() {
lat: res.latitude,
})
// 更新地图上的用户位置标记
const userLocationPoint = turf.point([res.longitude, res.latitude], {
name: '我的位置',
description: '当前位置',
icon: 'user-location-icon',
popup: `我的位置`,
})
addDefaultGeoJSONSource(map, `${page.id}-user-location`, [userLocationPoint])
addDefaultSymbolLayer(map, `${page.id}-user-location`, {
layout: {
'text-field': '',
'icon-image': ['get', 'icon'],
'icon-size': 1.2,
'icon-allow-overlap': true,
},
paint: {
'icon-color': '#FF4444',
},
})
// 飞到用户位置
flyTo(map, [res.longitude, res.latitude], 15, 0.5)
uni.showToast({
title: '已获取并回到当前位置',
icon: 'none',
duration: 1500
duration: 1500,
})
}
},
......@@ -263,14 +374,41 @@ function backToUserLocation() {
uni.showToast({
title: '获取位置失败,请检查定位权限',
icon: 'none',
duration: 2000
duration: 2000,
})
}
},
})
}
}
// 关闭弹框
function closeEmploymentPopup() {
model.showEmploymentPopup = false
model.selectedEmployment = null
}
// 计算距离显示
function getDistanceText(employment) {
if (!employment || !employment.longitude || !employment.latitude) {
return '未知'
}
// 使用turf计算距离
const from = turf.point([model.userLocation.longitude, model.userLocation.latitude])
const to = turf.point([employment.longitude, employment.latitude])
const distance = turf.distance(from, to, { units: 'kilometers' })
if (distance < 1) {
return `${Math.round(distance * 1000)}m`
}
return `${distance.toFixed(1)}km`
}
// 发布用工
function handlePublish() {
Navigate.to('/pages/linghuoyonggong/form')
}
onNavigationBarButtonTap((e) => {
console.log(e)
if (e.index === 0) {
Navigate.to('/pages/linghuoyonggong/linghuoyonggong')
}
......@@ -281,9 +419,14 @@ onNavigationBarButtonTap((e) => {
<view class="page h-95_dl_5vh bg-#E6F5E8 flex flex-col justify-between">
<view class="h-200rpx p-3">
<view class="w-full h-60rpx border-rd-3xl!">
<fui-input :bottomLeft="0" class="w-full h-full border-rd-3xl!" borderTop placeholder="请输入搜索内容"
<fui-input
:bottomLeft="0"
class="w-full h-full border-rd-3xl!"
borderTop
placeholder="请输入搜索内容"
placeholderStyle="color: #CCCCCC; font-weight: 400; font-family: PingFangSC-Regular;"
v-model="text">
v-model="model.searchText"
>
<template #left>
<view class="fui-left__icon">
<fui-icon name="search" color="#CCCCCC" :size="36" />
......@@ -292,10 +435,13 @@ onNavigationBarButtonTap((e) => {
</fui-input>
</view>
<view class="codefun-mt-14 codefun-flex-row group_2 gap-2">
<view v-for="tab in model.categoryTabs" :key="tab.id"
<view
v-for="tab in model.categoryTabs"
:key="tab.id"
class="codefun-flex-col codefun-justify-start codefun-items-center"
:class="[tab.id === model.search.type ? 'text-wrapper' : 'text-wrapper_2']"
@click="onCategoryTabClick(tab)">
@click="onCategoryTabClick(tab)"
>
<text class="font_2 text_2">
{{ tab.name }}
</text>
......@@ -311,10 +457,18 @@ onNavigationBarButtonTap((e) => {
<!-- 回到当前位置按钮 -->
<view class="location-control" @click="backToUserLocation">
<view class="location-button">
<fui-icon name="location" color="#5DB66F" :size="36" />
<image src="/static/images/toLocal.png" style="width: 58rpx; height: 58rpx"></image>
<!-- <fui-icon name="location" color="#5DB66F" :size="36" /> -->
</view>
</view>
</view>
<fui-fab position="right" distance="30" bottom="240" width="96" @click="handlePublish">
<view class="text-white text-center">
<view class="fab-icon" />
<view style="font-size: 24rpx">发布</view>
</view>
</fui-fab>
<RegisterDialog ref="registerDialogRef" />
</view>
</template>
......@@ -322,7 +476,7 @@ onNavigationBarButtonTap((e) => {
//
.page {
min-height: 100vh;
background: #E6F5E8;
background: #e6f5e8;
.map-box {
// #ifdef APP-PLUS
......@@ -336,7 +490,7 @@ onNavigationBarButtonTap((e) => {
width: 690rpx;
left: 30rpx;
border-radius: 20rpx;
background: #E6F5E8;
background: #e6f5e8;
}
.group_2 {
......@@ -381,28 +535,28 @@ onNavigationBarButtonTap((e) => {
.location-control {
position: absolute;
bottom: 100rpx;
right: 30rpx;
right: 10rpx;
z-index: 1000;
.location-button {
display: flex;
align-items: center;
justify-content: center;
width: 80rpx;
height: 80rpx;
// width: 80rpx;
// height: 80rpx;
background: rgba(255, 255, 255, 0.95);
border-radius: 50%;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.15);
backdrop-filter: blur(10rpx);
border: 2rpx solid #5DB66F;
// border: 2rpx solid #5db66f;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
background: linear-gradient(135deg, #5DB66F 0%, #4CAF50 100%);
background: linear-gradient(135deg, #5db66f 0%, #4caf50 100%);
:deep(.fui-icon) {
color: #FFFFFF !important;
color: #ffffff !important;
}
}
......@@ -413,4 +567,16 @@ onNavigationBarButtonTap((e) => {
}
}
}
::v-deep .mapboxgl-popup {
max-width: 568rpx !important;
}
::v-deep .fui-fab__btn-main {
background: linear-gradient(124.25deg, #a5d63f 0%, #5db66f 100%) !important;
box-shadow: 0px 1px 8px #5db66f;
}
::v-deep .mapboxgl-popup a {
outline: none !important;
-webkit-tap-highlight-color: transparent !important;
-webkit-touch-callout: none !important;
}
</style>
......@@ -92,7 +92,7 @@
{{ model.msg.phone }}
</view>
</view>
<view class="msgBox flex justify-between items-center text-30">
<!-- <view class="msgBox flex justify-between items-center text-30">
<view class="text-#999999"> 邮箱 </view>
<view class="text-#333333">
{{ model.msg.email }}
......@@ -106,7 +106,6 @@
align="right"
:text="model.msg.orgCodeTxt ? `${model.msg.orgCodeTxt}` : '- -'"
/>
<!-- {{ model.msg.orgCodeTxt ? model.msg.orgCodeTxt : '- -' }} -->
</view>
</view>
<view class="msgBox lastBox flex justify-between items-center text-30">
......@@ -114,7 +113,7 @@
<view class="text-#333333">
{{ model.msg.postText ? model.msg.postText : '- -' }}
</view>
</view>
</view> -->
</view>
</view>
</template>
......
<script setup lang="ts">
import dayjs from 'dayjs'
import * as WeatherAPI from '@/api/model/weather'
import { Echarts, useEcharts } from '@/components/Echarts'
import { getDayLabelValue, getWeatherIcon } from '@/utils/weather'
import dayjs from 'dayjs'
import * as WeatherAPI from '@/api/model/weather'
import { Echarts, useEcharts } from '@/components/Echarts'
import { getDayLabelValue, getWeatherIcon } from '@/utils/weather'
// 逐 7 天预报图表
const [register7Forecast, Forecast7Chart] = useEcharts()
const model = reactive({
days: 15,
updateTime: '-',
// 逐 7 天预报图表
const [register7Forecast, Forecast7Chart] = useEcharts()
const model = reactive({
days: 15,
updateTime: '-',
})
onLoad(async () => {
const location = uni.getStorageSync('location')
const forecasts = await WeatherAPI.forecast(`${location.lon},${location.lat}`, model.days).then((res) => {
model.updateTime = dayjs(res.data.updateTime).format('YYYY-MM-DD HH:mm')
return res.data.daily
})
console.log('forecasts', forecasts)
onLoad(async () => {
const location = uni.getStorageSync('location')
const forecasts = await WeatherAPI.forecast(`${location.lon},${location.lat}`, model.days).then((res) => {
model.updateTime = dayjs(res.data.updateTime).format('YYYY-MM-DD HH:mm')
return res.data.daily
})
console.log('forecasts', forecasts)
// 逐 7 天预报数据
const _7DayForecastData = forecasts.map((item, index) => {
return {
minTem: item.tempMin,
maxTem: item.tempMax,
textDay: item.textDay,
textNight: item.textNight,
dayWeather: item.iconDay,
nightWeather: item.iconNight,
fxDate: item.fxDate,
...getDayLabelValue(index),
}
})
const _7DayForecastMaxTemValue = Math.max(..._7DayForecastData.map((item) => Number(item.maxTem)))
// 逐 7 天预报数据
const _7DayForecastData = forecasts.map((item, index) => {
return {
minTem: item.tempMin,
maxTem: item.tempMax,
textDay: item.textDay,
textNight: item.textNight,
dayWeather: item.iconDay,
nightWeather: item.iconNight,
fxDate: item.fxDate,
...getDayLabelValue(index),
// 设置逐 7 天预报图表参数
Forecast7Chart.setOption({
tooltip: {
show: true,
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
formatter: (params) => {
// 过滤掉星期标签、日期标签和天气图标
const filteredParams = params.filter(param => {
return param.seriesName !== '星期标签' &&
param.seriesName !== '日期标签' &&
param.seriesName !== '天气图标';
});
if (filteredParams.length === 0) return '';
let result = '';
filteredParams.forEach(param => {
// 只显示有意义的数值信息
if (param.seriesName === '最高温度' || param.seriesName === '最低温度') {
result += `${param.seriesName}: ${param.value}°<br/>`;
}
});
return result;
}
})
const _7DayForecastMaxTemValue = Math.max(..._7DayForecastData.map((item) => Number(item.maxTem)))
const _7DayForecastMinTemValue = Math.min(..._7DayForecastData.map((item) => Number(item.minTem)))
// 设置逐 7 天预报图表参数
Forecast7Chart.setOption({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
},
grid: {
top: '10%',
bottom: '10%',
left: '0',
right: '3%',
},
xAxis: {
type: 'category',
data: _7DayForecastData.map((item) => item.textNight),
axisLine: {
show: false,
},
grid: {
top: '25%',
bottom: '10%',
left: '0',
right: '3%',
axisTick: {
show: false,
},
xAxis: {
type: 'category',
data: _7DayForecastData.map((item) => item.value),
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
show: false, // 隐藏x轴标签
},
axisLabel: {
show: true, // 隐藏x轴标签
interval: 0,
color: '#999',
fontSize: 11,
},
yAxis: {
type: 'value',
splitLine: {
show: false,
},
axisLabel: {
show: false,
},
},
yAxis: {
type: 'value',
splitLine: {
show: false,
},
axisLabel: {
show: false,
},
},
series: [
// 顶部星期标签(今天、明天、周X)- 第一行
{
name: '星期标签',
type: 'scatter',
data: _7DayForecastData.map((item, index) => {
return {
value: [index, Number(_7DayForecastMaxTemValue) + 10.5],
symbolSize: 0,
label: {
show: true,
position: 'top',
formatter: item.label,
fontSize: 14,
color: '#333333',
fontWeight: 'bold',
},
}
}),
},
// 顶部日期标签(09/10)- 第二行
{
name: '日期标签',
type: 'scatter',
data: _7DayForecastData.map((item, index) => {
return {
value: [index, Number(_7DayForecastMaxTemValue) + 6],
symbolSize: 0,
label: {
show: true,
position: 'top',
formatter: `${item.value}\n${item.textDay}\n`,
fontSize: 12,
color: '#666666',
},
}
}),
},
// 天气图标 - 第三行
{
name: '天气图标',
type: 'scatter',
data: _7DayForecastData.map((item, index) => {
return {
value: [index, Number(_7DayForecastMaxTemValue) + 5],
symbol: `image://${getWeatherIcon(String(item.dayWeather))}`,
symbolSize: [28, 28],
}
}),
},
series: [
{
name: '最高温度',
type: 'line',
data: _7DayForecastData.map((item) => item.maxTem),
smooth: true,
// 最高温度线
{
name: '最高温度',
type: 'line',
data: _7DayForecastData.map((item) => item.maxTem),
smooth: true,
color: '#F79D80',
symbolSize: 6,
label: {
show: true,
position: 'top',
formatter: '{c}°',
color: '#F79D80',
symbolSize: 6,
label: {
show: true,
position: 'top',
formatter: '{c}°',
color: '#F79D80',
fontSize: 11,
},
fontSize: 11,
},
{
name: '最低温度',
type: 'line',
data: _7DayForecastData.map((item) => item.minTem),
smooth: true,
},
// 最低温度线
{
name: '最低温度',
type: 'line',
data: _7DayForecastData.map((item) => item.minTem),
smooth: true,
color: '#52C41A',
symbolSize: 6,
label: {
show: true,
position: 'bottom',
formatter: '{c}°',
color: '#52C41A',
symbolSize: 6,
label: {
show: true,
position: 'bottom',
formatter: '{c}°',
color: '#52C41A',
fontSize: 11,
},
},
{
name: '白天天气',
type: 'scatter',
data: _7DayForecastData.map((item, index) => {
console.log('item', item,[index, Number(_7DayForecastMaxTemValue) + 3])
return {
value: [index, Number(_7DayForecastMaxTemValue) + 3],
symbol: `image://${getWeatherIcon(String(item.dayWeather))}`,
symbolSize: [20, 20],
symbolOffset: [0, -12],
label: {
show: true,
position: 'top',
formatter: `${item.label}\n${item.value}\n${item.textDay}`,
fontSize: 11,
color: '#333',
fontWeight: 'bold',
lineHeight: 18,
},
}
}),
fontSize: 11,
},
{
name: '天气描述',
type: 'scatter',
data: _7DayForecastData.map((item, index) => {
return {
value: [index, Number(_7DayForecastMinTemValue) - 3],
symbolSize: 0,
label: {
show: true,
position: 'bottom',
formatter: item.textDay,
fontSize: 10,
color: '#999',
},
}
}),
},
],
})
},
],
})
})
</script>
<template>
......@@ -151,7 +185,7 @@
<!-- 逐 7 天预报图表 -->
<view class="rain-forecast mt-2rpx bg-#fff rd-1.5 shadow flex flex-col px-2">
<view class="flex items-center justify-between pt-3 px-2">
<view class="text-32 font-600">{{ model.days }} 天预报</view>
<view class="text-32 font-600">{{ model.days }}天预报</view>
<!-- <view class="text-24">发布时间:{{ model.updateTime }}</view> -->
</view>
<scroll-view class="flex-1" scroll-x="true">
......@@ -162,5 +196,5 @@
</template>
<style lang="scss" scoped>
//
//
</style>
......@@ -440,7 +440,7 @@
<view class="box-4">
<view class="box-4-title">
<view class="box-4-title-text1"><text>基地设备</text></view>
<view class="box-4-title-text2"><text>+ 添加设备</text></view>
<navigator url="/pages/device/device" class="box-4-title-text2"><text>+ 添加设备</text></navigator>
</view>
<view class="box-4-device">
<view class="box-4-device-item" v-for="(device, index) in model.deviceTypeCount" :key="index">
......
......@@ -3,6 +3,7 @@ import { reactive } from 'vue'
import { onPullDownRefresh, onShow } from '@dcloudio/uni-app'
import WeatherForecast from './components/WeatherForecast.vue'
import Navigate from '@/utils/page/navigate'
import dayjs from 'dayjs'
import * as NongChangAPI from '@/api/model/nongchang'
import { useUserStore } from '@/store/modules/user'
......@@ -21,7 +22,7 @@ onShow(() => {
// 农技课堂
getAgricultureClassList()
// 智能设备
getDeviceList()
// getDeviceList()
// 获取农村
getFarmList()
})
......@@ -253,10 +254,9 @@ function getCommonToolsList() {
})
}
function getAgricultureClassList() {
getVideoList({ pageNo: 1, pageSize: 3, status: 1, classify: 3 }).then((res) => {
getVideoList({ pageNo: 1, pageSize: 10, status: 1, classify: 3 }).then((res) => {
const { records } = res
pageData.agricultureClass.videoList = records
pageData.agricultureClass.title = records[0]?.title
})
}
......@@ -509,8 +509,12 @@ onHide(() => {
<text class="codefun-ml-8 font_2 text_2">{{ pageData.header.searchPlaceholder }}</text>
</view> -->
<view class="codefun-flex-row equal-division section_3">
<view v-for="item in pageData.menuItems" :key="item.id"
class="codefun-flex-col codefun-items-center" @click="onMenuItemClick(item)">
<view
v-for="item in pageData.menuItems"
:key="item.id"
class="codefun-flex-col codefun-items-center"
@click="onMenuItemClick(item)"
>
<image class="image_6" :src="item.icon_url" />
<text class="font_3 mt-13" :class="`text_${item.id + 2}`">{{ item.name }}</text>
</view>
......@@ -530,7 +534,8 @@ onHide(() => {
<text class="font_4 text_9">{{ pageData.farmInfo.area }}</text>
</view>
<view
class="codefun-flex-col codefun-justify-start codefun-items-center text-wrapper_2 ml-3">
class="codefun-flex-col codefun-justify-start codefun-items-center text-wrapper_2 ml-3"
>
<text class="font_4 text_10">{{ pageData.farmInfo.crops }}</text>
</view>
</view>
......@@ -557,26 +562,33 @@ onHide(() => {
</view>
<view class="h-300rpx codefun-flex-col mr-3.5 mt-17 nongchang_box relative">
<image class="w-full h-full" src="/static/images/nongchang/mynongchang-1.png" />
<view v-show="pageData.hasFarm"
class="w-240rpx h-80rpx flex-center border-rd-3xl absolute top-50% left-50% color-#ffffff"
<view
v-show="pageData.hasFarm"
class="w-280rpx h-80rpx flex-center border-rd-3xl absolute top-50% left-50% color-#ffffff"
style="
background-color: rgb(255 255 255 / 20%);
border: 1rpx solid #fff;
transform: translateY(-50%) translateX(-50%);
" @click="toDetail(pageData.farmInfo)">
"
@click="toDetail(pageData.farmInfo)"
>
<image class="mr-1 w-40 h-40" src="/static/images/nongchang/eye-white.png" />
<text style="font-family: '思源黑体'; font-weight: 300">进入农场</text>
</view>
<view v-show="!pageData.hasFarm"
class="w-240rpx h-80rpx flex-center border-rd-3xl absolute top-50% left-50% color-#ffffff"
<view
v-show="!pageData.hasFarm"
class="w-280rpx h-80rpx flex-center border-rd-3xl absolute top-50% left-50% color-#ffffff"
style="
background-color: rgb(255 255 255 / 20%);
border: 1rpx solid #fff;
transform: translateY(-50%) translateX(-50%);
" @click="toAdd">
"
@click="toAdd"
>
<image class="mr-1 w-40 h-40" src="/static/images/nongchang/add.png" />
<text style="font-family: '思源黑体'; font-weight: 300">添加农场</text>
<text class="fontsize_28" style="font-family: '思源黑体'; font-weight: 400;color: #fff;">添加我的农场</text>
</view>
<view class="absolute nongchang-remark">基于农场实时精细化气象数据基地设备管理</view>
</view>
</view>
<view class="codefun-flex-col group_10">
......@@ -589,8 +601,8 @@ onHide(() => {
<view class="codefun-flex-row equal-division_3">
<template v-for="model in pageData.agricultureModels" :key="model.id">
<view class="codefun-flex-col equal-division-item_5 group_11">
<view class=" flex-row" style="text-align: center;">
<view class=" flex-center">
<view class="flex-row" style="text-align: center">
<view class="flex-center">
<image class="w-80 h-80" :src="model.icon_url" />
</view>
<view class="">
......@@ -600,7 +612,8 @@ onHide(() => {
</view>
<view
class="codefun-flex-col codefun-justify-start codefun-items-center codefun-self-center text-wrapper_3 mt-2!"
@click="onAgricultureModelClick(model)">
@click="onAgricultureModelClick(model)"
>
<text class="font_8 text_24">查看介绍</text>
</view>
</view>
......@@ -609,27 +622,34 @@ onHide(() => {
</view>
<view class="codefun-mt-12 codefun-flex-col section_8">
<view class="codefun-flex-row equal-division_4">
<view class="codefun-flex-row codefun-justify-center equal-division-item_6 section_9"
@click="onViewMoreFlexibleEmployment(1)">
<view
class="codefun-flex-row codefun-justify-center equal-division-item_6 section_9"
@click="onViewMoreFlexibleEmployment(1)"
>
<text class="codefun-self-start font_9 text_25">{{
pageData.flexibleEmployment.working
}}</text>
<image class="codefun-self-center image_8 ml-9"
src="/static/images/codefun/e12b4605ec265981ebf23e742ae09d77.png" />
}}</text>
<image
class="codefun-self-center image_8 ml-9"
src="/static/images/codefun/e12b4605ec265981ebf23e742ae09d77.png"
/>
</view>
<view
class="codefun-flex-row codefun-justify-evenly equal-division-item_6 section_10 ml-11"
@click="onViewMoreFlexibleEmployment(2)">
@click="onViewMoreFlexibleEmployment(2)"
>
<text class="codefun-self-start font_9 text_26">{{
pageData.flexibleEmployment.earning
}}</text>
<image class="codefun-self-center image_9"
src="/static/images/codefun/abc27711926ec08e17bd512f96740931.png" />
}}</text>
<image
class="codefun-self-center image_9"
src="/static/images/codefun/abc27711926ec08e17bd512f96740931.png"
/>
</view>
</view>
<text class="codefun-self-start font_10 text_27 mt-7">{{
pageData.flexibleEmployment.progress
}}</text>
}}</text>
</view>
</view>
</view>
......@@ -639,11 +659,17 @@ onHide(() => {
<text class="font_6 text_29" @click="onBaseManagementClick">更多</text>
</view>
<view class="codefun-flex-row equal-division_5 mt-17">
<view v-for="(item, index) in pageData.baseManagement" :key="item.id"
class="codefun-flex-col section_11 equal-division-item_7 gap-1 justify-center align-center"
:class="{ 'ml-9': index > 0 }" @click="onBaseManagementClick(item)">
<view
v-for="(item, index) in pageData.baseManagement"
:key="item.id"
class="codefun-flex-col section_11 equal-division-item_7 gap-1 justify-center align-center"
:class="{ 'ml-9': index > 0 }"
@click="onBaseManagementClick(item)"
>
<image class="image_5" :src="item.icon" />
<text class="fontsize_24 font_11 mt-0.5" :class="`text_${30 + item.id - 1}`">{{ item.name }}</text>
<text class="fontsize_24 font_11 mt-0.5" :class="`text_${30 + item.id - 1}`">{{
item.name
}}</text>
<view class="group_25">
<text class="font_12" :class="`text_${35 + item.id - 1}`">{{ item.num }}</text>
<text class="font_10" :class="`text_${35 + item.id + 3}`">{{ item.unit }}</text>
......@@ -651,179 +677,73 @@ onHide(() => {
</view>
</view>
</view>
<view class="codefun-flex-col group_21" id="monitorWarning">
<view class="codefun-flex-row codefun-justify-between codefun-items-center group_22">
<text class="font text_42">监测预警</text>
<text class="font_6 text_43 text_44" @click="onViewMoreMonitoring">更多</text>
</view>
<view class="codefun-flex-col section_12">
<view class="codefun-flex-row codefun-items-center group_23">
<view class="codefun-flex-col codefun-items-end codefun-shrink-0">
<text class="font_13 text_45">80</text>
<text class="codefun-mt-16 font_13 text_46">60</text>
<text class="codefun-mt-16 font_13 text_47">40</text>
<text class="codefun-mt-16 font_13 text_48">20</text>
<text class="codefun-mt-16 font_13 text_49">0</text>
</view>
<view class="codefun-flex-col codefun-flex-1 codefun-relative group_24 ml-7">
<view class="divider" />
<view class="divider view_2" />
<view class="divider view_3" />
<view
class="codefun-flex-col codefun-justify-start codefun-items-start image-wrapper pos_2">
<image class="codefun-shrink-0 image_11"
src="/static/images/codefun/fb791ee7e711cfb556043cb81d3c32b1.png" />
</view>
<view class="divider pos" />
<view class="divider pos_3" />
</view>
</view>
<view class="codefun-mt-10 codefun-flex-col codefun-justify-start group_25">
<view class="codefun-flex-row equal-division_6">
<view class="codefun-flex-col codefun-items-center section_13 equal-division-item_8">
<image class="image_12"
src="/static/images/codefun/68bae99a74dc71e194d799ee24c1f023.png" />
<view
class="codefun-mt-4 codefun-flex-col codefun-justify-start codefun-items-center text-wrapper_4">
<text class="font_10 text_50">气象灾害</text>
</view>
<view
class="codefun-mt-4 codefun-flex-col codefun-justify-start codefun-items-center text-wrapper_4">
<text class="font_10 text_53">台风预警</text>
</view>
</view>
<view class="codefun-flex-col section_13 equal-division-item_8 ml-11">
<image class="codefun-self-center image_12"
src="/static/images/codefun/29bc217d767c53f1f4968ddcf08b6d85.png" />
<view
class="codefun-mt-4 codefun-flex-col codefun-items-center codefun-self-stretch">
<view
class="codefun-flex-col codefun-justify-start codefun-items-center text-wrapper_4">
<text class="font_10 text_51">作物倒伏</text>
</view>
<view
class="codefun-mt-4 codefun-flex-col codefun-justify-start codefun-items-center text-wrapper_4">
<text class="font_10 text_54">中等风险</text>
</view>
</view>
</view>
<view class="codefun-flex-col section_13 section_14 ml-11">
<image class="codefun-self-center image_12"
src="/static/images/codefun/143013b1c946e75b10133de0db6d9c7f.png" />
<view
class="codefun-mt-4 codefun-flex-col codefun-justify-start codefun-items-center codefun-self-stretch text-wrapper_5">
<text class="font_10 text_52">病虫害风险</text>
</view>
<view
class="codefun-mt-4 codefun-flex-col codefun-justify-start codefun-items-center codefun-self-stretch text-wrapper_5">
<text class="font_10 text_55">水稻稻瘟病</text>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="codefun-flex-col group_21">
<view class="codefun-flex-row codefun-justify-between codefun-items-center group_22">
<text class="font text_42">常用工具</text>
<text class="font_6 text_43 text_44" @click="onViewMoreTools">更多</text>
</view>
<view class="codefun-flex-col section_12">
<view class="flex-center flex-wrap pt-3">
<view v-for="tool in pageData.commonTools" :key="tool.id"
<view class="flex-center flex-wrap pt-3">
<view
v-for="tool in pageData.commonTools"
:key="tool.id"
class="px-3 py-3 bg-white rounded-lg flex-center flex-col gap-2"
@click="onClickTool(tool)">
@click="onClickTool(tool)"
>
<image class="w-100 h-100" :src="tool.icon" mode="scaleToFill" />
<view class="text-24 fontsize_28">{{ tool.name }}</view>
</view>
</view>
</view>
</view>
<view class="codefun-flex-col group_26 mt-21">
<view class="codefun-flex-row codefun-justify-between codefun-items-baseline">
<text class="font text_56">智能设备</text>
<text class="font_6 text_57" @click="onDeviceManagementClick">设备管理</text>
</view>
<view class="codefun-flex-row group_26 mt-17 gap-2">
<view v-for="(device, index) in pageData.smartDevices" :key="device.id"
class="section_16 codefun-flex-row codefun-justify-center codefun-items-center codefun-shrink-0 codefun-relative">
<image class="image_13"
:src="device.isOnline === 1 ? pageData.smartDeviceIcon[0] : pageData.smartDeviceIcon[1]" />
<view class="codefun-ml-8 codefun-flex-col">
<text class="font_10">{{ device.deviceName }}</text>
<view class="codefun-mt-10 codefun-flex-row codefun-items-center">
<view class="section_17" v-if="index !== 1" />
<view class="section_18" v-if="index === 1" />
<text class="codefun-ml-4 font_4" :class="index !== 1 ? 'text_59' : 'text_60'"
:style="{ color: device.statusColor }">
{{ device.isOnline_dictText }}
</text>
</view>
</view>
</view>
</view>
</view>
<view class="codefun-flex-col group_28" id="creditCenter">
<text class="codefun-self-start font text_61">信用中心</text>
<view
class="codefun-flex-row codefun-justify-between codefun-items-center codefun-self-stretch section_19 mt-21">
<image class="image_15" :src="pageData.creditCenter.image" />
<view class="codefun-flex-col codefun-items-start group_29">
<text class="text_62">{{ userStore.getUserInfo?.creditScore || 600 }}</text>
<text class="font_5 text_63 mt-13">{{ pageData.creditCenter.rating }}</text>
<text class="font_10 text_64 mt-13">{{ pageData.creditCenter.tips }}</text>
<view
class="codefun-flex-col codefun-justify-start codefun-items-center text-wrapper_6 mt-13"
@click="onViewFinancialServices">
<text class="font_15 text_65">{{ pageData.creditCenter.actionText }}</text>
</view>
</view>
</view>
</view>
<view class="codefun-flex-col group_30">
<view class="codefun-flex-row codefun-justify-between codefun-items-center group_22">
<text class="font text_66">农技学习</text>
<text class="font_6 text_43 text_67" @click="onViewMoreClass">查看更多</text>
</view>
<view class="codefun-flex-col section_20 !relative">
<fui-swiper-dot :items="pageData.agricultureClass.videoList" :current="pageData.current"
:styles="{
height: 10,
activeWidth: 40,
background: '#dff0e2',
activeBackground: '#5db66f',
bottom: 10,
}">
<swiper class="fui-banner__wrap" circular :indicator-dots="false" :autoplay="false"
:interval="8000" :duration="300" :disable-touch="false" :touch-angle="45"
:threshold="50" @change="handleChangeVideo" @transition="handleTransition">
<swiper-item v-for="(video, index) in pageData.agricultureClass.videoList" :key="index">
<image :src="video.thumbnailPath" mode="scaleToFill" class="w-654rpx h-358rpx"
@click="playVideo(index)" />
<video :id="`video${index}`" :src="video.url" :poster="video.thumbnailPath"
:title="video.title" :controls="true" style="width: 654rpx; height: 358rpx"
:autoplay="false" :muted="false" :loop="true" :show-play-btn="true"
:show-center-play-btn="true" :enable-progress-gesture="true"
:show-progress="true" :direction="0" object-fit="contain"
@loadedmetadata="handleMetadataLoaded" @play="handleVideoPlay(index)"
@pause="handleVideoPause(index)"
@fullscreenchange="handleFullscreenChange($event, index)"
class="!hidden"></video>
<view class="describe relative">
<text class="codefun-self-start font text_34">{{
pageData.agricultureClass.title
}}</text>
<view
class="codefun-flex-row codefun-justify-between codefun-items-center codefun-self-stretch mt-13">
<image src="/static/images/codefun/play.png" mode="scaleToFill"
class="absolute w-64 h-64 top--150 left-275"
@click="playVideo(index)" />
<text class="font_14 text_36">{{ pageData.agricultureClass.time }}</text>
<view class="codefun-flex-col section_20 !relative rounded-lg" style="margin-left: -28rpx">
<fui-waterfall topGap="20" leftGap="20" rightGap="20" bottomGap="20">
<fui-waterfall-item
v-for="(video, index) in pageData.agricultureClass.videoList"
:key="index"
:src="video.thumbnailPath"
@click="playVideo(index)"
>
<view class="flex flex-col justify-between pl-2 pr-2 pb-2">
<view class="fontsize_28 mt-1 mb-2 font-13">{{ video.title }}</view>
<view class="flex justify-between text-25 color-#686868">
<view class="mr-1 flex-center">
<view class="flex-center text-24 lh-24rpx"
>{{ video.viewCount || 0 }}次播放</view
>
</view>
<text>{{ dayjs(video.publishDate).format('MM-DD') }}</text>
</view>
</swiper-item>
</swiper>
</fui-swiper-dot>
</view>
<video
:id="`video${index}`"
:src="video.url"
:poster="video.thumbnailPath"
:title="video.title"
:controls="true"
:autoplay="false"
:muted="false"
:loop="true"
:show-play-btn="true"
:show-center-play-btn="true"
:enable-progress-gesture="true"
:show-progress="true"
:direction="0"
object-fit="contain"
@loadedmetadata="handleMetadataLoaded"
@play="handleVideoPlay(index)"
@pause="handleVideoPause(index)"
@fullscreenchange="handleFullscreenChange($event, index)"
class="!hidden"
></video>
</fui-waterfall-item>
</fui-waterfall>
</view>
</view>
</view>
......@@ -989,7 +909,6 @@ onHide(() => {
}
.group_4 {
// position: absolute;
// right: 147rpx;
// top: 6rpx;
......@@ -999,7 +918,6 @@ onHide(() => {
}
.equal-division-item_3 {
// position: absolute;
// right: 13rpx;
// top: 6rpx;
......@@ -1516,11 +1434,13 @@ onHide(() => {
.divider {
mix-blend-mode: NOTTHROUGH;
background-image: repeating-linear-gradient(90deg,
#c6cacd,
#c6cacd 1.36%,
transparent 1.36%,
transparent 2.717%);
background-image: repeating-linear-gradient(
90deg,
#c6cacd,
#c6cacd 1.36%,
transparent 1.36%,
transparent 2.717%
);
background-position: -4rpx 0rpx;
height: 2rpx;
}
......@@ -1809,10 +1729,7 @@ onHide(() => {
position: relative;
margin-right: 28rpx;
height: 418rpx;
// padding: 271.06rpx 36.64rpx 22rpx 48rpx;
padding: 20rpx;
padding-bottom: 0;
background-color: #ffffff;
border-radius: 16rpx;
mix-blend-mode: NOTTHROUGH;
......@@ -1988,4 +1905,17 @@ onHide(() => {
.font_11 {
color: #666666;
}
.nongchang-remark {
font-size: 24rpx;
font-weight: 400;
letter-spacing: 0px;
line-height: 18px;
color: #ffffff;
text-align: center;
vertical-align: middle;
bottom: 30rpx;
width: 312rpx;
left: 50%;
transform: translateX(-50%);
}
</style>
......@@ -144,7 +144,8 @@ export function getDayLabelValue(index: number) {
} else if (index === 1) {
dayLabel = '明天'
} else {
dayLabel = dayjs().day(dayOfWeek).format('dddd')
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
dayLabel = weekdays[dayOfWeek]
}
return {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论