提交 b4b30b49 作者: 廖在望

feat: 页面功能重构

上级 1c87240e
# API 接口地址 # API 接口地址
# VITE_GLOB_API_URL=http://111.22.182.169:49600 # VITE_GLOB_API_URL=http://111.22.182.169:49600
# VITE_GLOB_API_URL=http://36.133.16.81:42111 # VITE_GLOB_API_URL=http://36.133.16.81:42111
VITE_GLOB_API_URL=http://123.207.47.17 VITE_GLOB_API_URL=http://localhost:8080
# API 接口地址前缀 # API 接口地址前缀
# VITE_GLOB_API_URL_PREFIX=/jeecgboot # VITE_GLOB_API_URL_PREFIX=/jeecgboot
......
const fs = require('fs');
['src/pages/chanxiao/supplyXuQiu.vue', 'src/pages/chanxiao/purchaseXuQiu.vue'].forEach(filePath => {
let file = fs.readFileSync(filePath, 'utf8');
// Replace ' required\n' or ' required ' inside tags
file = file.replace(/\s+required(\s*[\n>])/g, ' :required="isSave"$1');
file = file.replace(/class="form-item required flex align-center"/g, ':class="[\'form-item\', \'flex\', \'align-center\', isSave ? \'required\' : \'\']"');
file = file.replace(/placeholder="([^"]+)"/g, ':placeholder="isSave ? \'$1\' : \'\'"');
fs.writeFileSync(filePath, file);
});
const fs = require('fs');
['src/pages/chanxiao/supplyXuQiu.vue', 'src/pages/chanxiao/purchaseXuQiu.vue'].forEach(filePath => {
let file = fs.readFileSync(filePath, 'utf8');
// Fix ::placeholder back to :placeholder
file = file.replace(/::placeholder/g, ':placeholder');
// Also hide default text "请选择" if !isSave
file = file.replace(/\|\| '请选择(.*?)'/g, "|| (isSave ? '请选择$1' : '')");
fs.writeFileSync(filePath, file);
});
const fs = require('fs');
['src/pages/chanxiao/supplyXuQiu.vue', 'src/pages/chanxiao/purchaseXuQiu.vue'].forEach(filePath => {
let file = fs.readFileSync(filePath, 'utf8');
// Make wrapper clicks conditional
file = file.replace(/@click="show\.address = true"/g, '@click="isSave && (show.address = true)"');
file = file.replace(/@click="show\.time1 = true"/g, '@click="isSave && (show.time1 = true)"');
file = file.replace(/@click="show\.time2 = true"/g, '@click="isSave && (show.time2 = true)"');
file = file.replace(/@click="show\.classify = true"/g, '@click="isSave && (show.classify = true)"');
file = file.replace(/@click="show\.time = true"/g, '@click="isSave && (show.time = true)"');
// Remove `isSave ? '\`...`' : ''` syntax error
// From `:placeholder="isSave ? '\`请输入${pageText}标题\`' : ''"`
// To `:placeholder="isSave ? \`请输入${pageText}标题\` : ''"`
file = file.replace(/:placeholder="isSave \? '\\`(.*?)\\`' : ''"/g, ':placeholder="isSave ? \\`$1\\` : \'\'"');
fs.writeFileSync(filePath, file);
});
...@@ -4,7 +4,8 @@ import { otherHttp } from '/@/utils/http/axios' ...@@ -4,7 +4,8 @@ import { otherHttp } from '/@/utils/http/axios'
enum Api { enum Api {
purchaseList = '/purchaseSell/bizPurchase/list', // 采购需求列表 purchaseList = '/purchaseSell/bizPurchase/list', // 采购需求列表
supplyList = '/purchaseSell/bizSupply/list', // 供应需求列表 supplyList = '/purchaseSell/bizSupply/list', // 供应需求列表
purchaseSellDetails = '/purchaseSell/bizPurchase/queryById', // 产销详情 purchaseSellDetails = '/purchaseSell/bizPurchase/queryById', // 采购详情
supplyDetails = '/purchaseSell/bizSupply/queryById', // 供应详情
purchaseSell = '/purchaseSell/bizPurchase/add', // 发布采购需求 purchaseSell = '/purchaseSell/bizPurchase/add', // 发布采购需求
supplyAdd = '/purchaseSell/bizSupply/add', // 发布供应需求 supplyAdd = '/purchaseSell/bizSupply/add', // 发布供应需求
bizPurchaseSupplyRecord = '/purchaseSell/bizPurchaseSupplyRecord/add', // 报价 bizPurchaseSupplyRecord = '/purchaseSell/bizPurchaseSupplyRecord/add', // 报价
...@@ -34,7 +35,7 @@ export function supplyList(params = {}) { ...@@ -34,7 +35,7 @@ export function supplyList(params = {}) {
/** /**
* @param params 请求参数 * @param params 请求参数
* @description: 采购需求详情 * @description: 采购详情
*/ */
export function purchaseSellDetails(params = {}) { export function purchaseSellDetails(params = {}) {
return otherHttp.get({ return otherHttp.get({
...@@ -48,6 +49,20 @@ export function purchaseSellDetails(params = {}) { ...@@ -48,6 +49,20 @@ export function purchaseSellDetails(params = {}) {
/** /**
* @param params 请求参数 * @param params 请求参数
* @description: 供应详情
*/
export function supplyDetails(params = {}) {
return otherHttp.get({
url: Api.supplyDetails,
params,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
})
}
/**
* @param params 请求参数
* @description: 发布采购需求 * @description: 发布采购需求
*/ */
export function purchaseSellAdd(params = {}) { export function purchaseSellAdd(params = {}) {
......
import { otherHttp } from '/@/utils/http/axios' import { otherHttp } from '/@/utils/http/axios'
enum Api { // enum Api {
bizCommonFileList = '/mine/bizCommonFile/list', // 文件列表 // bizCommonFileList = '/mine/bizCommonFile/list', // 文件列表
} // }
//
/** // export function bizCommonFileList(params = {}) {
* @param params 请求参数 // return otherHttp.get({
* @description: 文件列表 // url: Api.bizCommonFileList,
*/ // params,
export function bizCommonFileList(params = {}) { // })
return otherHttp.get({ // }
url: Api.bizCommonFileList, // export function getResourceList(params = {}) {
params, // }
}) // export function addResource(params = {}) {
} // }
/** // export function downloadResource(params = {}) {
* 资源列表 // }
* @param params
* @returns
*/
export function getResourceList(params = {}) {
return otherHttp.get({
url: '/resource/list',
params,
})
}
/**
* 添加资源
* @param params
* @returns
*/
export function addResource(params = {}) {
return otherHttp.post({
url: '/resource/add',
params,
})
}
/**
* 下载资源
* @param params
* @returns
*/
export function downloadResource(params = {}) {
return otherHttp.get({
url: '/resource/download',
params,
})
}
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import * as LinghuoyonggongAPI from '@/api/model/linghuoyonggong'
const props = defineProps({
show: { type: Boolean, default: false },
title: { type: String, default: '选择所在地区' },
layer: { type: Number, default: 3 }, // 1-5 层
rootCode: { type: [String, Number], default: 0 }, // 湖南省代码是 43,默认 0 为全国
})
const emit = defineEmits(['update:show', 'confirm', 'cancel'])
const cascaderRef = ref(null)
const state = reactive({
options: [],
value: [],
})
// 监听显示状态
watch(() => props.show, (val) => {
if (val && state.options.length === 0) {
fetchSubData(props.rootCode, null)
}
})
function fetchSubData(parentCode, e) {
LinghuoyonggongAPI.queryConditions({ parentCode }).then((res) => {
if (res && res.length) {
const dataArr = res.map(i => ({ text: i.name, value: i.code }))
if (!state.options.length) {
state.options = dataArr
} else {
cascaderRef.value.setRequestData(dataArr, e.layer)
}
} else {
if (cascaderRef.value) cascaderRef.value.end()
}
})
}
function handleChange(e) {
// e.layer 从 1 开始
if (e.layer < props.layer) {
fetchSubData(e.value, e)
} else {
if (cascaderRef.value) cascaderRef.value.end()
}
}
function handleComplete(e) {
emit('confirm', {
text: e.text,
value: e.value,
fullText: e.text.join(' / '),
fullCode: e.value.join(',')
})
emit('update:show', false)
}
function handleClose() {
emit('update:show', false)
emit('cancel')
}
</script>
<template>
<fui-bottom-popup :show="show" @close="handleClose">
<view class="area-picker-wrap">
<view class="area-header">
<text class="area-title">{{ title }}</text>
<view class="close-icon" @click="handleClose">
<fui-icon name="close" :size="44" color="#ccc"></fui-icon>
</view>
</view>
<view class="area-body">
<fui-cascader
ref="cascaderRef"
:value="state.value"
stepLoading
@change="handleChange"
@complete="handleComplete"
:options="state.options"
/>
</view>
</view>
</fui-bottom-popup>
</template>
<style lang="scss" scoped>
.area-picker-wrap {
background-color: #fff;
border-radius: 32rpx 32rpx 0 0;
display: flex;
flex-direction: column;
height: 80vh;
font-family: 'DingTalk Sans', sans-serif;
}
.area-header {
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx 30rpx;
position: relative;
border-bottom: 1rpx solid #f5f5f5;
.area-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.close-icon {
position: absolute;
right: 30rpx;
top: 50%;
transform: translateY(-50%);
padding: 10rpx;
}
}
.area-body {
flex: 1;
overflow: hidden;
}
/* 统一字体穿透 */
:deep(.fui-cascader__item) {
font-family: 'DingTalk Sans' !important;
}
</style>
...@@ -80,6 +80,8 @@ export function useMapbox<T extends MapboxInstance, P extends MapboxConfig>( ...@@ -80,6 +80,8 @@ export function useMapbox<T extends MapboxInstance, P extends MapboxConfig>(
getInstance()?.setLayoutProperty(layerId, name, value), getInstance()?.setLayoutProperty(layerId, name, value),
setFilter: (layerId: string, filter: any[]) => getInstance()?.setFilter(layerId, filter), setFilter: (layerId: string, filter: any[]) => getInstance()?.setFilter(layerId, filter),
flyTo: (options: mapboxgl.FlyToOptions) => getInstance()?.flyTo(options), flyTo: (options: mapboxgl.FlyToOptions) => getInstance()?.flyTo(options),
fitBounds: (bounds: [[number, number], [number, number]], options?: mapboxgl.FitBoundsOptions) =>
getInstance()?.fitBounds(bounds, options),
addMarker: ( addMarker: (
id: string, id: string,
lnglat: [number, number], lnglat: [number, number],
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
flyToOptions: undefined, flyToOptions: undefined,
regionOptions: undefined, regionOptions: undefined,
addMarkerOptions: undefined, addMarkerOptions: undefined,
fitBoundsOptions: undefined,
// change options 锁,结合 event,配合数组实现先进先出队列控制 // change options 锁,结合 event,配合数组实现先进先出队列控制
changeLock: false, changeLock: false,
...@@ -372,6 +373,18 @@ ...@@ -372,6 +373,18 @@
this.tryTriggerChange() this.tryTriggerChange()
}, },
fitBounds(bounds, options) {
// 加入到 change 事件队列中
this.changeOptionsQueue.push({
fn: 'fitBounds',
bounds,
options,
})
// 尝试触发 change 事件
this.tryTriggerChange()
},
addMarker(id, lngLat, popup, popupDefaultOpen, imageUrl, iconSize) { addMarker(id, lngLat, popup, popupDefaultOpen, imageUrl, iconSize) {
// 加入到 change 事件队列中 // 加入到 change 事件队列中
this.changeOptionsQueue.push({ this.changeOptionsQueue.push({
...@@ -460,6 +473,8 @@ ...@@ -460,6 +473,8 @@
:change:regionOptions="mapbox.changeRegionOptions" :change:regionOptions="mapbox.changeRegionOptions"
:addMarkerOptions="addMarkerOptions" :addMarkerOptions="addMarkerOptions"
:change:addMarkerOptions="mapbox.changeAddMarkerOptions" :change:addMarkerOptions="mapbox.changeAddMarkerOptions"
:fitBoundsOptions="fitBoundsOptions"
:change:fitBoundsOptions="mapbox.changeFitBoundsOptions"
/> />
<!-- #endif --> <!-- #endif -->
<!-- #ifndef APP-PLUS || H5 --> <!-- #ifndef APP-PLUS || H5 -->
......
...@@ -410,6 +410,11 @@ export default { ...@@ -410,6 +410,11 @@ export default {
this.map.flyTo(options) this.map.flyTo(options)
} }
}, },
changeFitBoundsOptions(options) {
if (this.checkOnChangeValidity(options)) {
this.map.fitBounds(options.bounds, options.options)
}
},
changeAddSourceOptions(options) { changeAddSourceOptions(options) {
if (this.checkOnChangeValidity(options)) { if (this.checkOnChangeValidity(options)) {
if (this.map.getSource(options.id)) { if (this.map.getSource(options.id)) {
......
...@@ -293,20 +293,7 @@ ...@@ -293,20 +293,7 @@
"navigationBarBackgroundColor": "#5DB66F", "navigationBarBackgroundColor": "#5DB66F",
"navigationBarTextStyle": "white", "navigationBarTextStyle": "white",
"backgroundColorBottom": "#F2F2F2", "backgroundColorBottom": "#F2F2F2",
"onReachBottomDistance": 50, "onReachBottomDistance": 50
"app-plus": {
"titleNView": {
"titleSize": "20",
"buttons": [
{
"text": "申请入驻",
"color": "#fff",
"fontSize": "28rpx",
"width": "auto"
}
]
}
}
} }
}, },
{ {
...@@ -357,21 +344,7 @@ ...@@ -357,21 +344,7 @@
"navigationBarBackgroundColor": "#5DB66F", "navigationBarBackgroundColor": "#5DB66F",
"navigationBarTextStyle": "white", "navigationBarTextStyle": "white",
"backgroundColorBottom": "#F2F2F2", "backgroundColorBottom": "#F2F2F2",
"onReachBottomDistance": 50, "onReachBottomDistance": 50
"app-plus": {
"titleNView": {
"buttons": [
{
"text": "\uE674 地图模式",
"fontSrc": "/static/fonts/tihuan.ttf",
"color": "#fff",
"fontSize": "26rpx",
"width": "auto",
"icon": "map"
}
]
}
}
} }
}, },
{ {
...@@ -382,21 +355,7 @@ ...@@ -382,21 +355,7 @@
"navigationBarBackgroundColor": "#5DB66F", "navigationBarBackgroundColor": "#5DB66F",
"navigationBarTextStyle": "white", "navigationBarTextStyle": "white",
"backgroundColorBottom": "#F2F2F2", "backgroundColorBottom": "#F2F2F2",
"onReachBottomDistance": 50, "onReachBottomDistance": 50
"app-plus": {
"titleNView": {
"buttons": [
{
"text": "\uE674 列表模式",
"fontSrc": "/static/fonts/tihuan.ttf",
"color": "#fff",
"fontSize": "26rpx",
"width": "auto",
"icon": "map"
}
]
}
}
} }
}, },
{ {
...@@ -591,29 +550,6 @@ ...@@ -591,29 +550,6 @@
} }
}, },
{ {
"path": "pages/resource/resource",
"style": {
"navigationBarTitleText": "资源库管理",
"enablePullDownRefresh": false,
"navigationBarBackgroundColor": "#5DB66F",
"navigationBarTextStyle": "white",
"backgroundColorBottom": "#F2F2F2",
"app-plus": {
"titleNView": {
"buttons": [
{
"text": "+ 添加资源",
"fontSrc": "/static/uni.ttf",
"color": "#fff",
"fontSize": "26rpx",
"width": "auto"
}
]
}
}
}
},
{
"path": "pages/nongchang/detail/index", "path": "pages/nongchang/detail/index",
"style": { "style": {
"navigationStyle": "custom", "navigationStyle": "custom",
...@@ -689,19 +625,7 @@ ...@@ -689,19 +625,7 @@
"path" : "pages/kexinnongzi/kexinnongzi", "path" : "pages/kexinnongzi/kexinnongzi",
"style" : "style" :
{ {
"navigationBarTitleText" : "可信农资", "navigationBarTitleText" : "可信农资"
"app-plus": {
"titleNView": {
"buttons": [
{
"text": "申请入驻",
"color": "#fff",
"fontSize": "26rpx",
"width": "auto"
}
]
}
}
} }
}, },
{ {
......
...@@ -3,7 +3,7 @@ import { onShow } from '@dcloudio/uni-app' ...@@ -3,7 +3,7 @@ import { onShow } from '@dcloudio/uni-app'
import { useUserStore } from '@/store/modules/user' import { useUserStore } from '@/store/modules/user'
import { useGlobSetting } from '/@/hooks/setting' import { useGlobSetting } from '/@/hooks/setting'
import * as NongchangAPI from '@/api/model/nongchang' import * as NongchangAPI from '@/api/model/nongchang'
import { areaTree } from '@/utils/areaData' import AreaPicker from '@/components/AreaPicker/index.vue'
import { useDictStore } from '@/store/modules/dict' import { useDictStore } from '@/store/modules/dict'
const dictStore = useDictStore() const dictStore = useDictStore()
...@@ -166,7 +166,6 @@ const pageData = reactive({ ...@@ -166,7 +166,6 @@ const pageData = reactive({
}) })
function initDict() { function initDict() {
pageData.options.address = areaTree
pageData.options.mainProducts = dictStore.getDictList.main_business.map((item) => { pageData.options.mainProducts = dictStore.getDictList.main_business.map((item) => {
return { return {
value: item.value, value: item.value,
...@@ -180,6 +179,12 @@ function initDict() { ...@@ -180,6 +179,12 @@ function initDict() {
} }
}) })
} }
function handleAreaConfirm(e) {
pageData.form.provinceName = e.text[0]
pageData.form.cityName = e.text[1]
pageData.form.districtName = e.text[2]
pageData.form.provinceText = e.fullText
}
function handleChangeFarmType(e) { function handleChangeFarmType(e) {
pageData.form.farmType = e.value pageData.form.farmType = e.value
pageData.form.farmTypeText = e.text pageData.form.farmTypeText = e.text
...@@ -190,13 +195,6 @@ function handleChangeGrowCrops(e) { ...@@ -190,13 +195,6 @@ function handleChangeGrowCrops(e) {
pageData.form.growCropsText = e.text pageData.form.growCropsText = e.text
pageData.show.mainProducts = false pageData.show.mainProducts = false
} }
function handleChangeAddress(e) {
pageData.form.provinceName = e.text[0]
pageData.form.cityName = e.text[1]
pageData.form.districtName = e.text[2]
pageData.form.provinceText = e.text[0] + '/' + e.text[1] + '/' + e.text[2]
pageData.show.address = false
}
const toastRef = ref() const toastRef = ref()
const uploadRef = ref() const uploadRef = ref()
// 文件上传 // 文件上传
...@@ -500,14 +498,7 @@ function submit() { ...@@ -500,14 +498,7 @@ function submit() {
@change="handleChangeGrowCrops" @change="handleChangeGrowCrops"
@cancel="pageData.show.mainProducts = false" @cancel="pageData.show.mainProducts = false"
/> />
<fui-picker <AreaPicker v-model:show="pageData.show.address" :layer="3" title="选择归属地区" @confirm="handleAreaConfirm" />
:show="pageData.show.address"
:options="pageData.options.address"
:linkage="true"
:layer="3"
@change="handleChangeAddress"
@cancel="pageData.show.address = false"
/>
<fui-toast ref="toastRef" /> <fui-toast ref="toastRef" />
<fui-loading isFixed v-if="pageData.loading" backgroundColor="rgba(0, 0, 0, 0.4)" /> <fui-loading isFixed v-if="pageData.loading" backgroundColor="rgba(0, 0, 0, 0.4)" />
......
<script setup lang="ts"> <script setup lang="ts">
import { reactive } from 'vue' import { reactive, ref, onMounted } from 'vue'
import * as NongjifuwuAPI from '@/api/model/nongjifuwu' import * as NongjifuwuAPI from '@/api/model/nongjifuwu'
import { useUserStore } from '@/store/modules/user' import { useUserStore } from '@/store/modules/user'
import { getDictData, getText } from '@/utils/dict/area' import AreaPicker from '@/components/AreaPicker/index.vue'
const { getUserInfo } = useUserStore() const { getUserInfo } = useUserStore()
...@@ -10,12 +10,9 @@ ...@@ -10,12 +10,9 @@
show: false, show: false,
areaShow: { areaShow: {
time: false, time: false,
classify: false,
address: false, address: false,
}, },
options: null, scopeText: '',
scopeText: null,
content: '',
form: { form: {
machineId: '', machineId: '',
serviceType: '', serviceType: '',
...@@ -29,190 +26,93 @@ ...@@ -29,190 +26,93 @@
demand: '', demand: '',
}, },
rules: [ rules: [
{ { name: 'phone', rule: ['required', 'isMobile'], msg: ['请填写手机号码', '手机号格式不正确'] },
name: 'phone', { name: 'scope', rule: ['required'], msg: ['请选择作业区域'] },
rule: ['required'], { name: 'startTime', rule: ['required'], msg: ['请选择开始时间'] },
msg: ['请填写手机号码'], { name: 'endTime', rule: ['required'], msg: ['请选择结束时间'] },
}, { name: 'address', rule: ['required'], msg: ['请填写详细地址'] },
{ { name: 'demand', rule: ['required'], msg: ['请填写需求'] },
name: 'scope',
rule: ['required'],
msg: ['请选择作业区域'],
},
{
name: 'startTime',
rule: ['required'],
msg: ['请选择开始时间'],
},
{
name: 'endTime',
rule: ['required'],
msg: ['请选择结束时间'],
},
{
name: 'address',
rule: ['required'],
msg: ['请填写详细地址'],
},
{
name: 'demand',
rule: ['required'],
msg: ['请填写需求'],
},
], ],
}) })
const dict = reactive({
show: {
time: false,
},
})
function handleTimeChange(e) { function handleTimeChange(e) {
pageData.form.startTime = e.startDate.result pageData.form.startTime = e.startDate.result
pageData.form.endTime = e.endDate.result pageData.form.endTime = e.endDate.result
pageData.form.time = `${e.startDate.result}${e.endDate.result}` pageData.form.time = `${e.startDate.result}${e.endDate.result}`
dict.show.time = false pageData.areaShow.time = false
}
function handleTimeCancel() {
dict.show.time = false
} }
function open(params) { function open(params) {
reset() reset()
pageData.form.machineId = params.id pageData.form.machineId = params.id
pageData.form.serviceType = params.serviceType pageData.form.serviceType = params.serviceType
pageData.form.userId = getUserInfo.id pageData.form.userId = getUserInfo?.id || ''
pageData.show = true pageData.show = true
} }
function close() { function close() {
pageData.show = false pageData.show = false
pageData.areaShow.address = false
} }
function reset() { function reset() {
pageData.form = { pageData.form = {
machineId: '', machineId: '', serviceType: '', userId: '', time: '', startTime: '', endTime: '',
serviceType: '', scope: '', address: '', phone: '', demand: '',
userId: '',
time: '',
startTime: '',
endTime: '',
scope: '',
address: '',
phone: '',
demand: '',
} }
pageData.scopeText = null pageData.scopeText = ''
} }
const formRef = ref() const formRef = ref()
function submit() { function submit() {
formRef.value.validator(pageData.form, pageData.rules, true).then((res) => { formRef.value.validator(pageData.form, pageData.rules, true).then((res) => {
if (res.isPassed) { if (res.isPassed) {
NongjifuwuAPI.farmMachineRegister(pageData.form).then(() => { NongjifuwuAPI.farmMachineRegister(pageData.form).then(() => {
reset() uni.showToast({ title: '预约提交成功', icon: 'success' })
close() close()
uni.showToast({
title: '提交成功',
icon: 'success',
})
}) })
} }
}) })
} }
function handleChangeAddress(e) {
pageData.form.scope = e.value.join(',') function handleAreaConfirm(e) {
pageData.scopeText = getText(pageData.form.scope, ' / ') pageData.form.scope = e.fullCode
pageData.areaShow.address = false pageData.scopeText = e.fullText
} }
onShow(() => {
pageData.options = getDictData() defineExpose({ open, close })
})
defineExpose({
open,
close,
})
</script> </script>
<template> <template>
<fui-dialog title="" :buttons="[]" :show="pageData.show" maskClosable> <fui-dialog title="" :buttons="[]" :show="pageData.show" maskClosable @close="close">
<view class="title flex justify-center"> <view class="dialog-header">
<view class="flex-1">预约表单</view> <text class="dialog-title">预约登记</text>
<fui-icon class="close flex-basis" name="close" size="46" color="#999999" @click="close" /> <fui-icon name="close" :size="40" color="#999" @click="close"></fui-icon>
</view> </view>
<view class="text-left"> <view class="dialog-body">
<fui-form ref="formRef"> <fui-form ref="formRef">
<fui-input <fui-input label="联系电话" placeholder="请输入手机号" v-model="pageData.form.phone" required type="number" maxlength="11" />
marginTop="30" <fui-input label="作业区域" placeholder="请选择" v-model="pageData.scopeText" @click="pageData.areaShow.address = true" disabled required />
size="24" <fui-input label="详细地址" placeholder="村组/街道门牌" v-model="pageData.form.address" required />
type="number" <fui-input label="作业时间" placeholder="请选择周期" v-model="pageData.form.time" @click="pageData.areaShow.time = true" disabled required />
maxlength="11" <fui-textarea label="需求说明" placeholder="简要说明作业要求..." v-model="pageData.form.demand" required height="120rpx" />
placeholder="请填写手机号码"
v-model="pageData.form.phone" <view class="submit-btn-wrap">
required <fui-button text="立即预约" radius="100rpx" background="#5db66f" @click="submit" />
placeholderStyle="margin-left: 10rpx;"
/>
<fui-input
marginTop="30"
size="24"
disabled
@click="pageData.areaShow.address = true"
placeholder="请选择作业区域"
v-model="pageData.scopeText"
required
placeholderStyle="margin-left: 10rpx;"
/>
<fui-input
marginTop="30"
size="24"
placeholder="请填写详细地址"
v-model="pageData.form.address"
required
placeholderStyle="margin-left: 10rpx;"
/>
<fui-input
marginTop="30"
size="24"
placeholder="请选择作业时间"
v-model="pageData.form.time"
@click="dict.show.time = true"
required
placeholderStyle="margin-left: 10rpx;"
/>
<fui-textarea
v-model="pageData.form.demand"
:marginTop="30"
size="24"
placeholder="简要说明作业要求"
flexStart
required
placeholderStyle="margin-left: 10rpx;"
height="100rpx"
/>
<view style="margin-top: 30rpx">
<fui-button type="warning" text="提交" bold radius="96rpx" @click="submit" />
</view> </view>
</fui-form> </fui-form>
</view> </view>
</fui-dialog> </fui-dialog>
<fui-date-picker :show="dict.show.time" type="3" range @change="handleTimeChange" @cancel="handleTimeCancel" />
<fui-picker <fui-date-picker :show="pageData.areaShow.time" type="3" range @change="handleTimeChange" @cancel="pageData.areaShow.time = false" />
:show="pageData.areaShow.address" <AreaPicker v-model:show="pageData.areaShow.address" :layer="3" title="选择作业区域" @confirm="handleAreaConfirm" />
:options="pageData.options"
:linkage="true"
:layer="3"
@change="handleChangeAddress"
@cancel="pageData.areaShow.address = false"
/>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.fui-dialog__body) { .dialog-header {
background: linear-gradient(0deg, rgba(93, 182, 111, 0) 0%, rgba(93, 182, 111, 0.25) 100%); display: flex; justify-content: space-between; align-items: center; padding: 20rpx 0;
margin: 0; .dialog-title { font-size: 32rpx; font-weight: bold; color: #333; }
}
:deep(.fui-dialog__footer) {
display: none;
}
:deep(.fui-input) {
margin-top: 40rpx;
} }
.dialog-body { text-align: left; padding-bottom: 20rpx; }
.submit-btn-wrap { margin-top: 40rpx; }
:deep(.fui-input__label) { font-size: 28rpx; width: 160rpx !important; }
</style> </style>
<script setup>
import { reactive, ref } from 'vue'
import { onNavigationBarButtonTap } from '@dcloudio/uni-app'
import SaveDialog from './components/save-dialog.vue'
import * as API from '@/api/model/wode'
const isOnePage = ref(true)
const paging = ref(null)
const pageData = reactive({
param: {
pageNo: 1,
pageSize: 10,
fileName: '',
},
list: [],
})
function getList() {
if (!paging.value)
return
// API留空,使用模拟数据 - 根据图片内容调整
API.getResourceList(pageData.param).then((res) => {
paging.value.complete(res.records)
})
}
function queryList(pageNo, pageSize) {
pageData.param.pageNo = pageNo
pageData.param.pageSize = pageSize
getList()
}
function handleSearch() {
pageData.param.pageNo = 1
if (paging.value) {
paging.value.reload()
}
}
const showDialog = ref(false)
const currentEditData = ref(null)
onNavigationBarButtonTap((_) => {
showAddDialog()
})
function showAddDialog() {
currentEditData.value = null
showDialog.value = true
}
// 格式化时间显示
function formatTime(time) {
if (!time) return ''
// 如果是完整的时间字符串,可以格式化为图片中的样式
return time.includes(' ') ? time : `${time} 14:00`
}
// 下载资源
async function handleDownload(resource) {
await API.downloadResource({ id: resource.id })
// 更新下载次数
const index = pageData.list.findIndex((item) => item.id === resource.id)
if (index !== -1) {
pageData.list[index].downloadCount = (pageData.list[index].downloadCount || 0) + 1
}
const { downloadResource } = await import('@/utils')
// 使用封装的下载方法
const result = await downloadResource(resource)
if (!result.success) {
console.error('下载失败:', result.error)
}
}
// 格式化文件大小
function formatFileSize(bytes) {
if (!bytes) return '125kb'
const k = 1024
const sizes = ['B', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return Number.parseFloat((bytes / k ** i).toFixed(0)) + sizes[i].toLowerCase()
}
function handleSubmitSuccess() {
showDialog.value = false
// 重新加载数据
handleSearch()
}
</script>
<template>
<view class="codefun-flex-col page">
<z-paging ref="paging" v-model="pageData.list" @query="queryList">
<view class="codefun-flex-col group_3">
<view class="codefun-flex-row codefun-items-center section_2">
<image class="image_6" src="/static/images/codefun/6c5c5a3c082b8c60a307d3a7caee623c.png" />
<u-input
v-model="pageData.param.fileName"
placeholder="请输入文件名称搜索"
border="none"
class="codefun-ml-8"
@confirm="handleSearch"
/>
</view>
<!-- 资源列表 - 根据图片样式修改 -->
<view class="resource-list">
<view v-for="(item, index) in pageData.list" :key="index" class="resource-item">
<view class="resource-content">
<view class="resource-main">
<view class="resource-name">{{ item.fileName }}</view>
<view class="resource-meta">
<text class="resource-size">{{ item.fileSize }}</text>
<text class="separator">|</text>
<text class="download-count">已下载{{ item.downloadCount || 0 }}</text>
<text class="separator">|</text>
<text class="upload-time">{{ formatTime(item.createTime) }}</text>
</view>
</view>
<view
class="codefun-flex-col codefun-justify-start codefun-items-center text-wrapper_4"
@click.stop="handleDownload(item)"
>
<text class="font_10">下载</text>
</view>
<!-- <view class="download-section">
<view class="download-btn" @click="handleDownload(item)">
<text class="btn-text">下载</text>
</view>
</view> -->
</view>
</view>
</view>
<!-- 空状态 -->
<!-- <view class="empty-state" v-if="pageData.list.length === 0">
<image class="empty-icon" src="/static/images/empty.png" mode="aspectFit"></image>
<text class="empty-text">暂无资源</text>
</view> -->
</view>
</z-paging>
<!-- 弹窗组件 -->
<SaveDialog
:show="showDialog"
:editData="currentEditData"
@update:show="showDialog = $event"
@submit-success="handleSubmitSuccess"
/>
</view>
</template>
<style lang="scss">
body {
background: #e6f5e8;
}
.page {
background: #e6f5e8;
width: 100%;
overflow-y: auto;
overflow-x: hidden;
height: 100%;
}
.group_3 {
padding: 28rpx 24rpx;
}
.section_2 {
padding: 16rpx 20rpx;
background-color: #ffffff;
border-radius: 1998rpx;
margin-bottom: 30rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
}
.image_6 {
width: 32rpx;
height: 32rpx;
}
/* 资源列表样式 - 根据图片样式重写 */
.resource-list {
margin-top: 0;
border-radius: 16rpx;
background-color: #ffffff;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
padding: 0 20rpx;
}
.resource-item {
// border-radius: 16rpx;
// margin-bottom: 20rpx;
overflow: hidden;
transition: all 0.3s ease;
border-bottom: 1px solid #e3e3e3;
&:active {
transform: translateY(2rpx);
box-shadow: 0 1rpx 6rpx rgba(0, 0, 0, 0.1);
}
}
.resource-content {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx 24rpx;
}
.resource-main {
flex: 1;
min-width: 0;
}
.resource-name {
font-size: 32rpx;
font-weight: 500;
color: #333333;
line-height: 1.4;
margin-bottom: 12rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
text-overflow: ellipsis;
}
.resource-meta {
display: flex;
align-items: center;
font-size: 20rpx;
color: #999999;
gap: 10rpx;
flex-wrap: wrap;
}
.separator {
color: #dddddd;
font-size: 20rpx;
}
.resource-size,
.download-count,
.upload-time {
color: #666666;
}
.download-section {
margin-left: 30rpx;
flex-shrink: 0;
}
.download-btn {
background-color: #5db66f;
border: none;
border-radius: 20rpx;
padding: 12rpx 30rpx;
min-width: 120rpx;
transition: all 0.3s ease;
&::after {
border: none;
}
&:active {
background-color: #4ca85c;
transform: scale(0.95);
}
}
.text-wrapper_4 {
padding: 16rpx 0;
background-color: #5db66f26;
border-radius: 400rpx;
mix-blend-mode: NOTTHROUGH;
width: 136rpx;
.font_10 {
font-size: 24rpx;
line-height: 24rpx;
color: #16a34a;
}
}
.btn-text {
color: #ffffff;
font-size: 28rpx;
font-weight: 500;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
padding: 120rpx 0;
color: #999999;
}
.empty-icon {
width: 160rpx;
height: 160rpx;
margin-bottom: 30rpx;
opacity: 0.6;
}
.empty-text {
font-size: 28rpx;
color: #999999;
}
/* 响应式调整 */
@media (max-width: 375px) {
.resource-content {
padding: 24rpx 20rpx;
}
.resource-name {
font-size: 30rpx;
}
.resource-meta {
font-size: 22rpx;
}
.download-btn {
padding: 10rpx 24rpx;
min-width: 100rpx;
}
.btn-text {
font-size: 26rpx;
}
}
</style>
...@@ -16,6 +16,12 @@ ...@@ -16,6 +16,12 @@
onLoad(async () => { onLoad(async () => {
try { try {
await getServiceItems() await getServiceItems()
// 如果已经登录,尝试静默进入,无需等待4秒倒计时
const token = userStore.getToken
if (token) {
// 缩短等待时间到 1s,给用户看一眼开屏图的时间,同时提升体验
seconds.value = 1
}
} finally { } finally {
// #ifdef APP-PLUS // #ifdef APP-PLUS
plus.navigator.closeSplashscreen() plus.navigator.closeSplashscreen()
......
...@@ -79,49 +79,6 @@ ...@@ -79,49 +79,6 @@
}, },
], ],
// 常用资源
commonResources: {
title: '常用资源',
actionText: '',
icon: {
1: {
icon: '/static/images/codefun/doc_img.png',
name: '文档格式',
},
2: {
icon: '/static/images/codefun/elx_img.png',
name: '表格格式',
},
3: {
icon: '/static/images/codefun/pdf_img.png',
name: 'PDF格式',
},
},
resources: [
// {
// id: 1,
// icon: '/static/images/codefun/38f8cccf12ace58fd9cd4612dce944b0.png',
// title: '水稻种植合同模版',
// size: '125kb',
// actionText: '下载',
// },
// {
// id: 2,
// icon: '/static/images/codefun/38f8cccf12ace58fd9cd4612dce944b0.png',
// title: '玉米种植技术指南',
// size: '210kb',
// actionText: '下载',
// },
// {
// id: 3,
// icon: '/static/images/codefun/38f8cccf12ace58fd9cd4612dce944b0.png',
// title: '肥料使用记录表',
// size: '86kb',
// actionText: '下载',
// },
],
},
// 我的设备 // 我的设备
myDevices: { myDevices: {
title: '我的设备', title: '我的设备',
...@@ -174,15 +131,6 @@ ...@@ -174,15 +131,6 @@
}, },
}) })
function getBizCommonFileList() {
WodeAPI.bizCommonFileList({
pageNo: 1,
pageSize: 4,
}).then((res) => {
const { records } = res
pageData.commonResources.resources = records
})
}
function getFarmBaseList(id) { function getFarmBaseList(id) {
NongchangAPI.getFarmBaseList({ id }).then((res) => { NongchangAPI.getFarmBaseList({ id }).then((res) => {
pageData.statistics[0].value = res.length pageData.statistics[0].value = res.length
...@@ -242,33 +190,6 @@ ...@@ -242,33 +190,6 @@
if (feature.id === 2) if (feature.id === 2)
showAddDialog() showAddDialog()
} }
// 常用资源点击事件
function onResourceClick(resource: any) {
console.log('点击资源:', resource)
// 在这里添加具体的资源点击逻辑
}
// 资源下载点击事件
async function onDownloadClick(e, resource: any) {
// 阻止事件冒泡
e?.stopPropagation()
const { downloadResource } = await import('@/utils')
// 使用封装的下载方法
const result = await downloadResource(resource)
if (!result.success) {
console.error('下载失败:', result.error)
}
}
// 查看所有资源
function onViewAllResources() {
console.log('查看所有资源')
// 在这里添加具体的查看所有资源逻辑
}
// 我的设备标题点击事件 // 我的设备标题点击事件
function onMyDevicesTitleClick() { function onMyDevicesTitleClick() {
console.log('点击我的设备标题') console.log('点击我的设备标题')
......
...@@ -74,15 +74,25 @@ const transform: AxiosTransform = { ...@@ -74,15 +74,25 @@ const transform: AxiosTransform = {
userStore.setToken('') userStore.setToken('')
// 判断当前页面是否为登录页,防止多个请求时重复跳转 // 判断当前页面是否为登录页,防止多个请求时重复跳转
const page = getCurrentPages()[0] const pages = getCurrentPages()
const loginPageRoute = `/pages/login/login` if (pages.length > 0) {
const page = pages[pages.length - 1]
const loginPageRoute = 'pages/login/login'
if (page.route !== loginPageRoute) { if (page.route !== loginPageRoute) {
// 跳转到登录页 // 跳转到登录页
uni.showToast({
title: '登录已过期,请重新登录',
icon: 'none',
duration: 2000
})
setTimeout(() => {
uni.reLaunch({ uni.reLaunch({
url: loginPageRoute, url: `/${loginPageRoute}`,
}) })
}, 1500)
return return
} }
}
break break
} }
......
...@@ -8,6 +8,7 @@ export {} ...@@ -8,6 +8,7 @@ export {}
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
AffixFilter: typeof import('./../src/components/Map/Widgets/AffixFilter/src/AffixFilter.vue')['default'] AffixFilter: typeof import('./../src/components/Map/Widgets/AffixFilter/src/AffixFilter.vue')['default']
AreaPicker: typeof import('./../src/components/AreaPicker/index.vue')['default']
BottomBar: typeof import('./../src/components/Map/Widgets/BottomBar/src/BottomBar.vue')['default'] BottomBar: typeof import('./../src/components/Map/Widgets/BottomBar/src/BottomBar.vue')['default']
CacheImage: typeof import('./../src/components/CacheImage/index.vue')['default'] CacheImage: typeof import('./../src/components/CacheImage/index.vue')['default']
ConfirmDialog: typeof import('./../src/components/ConfirmDialog/index.vue')['default'] ConfirmDialog: typeof import('./../src/components/ConfirmDialog/index.vue')['default']
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论