提交 b4b30b49 作者: 廖在望

feat: 页面功能重构

上级 1c87240e
# API 接口地址
# 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://123.207.47.17
VITE_GLOB_API_URL=http://localhost:8080
# API 接口地址前缀
# 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'
enum Api {
purchaseList = '/purchaseSell/bizPurchase/list', // 采购需求列表
supplyList = '/purchaseSell/bizSupply/list', // 供应需求列表
purchaseSellDetails = '/purchaseSell/bizPurchase/queryById', // 产销详情
purchaseSellDetails = '/purchaseSell/bizPurchase/queryById', // 采购详情
supplyDetails = '/purchaseSell/bizSupply/queryById', // 供应详情
purchaseSell = '/purchaseSell/bizPurchase/add', // 发布采购需求
supplyAdd = '/purchaseSell/bizSupply/add', // 发布供应需求
bizPurchaseSupplyRecord = '/purchaseSell/bizPurchaseSupplyRecord/add', // 报价
......@@ -34,7 +35,7 @@ export function supplyList(params = {}) {
/**
* @param params 请求参数
* @description: 采购需求详情
* @description: 采购详情
*/
export function purchaseSellDetails(params = {}) {
return otherHttp.get({
......@@ -48,6 +49,20 @@ export function purchaseSellDetails(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: 发布采购需求
*/
export function purchaseSellAdd(params = {}) {
......
import { otherHttp } from '/@/utils/http/axios'
enum Api {
bizCommonFileList = '/mine/bizCommonFile/list', // 文件列表
}
/**
* @param params 请求参数
* @description: 文件列表
*/
export function bizCommonFileList(params = {}) {
return otherHttp.get({
url: Api.bizCommonFileList,
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,
})
}
// enum Api {
// bizCommonFileList = '/mine/bizCommonFile/list', // 文件列表
// }
//
// export function bizCommonFileList(params = {}) {
// return otherHttp.get({
// url: Api.bizCommonFileList,
// params,
// })
// }
// export function getResourceList(params = {}) {
// }
// export function addResource(params = {}) {
// }
// export function downloadResource(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>(
getInstance()?.setLayoutProperty(layerId, name, value),
setFilter: (layerId: string, filter: any[]) => getInstance()?.setFilter(layerId, filter),
flyTo: (options: mapboxgl.FlyToOptions) => getInstance()?.flyTo(options),
fitBounds: (bounds: [[number, number], [number, number]], options?: mapboxgl.FitBoundsOptions) =>
getInstance()?.fitBounds(bounds, options),
addMarker: (
id: string,
lnglat: [number, number],
......
......@@ -46,6 +46,7 @@
flyToOptions: undefined,
regionOptions: undefined,
addMarkerOptions: undefined,
fitBoundsOptions: undefined,
// change options 锁,结合 event,配合数组实现先进先出队列控制
changeLock: false,
......@@ -372,6 +373,18 @@
this.tryTriggerChange()
},
fitBounds(bounds, options) {
// 加入到 change 事件队列中
this.changeOptionsQueue.push({
fn: 'fitBounds',
bounds,
options,
})
// 尝试触发 change 事件
this.tryTriggerChange()
},
addMarker(id, lngLat, popup, popupDefaultOpen, imageUrl, iconSize) {
// 加入到 change 事件队列中
this.changeOptionsQueue.push({
......@@ -460,6 +473,8 @@
:change:regionOptions="mapbox.changeRegionOptions"
:addMarkerOptions="addMarkerOptions"
:change:addMarkerOptions="mapbox.changeAddMarkerOptions"
:fitBoundsOptions="fitBoundsOptions"
:change:fitBoundsOptions="mapbox.changeFitBoundsOptions"
/>
<!-- #endif -->
<!-- #ifndef APP-PLUS || H5 -->
......
......@@ -410,6 +410,11 @@ export default {
this.map.flyTo(options)
}
},
changeFitBoundsOptions(options) {
if (this.checkOnChangeValidity(options)) {
this.map.fitBounds(options.bounds, options.options)
}
},
changeAddSourceOptions(options) {
if (this.checkOnChangeValidity(options)) {
if (this.map.getSource(options.id)) {
......
......@@ -293,20 +293,7 @@
"navigationBarBackgroundColor": "#5DB66F",
"navigationBarTextStyle": "white",
"backgroundColorBottom": "#F2F2F2",
"onReachBottomDistance": 50,
"app-plus": {
"titleNView": {
"titleSize": "20",
"buttons": [
{
"text": "申请入驻",
"color": "#fff",
"fontSize": "28rpx",
"width": "auto"
}
]
}
}
"onReachBottomDistance": 50
}
},
{
......@@ -357,21 +344,7 @@
"navigationBarBackgroundColor": "#5DB66F",
"navigationBarTextStyle": "white",
"backgroundColorBottom": "#F2F2F2",
"onReachBottomDistance": 50,
"app-plus": {
"titleNView": {
"buttons": [
{
"text": "\uE674 地图模式",
"fontSrc": "/static/fonts/tihuan.ttf",
"color": "#fff",
"fontSize": "26rpx",
"width": "auto",
"icon": "map"
}
]
}
}
"onReachBottomDistance": 50
}
},
{
......@@ -382,21 +355,7 @@
"navigationBarBackgroundColor": "#5DB66F",
"navigationBarTextStyle": "white",
"backgroundColorBottom": "#F2F2F2",
"onReachBottomDistance": 50,
"app-plus": {
"titleNView": {
"buttons": [
{
"text": "\uE674 列表模式",
"fontSrc": "/static/fonts/tihuan.ttf",
"color": "#fff",
"fontSize": "26rpx",
"width": "auto",
"icon": "map"
}
]
}
}
"onReachBottomDistance": 50
}
},
{
......@@ -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",
"style": {
"navigationStyle": "custom",
......@@ -689,19 +625,7 @@
"path" : "pages/kexinnongzi/kexinnongzi",
"style" :
{
"navigationBarTitleText" : "可信农资",
"app-plus": {
"titleNView": {
"buttons": [
{
"text": "申请入驻",
"color": "#fff",
"fontSize": "26rpx",
"width": "auto"
}
]
}
}
"navigationBarTitleText" : "可信农资"
}
},
{
......
......@@ -3,7 +3,7 @@ import { onShow } from '@dcloudio/uni-app'
import { useUserStore } from '@/store/modules/user'
import { useGlobSetting } from '/@/hooks/setting'
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'
const dictStore = useDictStore()
......@@ -166,7 +166,6 @@ const pageData = reactive({
})
function initDict() {
pageData.options.address = areaTree
pageData.options.mainProducts = dictStore.getDictList.main_business.map((item) => {
return {
value: item.value,
......@@ -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) {
pageData.form.farmType = e.value
pageData.form.farmTypeText = e.text
......@@ -190,13 +195,6 @@ function handleChangeGrowCrops(e) {
pageData.form.growCropsText = e.text
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 uploadRef = ref()
// 文件上传
......@@ -500,14 +498,7 @@ function submit() {
@change="handleChangeGrowCrops"
@cancel="pageData.show.mainProducts = false"
/>
<fui-picker
:show="pageData.show.address"
:options="pageData.options.address"
:linkage="true"
:layer="3"
@change="handleChangeAddress"
@cancel="pageData.show.address = false"
/>
<AreaPicker v-model:show="pageData.show.address" :layer="3" title="选择归属地区" @confirm="handleAreaConfirm" />
<fui-toast ref="toastRef" />
<fui-loading isFixed v-if="pageData.loading" backgroundColor="rgba(0, 0, 0, 0.4)" />
......
<script setup lang="ts">
import { reactive } from 'vue'
import { reactive, ref, onMounted } from 'vue'
import * as NongjifuwuAPI from '@/api/model/nongjifuwu'
import { useUserStore } from '@/store/modules/user'
import { getDictData, getText } from '@/utils/dict/area'
import AreaPicker from '@/components/AreaPicker/index.vue'
const { getUserInfo } = useUserStore()
......@@ -10,12 +10,9 @@
show: false,
areaShow: {
time: false,
classify: false,
address: false,
},
options: null,
scopeText: null,
content: '',
scopeText: '',
form: {
machineId: '',
serviceType: '',
......@@ -29,190 +26,93 @@
demand: '',
},
rules: [
{
name: 'phone',
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: ['请填写需求'],
},
{ name: 'phone', rule: ['required', 'isMobile'], 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) {
pageData.form.startTime = e.startDate.result
pageData.form.endTime = e.endDate.result
pageData.form.time = `${e.startDate.result}${e.endDate.result}`
dict.show.time = false
}
function handleTimeCancel() {
dict.show.time = false
pageData.areaShow.time = false
}
function open(params) {
reset()
pageData.form.machineId = params.id
pageData.form.serviceType = params.serviceType
pageData.form.userId = getUserInfo.id
pageData.form.userId = getUserInfo?.id || ''
pageData.show = true
}
function close() {
pageData.show = false
pageData.areaShow.address = false
}
function reset() {
pageData.form = {
machineId: '',
serviceType: '',
userId: '',
time: '',
startTime: '',
endTime: '',
scope: '',
address: '',
phone: '',
demand: '',
machineId: '', serviceType: '', userId: '', time: '', startTime: '', endTime: '',
scope: '', address: '', phone: '', demand: '',
}
pageData.scopeText = null
pageData.scopeText = ''
}
const formRef = ref()
function submit() {
formRef.value.validator(pageData.form, pageData.rules, true).then((res) => {
if (res.isPassed) {
NongjifuwuAPI.farmMachineRegister(pageData.form).then(() => {
reset()
uni.showToast({ title: '预约提交成功', icon: 'success' })
close()
uni.showToast({
title: '提交成功',
icon: 'success',
})
})
}
})
}
function handleChangeAddress(e) {
pageData.form.scope = e.value.join(',')
pageData.scopeText = getText(pageData.form.scope, ' / ')
pageData.areaShow.address = false
function handleAreaConfirm(e) {
pageData.form.scope = e.fullCode
pageData.scopeText = e.fullText
}
onShow(() => {
pageData.options = getDictData()
})
defineExpose({
open,
close,
})
defineExpose({ open, close })
</script>
<template>
<fui-dialog title="" :buttons="[]" :show="pageData.show" maskClosable>
<view class="title flex justify-center">
<view class="flex-1">预约表单</view>
<fui-icon class="close flex-basis" name="close" size="46" color="#999999" @click="close" />
<fui-dialog title="" :buttons="[]" :show="pageData.show" maskClosable @close="close">
<view class="dialog-header">
<text class="dialog-title">预约登记</text>
<fui-icon name="close" :size="40" color="#999" @click="close"></fui-icon>
</view>
<view class="text-left">
<view class="dialog-body">
<fui-form ref="formRef">
<fui-input
marginTop="30"
size="24"
type="number"
maxlength="11"
placeholder="请填写手机号码"
v-model="pageData.form.phone"
required
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" />
<fui-input label="联系电话" placeholder="请输入手机号" v-model="pageData.form.phone" required type="number" maxlength="11" />
<fui-input label="作业区域" placeholder="请选择" v-model="pageData.scopeText" @click="pageData.areaShow.address = true" disabled required />
<fui-input label="详细地址" placeholder="村组/街道门牌" v-model="pageData.form.address" required />
<fui-input label="作业时间" placeholder="请选择周期" v-model="pageData.form.time" @click="pageData.areaShow.time = true" disabled required />
<fui-textarea label="需求说明" placeholder="简要说明作业要求..." v-model="pageData.form.demand" required height="120rpx" />
<view class="submit-btn-wrap">
<fui-button text="立即预约" radius="100rpx" background="#5db66f" @click="submit" />
</view>
</fui-form>
</view>
</fui-dialog>
<fui-date-picker :show="dict.show.time" type="3" range @change="handleTimeChange" @cancel="handleTimeCancel" />
<fui-picker
:show="pageData.areaShow.address"
:options="pageData.options"
:linkage="true"
:layer="3"
@change="handleChangeAddress"
@cancel="pageData.areaShow.address = false"
/>
<fui-date-picker :show="pageData.areaShow.time" type="3" range @change="handleTimeChange" @cancel="pageData.areaShow.time = false" />
<AreaPicker v-model:show="pageData.areaShow.address" :layer="3" title="选择作业区域" @confirm="handleAreaConfirm" />
</template>
<style lang="scss" scoped>
:deep(.fui-dialog__body) {
background: linear-gradient(0deg, rgba(93, 182, 111, 0) 0%, rgba(93, 182, 111, 0.25) 100%);
margin: 0;
}
:deep(.fui-dialog__footer) {
display: none;
}
:deep(.fui-input) {
margin-top: 40rpx;
.dialog-header {
display: flex; justify-content: space-between; align-items: center; padding: 20rpx 0;
.dialog-title { font-size: 32rpx; font-weight: bold; color: #333; }
}
.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>
<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 @@
onLoad(async () => {
try {
await getServiceItems()
// 如果已经登录,尝试静默进入,无需等待4秒倒计时
const token = userStore.getToken
if (token) {
// 缩短等待时间到 1s,给用户看一眼开屏图的时间,同时提升体验
seconds.value = 1
}
} finally {
// #ifdef APP-PLUS
plus.navigator.closeSplashscreen()
......
......@@ -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: {
title: '我的设备',
......@@ -174,15 +131,6 @@
},
})
function getBizCommonFileList() {
WodeAPI.bizCommonFileList({
pageNo: 1,
pageSize: 4,
}).then((res) => {
const { records } = res
pageData.commonResources.resources = records
})
}
function getFarmBaseList(id) {
NongchangAPI.getFarmBaseList({ id }).then((res) => {
pageData.statistics[0].value = res.length
......@@ -242,33 +190,6 @@
if (feature.id === 2)
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() {
console.log('点击我的设备标题')
......
......@@ -74,15 +74,25 @@ const transform: AxiosTransform = {
userStore.setToken('')
// 判断当前页面是否为登录页,防止多个请求时重复跳转
const page = getCurrentPages()[0]
const loginPageRoute = `/pages/login/login`
const pages = getCurrentPages()
if (pages.length > 0) {
const page = pages[pages.length - 1]
const loginPageRoute = 'pages/login/login'
if (page.route !== loginPageRoute) {
// 跳转到登录页
uni.showToast({
title: '登录已过期,请重新登录',
icon: 'none',
duration: 2000
})
setTimeout(() => {
uni.reLaunch({
url: loginPageRoute,
url: `/${loginPageRoute}`,
})
}, 1500)
return
}
}
break
}
......
......@@ -8,6 +8,7 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
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']
CacheImage: typeof import('./../src/components/CacheImage/index.vue')['default']
ConfirmDialog: typeof import('./../src/components/ConfirmDialog/index.vue')['default']
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论