提交 e266b465 作者: 15973817745_JPN

Merge branch 'main' of https://gitee.com/mrf/agri-app

......@@ -180,3 +180,39 @@ page {
.fui-relative {
position: relative;
}
.fab-icon {
position: relative;
width: 40rpx;
height: 40rpx;
font-size: 0;
margin: auto;
}
.fab-icon::before,
.fab-icon::after {
content: '';
position: absolute;
border-radius: 20rpx;
background: linear-gradient(90deg, #ffffff 0%, #ffffff 100%);
}
.fab-icon::before {
/* 横线 */
top: 50%;
left: 25%;
right: 25%;
height: 4rpx;
transform: translateY(-50%);
}
.fab-icon::after {
/* 竖线 */
left: 50%;
top: 25%;
bottom: 25%;
width: 4rpx;
transform: translateX(-50%);
border-radius: 20rpx;
background: linear-gradient(90deg, #ffffff 0%, #ffffff 100%);
}
......@@ -395,14 +395,14 @@
</view>
</view>
</view>
<fui-fab background="#5db66f" position="right" distance="10" bottom="240" width="120" @click="handlePublish">
<fui-fab position="right" distance="10" bottom="240" width="96" @click="handlePublish">
<view v-show="pageData.currentTransactionTab === 1" class="text-white text-center">
<image src="/src/static/images/chanxiao/notepad.svg" style="width: 40rpx" mode="widthFix"></image>
<view style="font-size: 24rpx">发布需求</view>
<view class="fab-icon"></view>
<view style="font-size: 24rpx">发布</view>
</view>
<view v-show="pageData.currentTransactionTab === 2" class="text-white text-center">
<image src="/src/static/images/chanxiao/flower.svg" style="width: 50rpx" mode="widthFix"></image>
<view style="font-size: 24rpx">发布供应</view>
<view class="fab-icon"></view>
<view style="font-size: 24rpx">发布</view>
</view>
</fui-fab>
......@@ -827,4 +827,9 @@
border-top: solid 1rpx #e7e7e7;
}
}
::v-deep .fui-fab__btn-main {
background: linear-gradient(124.25deg, #a5d63f 0%, #5db66f 100%) !important;
box-shadow: 0px 1px 8px #5db66f;
}
</style>
......@@ -77,7 +77,13 @@
<fui-form ref="formRef" top="180" color="#000">
<fui-input marginTop="30" size="28" placeholder="请填写联系人姓名" v-model="pageData.form.supplyName" />
<fui-input marginTop="30" size="28" placeholder="请填写联系电话" v-model="pageData.form.phone" />
<fui-input marginTop="30" size="28" placeholder="请填写价格" v-model="pageData.form.supplyPrice">
<fui-input
type="number"
marginTop="30"
size="28"
placeholder="请填写价格"
v-model="pageData.form.supplyPrice"
>
<view class="flex">
<view class="mr-3" style="color: #ccc">|</view>
<view></view>
......
<script setup lang="ts">
import { reactive, toRefs } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { useUserStore } from '@/store/modules/user'
import { useGlobSetting } from '/@/hooks/setting'
import * as ChanxiaoAPI from '@/api/model/chanxiao'
import * as UserInfoAPI from '@/api/model/userInfo'
import { areaTree, getTextByCode, getCodeByText } from '@/utils/areaData'
import { useDictStore } from '@/store/modules/dict'
const dictStore = useDictStore()
const userStore = useUserStore()
const globSetting = useGlobSetting()
onLoad((option) => {
uni.setNavigationBarTitle({
title: '发布采购需求',
import { reactive, toRefs } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { useUserStore } from '@/store/modules/user'
import { useGlobSetting } from '/@/hooks/setting'
import * as ChanxiaoAPI from '@/api/model/chanxiao'
import * as UserInfoAPI from '@/api/model/userInfo'
import { areaTree, getTextByCode, getCodeByText } from '@/utils/areaData'
import { useDictStore } from '@/store/modules/dict'
const dictStore = useDictStore()
const userStore = useUserStore()
const globSetting = useGlobSetting()
onLoad((option) => {
uni.setNavigationBarTitle({
title: '发布采购需求',
})
// 获取数据详情
if (option.id) {
getDetails(option.id)
} else {
// 获取当前位置
getCurrentAddressInfo()
}
})
// 获取数据详情
if (option.id) {
getDetails(option.id)
} else {
// 获取当前位置
getCurrentAddressInfo()
}
})
onShow(() => {
// 数据字典赋值
initDict()
})
const pageData = reactive({
title: '发布采购需求',
show: {
time: false,
classify: false,
address: false,
},
options: {
address: [],
classify: [],
},
form: {
id: '',
title: '',
count: '',
unit: '',
deadLine: '',
priceStart: '',
priceEnd: '',
address: '',
province: '',
city: '',
country: '',
classify: '',
classifyText: '',
inputTextArea: '',
image: null,
imageObj: null,
},
rules: [
{
name: 'title',
rule: ['required'],
msg: ['请输入标题'],
},
{
name: 'count',
rule: ['required'],
msg: ['请输入数量'],
},
{
name: 'unit',
rule: ['required'],
msg: ['请输入单位'],
},
{
name: 'deadLine',
rule: ['required'],
msg: ['请选择截至时间'],
},
{
name: 'priceStart',
rule: ['required'],
msg: ['请输入最低价'],
},
{
name: 'priceEnd',
rule: ['required'],
msg: ['请输入最高价'],
},
{
name: 'address',
rule: ['required'],
msg: ['请选择省/市/区县'],
onShow(() => {
// 数据字典赋值
initDict()
})
const pageData = reactive({
title: '发布采购需求',
show: {
time: false,
classify: false,
address: false,
},
{
name: 'classify',
rule: ['required'],
msg: ['请选择分类'],
options: {
address: [],
classify: [],
},
{
name: 'image',
rule: ['required'],
msg: ['请上传示例图片'],
form: {
id: '',
title: '',
count: '',
unit: '',
deadLine: '',
priceStart: '',
priceEnd: '',
address: '',
province: '',
city: '',
country: '',
classify: '',
classifyText: '',
inputTextArea: '',
image: null,
imageObj: null,
},
],
})
rules: [
{
name: 'title',
rule: ['required'],
msg: ['请输入标题'],
},
{
name: 'count',
rule: ['required'],
msg: ['请输入数量'],
},
{
name: 'unit',
rule: ['required'],
msg: ['请输入单位'],
},
{
name: 'deadLine',
rule: ['required'],
msg: ['请选择截至时间'],
},
{
name: 'priceStart',
rule: ['required'],
msg: ['请输入最低价'],
},
{
name: 'priceEnd',
rule: ['required'],
msg: ['请输入最高价'],
},
{
name: 'address',
rule: ['required'],
msg: ['请选择省/市/区县'],
},
{
name: 'classify',
rule: ['required'],
msg: ['请选择分类'],
},
{
name: 'image',
rule: ['required'],
msg: ['请上传示例图片'],
},
],
})
const { show, options, form } = toRefs(pageData)
const { show, options, form } = toRefs(pageData)
function initDict() {
pageData.options.classify = dictStore.getDictList['classify'].map((item) => {
return {
value: item.value,
text: item.text,
}
})
pageData.options.address = areaTree
}
function getCurrentAddressInfo() {
if (!uni.getStorageSync('location')) return
const { lon, lat } = uni.getStorageSync('location')
UserInfoAPI.location({
lon,
lat,
}).then((res) => {
pageData.form.province = res.province
pageData.form.city = res.city
pageData.form.country = res.country
pageData.form.address = `${res.province}/${res.city}/${res.country}`
})
}
function initDict() {
pageData.options.classify = dictStore.getDictList['classify'].map((item) => {
function getDetails(id) {
ChanxiaoAPI.purchaseSellDetails({ id }).then((res) => {
pageData.form = res
pageData.form.address = `${getTextByCode(res.province)}/${getTextByCode(res.city)}/${getTextByCode(res.country)}`
pageData.form.classifyText = pageData.options.classify.find((item) => item.value == res.classify)?.text
pageData.form.imageObj = pageData.form.image && parseUrlInfo(pageData.form.image)
})
}
function parseUrlInfo(url) {
// 从URL中提取文件名
const pathParts = url.split('/')
const fileName = pathParts[pathParts.length - 1]
// 提取扩展名
const fileParts = fileName.split('.')
const extname = fileParts[fileParts.length - 1]
// 返回格式化的对象
return {
value: item.value,
text: item.text,
name: fileName,
extname: extname,
url: url,
}
})
pageData.options.address = areaTree
}
function getCurrentAddressInfo() {
if (!uni.getStorageSync('location')) return
const { lon, lat } = uni.getStorageSync('location')
UserInfoAPI.location({
lon,
lat,
}).then((res) => {
pageData.form.province = res.province
pageData.form.city = res.city
pageData.form.country = res.country
pageData.form.address = `${res.province}/${res.city}/${res.country}`
})
}
function getDetails(id) {
ChanxiaoAPI.purchaseSellDetails({ id }).then((res) => {
pageData.form = res
pageData.form.address = `${getTextByCode(res.province)}/${getTextByCode(res.city)}/${getTextByCode(res.country)}`
pageData.form.classifyText = pageData.options.classify.find((item) => item.value == res.classify)?.text
pageData.form.imageObj = pageData.form.image && parseUrlInfo(pageData.form.image)
})
}
function parseUrlInfo(url) {
// 从URL中提取文件名
const pathParts = url.split('/')
const fileName = pathParts[pathParts.length - 1]
// 提取扩展名
const fileParts = fileName.split('.')
const extname = fileParts[fileParts.length - 1]
// 返回格式化的对象
return {
name: fileName,
extname: extname,
url: url,
}
}
function handleChangeTime(e) {
pageData.form.deadLine = e.result
pageData.show.time = false
}
function handleChangeClassify(e) {
pageData.form.classify = e.value
pageData.form.classifyText = e.text
pageData.show.classify = false
}
function handleChangeAddress(e) {
pageData.form.address = e.text.join('/')
pageData.show.address = false
}
const toastRef = ref()
const uploadRef = ref()
// 文件上传
function handleUpload(file) {
uni.uploadFile({
url: globSetting.apiUrl + globSetting.urlPrefix + '/sys/common/upload', // 直接使用上传接口URL
filePath: file.tempFiles[0].path,
name: 'file',
formData: {
biz: 'temp',
},
header: {
'X-Access-Token': userStore.getToken,
},
success: (res) => {
if (res.statusCode === 200) {
const data = JSON.parse(res.data)
if (data.code === 200 || data.code === 0) {
toastRef.value.show({
type: 'success',
text: '上传成功',
})
pageData.form.image = data.message // 保存返回的图片信息
function handleChangeTime(e) {
pageData.form.deadLine = e.result
pageData.show.time = false
}
function handleChangeClassify(e) {
pageData.form.classify = e.value
pageData.form.classifyText = e.text
pageData.show.classify = false
}
function handleChangeAddress(e) {
pageData.form.address = e.text.join('/')
pageData.show.address = false
}
const toastRef = ref()
const uploadRef = ref()
// 文件上传
function handleUpload(file) {
uni.uploadFile({
url: globSetting.apiUrl + globSetting.urlPrefix + '/sys/common/upload', // 直接使用上传接口URL
filePath: file.tempFiles[0].path,
name: 'file',
formData: {
biz: 'temp',
},
header: {
'X-Access-Token': userStore.getToken,
},
success: (res) => {
if (res.statusCode === 200) {
const data = JSON.parse(res.data)
if (data.code === 200 || data.code === 0) {
toastRef.value.show({
type: 'success',
text: '上传成功',
})
pageData.form.image = data.message // 保存返回的图片信息
}
}
}
},
fail: () => {
toastRef.value.show({
type: 'error',
text: '上传失败',
})
uploadRef.value.clearFiles()
pageData.form.image = null
},
})
}
// 文件删除
function handleDelete() {
uploadRef.value.clearFiles()
pageData.form.image = null
}
const formRef = ref()
function submit() {
formRef.value.validator(pageData.form, pageData.rules, true).then((res) => {
if (res.isPassed) {
changeAddressValue(pageData.form)
ChanxiaoAPI.purchaseSellAdd(pageData.form).then(() => {
},
fail: () => {
toastRef.value.show({
type: 'success',
text: '需求发布成功',
type: 'error',
text: '上传失败',
})
uni.switchTab({
url: '/pages/chanxiao/chanxiao',
uploadRef.value.clearFiles()
pageData.form.image = null
},
})
}
// 文件删除
function handleDelete() {
uploadRef.value.clearFiles()
pageData.form.image = null
}
const formRef = ref()
function submit() {
formRef.value.validator(pageData.form, pageData.rules, true).then((res) => {
if (res.isPassed) {
changeAddressValue(pageData.form)
ChanxiaoAPI.purchaseSellAdd(pageData.form).then(() => {
toastRef.value.show({
type: 'success',
text: '需求发布成功',
})
uni.switchTab({
url: '/pages/chanxiao/chanxiao',
})
})
})
}
})
}
/**
* 处理地区值
* @param formData 表单数据
*/
const changeAddressValue = (formData) => {
const addressValue = formData.address.split('/')
if (addressValue.length === 3) {
formData.province = getCodeByText(addressValue[0])
formData.city = getCodeByText(addressValue[1])
formData.country = getCodeByText(addressValue[2])
}
})
}
/**
* 处理地区值
* @param formData 表单数据
*/
const changeAddressValue = (formData) => {
const addressValue = formData.address.split('/')
if (addressValue.length === 3) {
formData.province = getCodeByText(addressValue[0])
formData.city = getCodeByText(addressValue[1])
formData.country = getCodeByText(addressValue[2])
}
}
</script>
<template>
......@@ -250,42 +250,76 @@ const changeAddressValue = (formData) => {
<view class="formBox">
<fui-form ref="formRef" label-weight="auto" top="60">
<view class="mt20">
<fui-input required label="采购标题" placeholder="请输入采购标题" v-model="form.title" labelSize="28"
label-width="180"></fui-input>
<fui-input label="说明" placeholder="请输入规格说明" v-model="form.inputTextArea" labelSize="28"
label-width="180"></fui-input>
<fui-input
required
label="采购标题"
placeholder="请输入采购标题"
v-model="form.title"
labelSize="28"
label-width="180"
></fui-input>
<fui-input
label="说明"
placeholder="请输入规格说明"
v-model="form.inputTextArea"
labelSize="28"
label-width="180"
></fui-input>
</view>
<view class="mt20">
<!-- 价格区间 -->
<view class="form-section" style="padding: 0 10rpx;">
<view class="form-section" style="padding: 0 10rpx">
<view class="form-item required flex align-center">
<text class="label">价格区间</text>
<view class="price-range">
<input type="number" class="price-input" v-model="form.priceStart" placeholder="最低价"
:min="0" />
<input
type="number"
class="price-input"
v-model="form.priceStart"
placeholder="最低价"
:min="0"
/>
<text class="price-separator">-</text>
<input type="number" class="price-input" v-model="form.priceEnd" placeholder="最高价"
:min="0" />
<input
type="number"
class="price-input"
v-model="form.priceEnd"
placeholder="最高价"
:min="0"
/>
</view>
</view>
</view>
<fui-input type="number" required label="数量" placeholder="请输入数量" v-model="form.count" labelSize="28"
label-width="180"></fui-input>
<fui-input required label="单位" placeholder="请输入计量单位" v-model="form.unit" labelSize="28"
label-width="180"></fui-input>
<fui-input
type="number"
required
label="数量"
placeholder="请输入数量"
v-model="form.count"
labelSize="28"
label-width="180"
></fui-input>
<fui-input
required
label="单位"
placeholder="请输入计量单位"
v-model="form.unit"
labelSize="28"
label-width="180"
></fui-input>
</view>
<view class="mt20">
<view class="form-item required flex align-center" style="padding: 20rpx 10rpx;">
<view class="form-item required flex align-center" style="padding: 20rpx 10rpx">
<text class="label">省/市/区县</text>
<view class="select-input" @click="show.address = true">
<text class="time-text" :class="{ placeholder: !form.address }">
<view class="time-input" @click="show.address = true">
<text class="select-text" :class="{ placeholder: !form.address }">
{{ form.address || '请选择省/市/区县' }}
</text>
</view>
</view>
<!-- 截至时间 -->
<view class="form-section" style="padding: 0 10rpx;">
<view class="form-section" style="padding: 0 10rpx">
<view class="form-item required flex align-center">
<text class="label">截至时间</text>
<view class="time-input" @click="show.time = true">
......@@ -295,7 +329,7 @@ const changeAddressValue = (formData) => {
</view>
</view>
</view>
<view class="form-section" style="padding: 0 10rpx;">
<view class="form-section" style="padding: 0 10rpx">
<view class="form-item required flex align-center">
<text class="label">分类</text>
<view class="time-input" @click="show.classify = true">
......@@ -309,275 +343,314 @@ const changeAddressValue = (formData) => {
<view class="bg-white mt20" style="padding: 0.875rem 1rem">
<view class="mb-1 flex justify-start"> 示例图片 </view>
<uni-file-picker :value="form.imageObj" ref="uploadRef" limit="1" :auto-upload="false"
@select="handleUpload" @delete="handleDelete"></uni-file-picker>
<uni-file-picker
:value="form.imageObj"
ref="uploadRef"
limit="1"
:auto-upload="false"
@select="handleUpload"
@delete="handleDelete"
></uni-file-picker>
</view>
<view class="fui-btn__box" v-if="!form.id" style="margin-top: 30rpx;">
<view class="fui-btn__box" v-if="!form.id" style="margin-top: 30rpx">
<fui-button text="发布需求" bold radius="96rpx" @click="submit"></fui-button>
</view>
</fui-form>
<fui-date-picker :show="show.time" type="3" @change="handleChangeTime"
@cancel="show.time = false"></fui-date-picker>
<fui-picker :show="show.classify" :layer="1" :linkage="true" :options="options.classify"
@change="handleChangeClassify" @cancel="show.classify = false"></fui-picker>
<fui-picker :show="show.address" :options="options.address" :linkage="true" :layer="3"
@change="handleChangeAddress" @cancel="show.address = false"></fui-picker>
<fui-date-picker
:show="show.time"
type="3"
@change="handleChangeTime"
@cancel="show.time = false"
></fui-date-picker>
<fui-picker
:show="show.classify"
:layer="1"
:linkage="true"
:options="options.classify"
@change="handleChangeClassify"
@cancel="show.classify = false"
></fui-picker>
<fui-picker
:show="show.address"
:options="options.address"
:linkage="true"
:layer="3"
@change="handleChangeAddress"
@cancel="show.address = false"
></fui-picker>
<fui-toast ref="toastRef"></fui-toast>
</view>
</view>
<fui-date-picker :show="show.time" type="3" @change="handleChangeTime" @cancel="show.time = false"
minDate="2025-01-01"></fui-date-picker>
<fui-picker :show="show.classify" :layer="1" :linkage="true" :options="options.classify"
@change="handleChangeClassify" @cancel="show.classify = false"></fui-picker>
<fui-picker :show="show.address" :options="options.address" :linkage="true" :layer="3" @change="handleChangeAddress"
@cancel="show.address = false"></fui-picker>
<fui-date-picker
:show="show.time"
type="3"
@change="handleChangeTime"
@cancel="show.time = false"
minDate="2025-01-01"
></fui-date-picker>
<fui-picker
:show="show.classify"
:layer="1"
:linkage="true"
:options="options.classify"
@change="handleChangeClassify"
@cancel="show.classify = false"
></fui-picker>
<fui-picker
:show="show.address"
:options="options.address"
:linkage="true"
:layer="3"
@change="handleChangeAddress"
@cancel="show.address = false"
></fui-picker>
<fui-toast ref="toastRef"></fui-toast>
</template>
<style lang="scss" scoped>
body {
background-color: #E6F5E8;
}
.page {
background-color: #E6F5E8;
width: 750rpx;
overflow-x: hidden;
.mt20 {
margin-top: 30rpx;
background: #FFF;
padding: 20rpx;
border-radius: 10rpx;
body {
background-color: #e6f5e8;
}
.formBox {
width: 690rpx;
margin: 30rpx auto;
}
.page {
background-color: #e6f5e8;
width: 750rpx;
overflow-x: hidden;
.purchase-form {
background: transparent;
}
.mt20 {
margin-top: 30rpx;
background: #fff;
padding: 20rpx;
border-radius: 10rpx;
}
.form-section {
// background: #ffffff;
// border-radius: 12rpx;
// margin-bottom: 20rpx;
.formBox {
width: 690rpx;
margin: 30rpx auto;
}
// box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
border-bottom: 1rpx solid #f5f5f5;
}
.purchase-form {
background: transparent;
}
.form-item {
padding: 30rpx 0;
border-bottom: 1rpx solid #f5f5f5;
.form-section {
// background: #ffffff;
// border-radius: 12rpx;
// margin-bottom: 20rpx;
&:last-child {
border-bottom: none;
// box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
border-bottom: 1rpx solid #f5f5f5;
}
&.required .label::before {
content: '*';
color: #ff4d4f;
margin-right: 8rpx;
.form-item {
padding: 30rpx 0;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
&.required .label::before {
content: '*';
color: #ff4d4f;
margin-right: 8rpx;
}
// 添加点击区域样式
.select-input {
position: relative;
}
}
// 添加点击区域样式
.select-input {
position: relative;
.form-row {
display: flex;
justify-content: space-between;
}
}
.form-row {
display: flex;
justify-content: space-between;
}
.half-width {
width: 48%;
}
.half-width {
width: 48%;
}
.align-center {
align-items: center;
}
.align-center {
align-items: center;
}
.label {
display: block;
font-size: 28rpx;
color: #333333;
font-weight: 500;
width: 180rpx;
// margin-right: 20rpx;
}
.label {
display: block;
font-size: 28rpx;
color: #333333;
font-weight: 500;
width: 180rpx;
// margin-right: 20rpx;
}
.input {
width: 100%;
height: 80rpx;
background: #f8f9fa;
border-radius: 8rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333333;
.input {
width: 100%;
height: 80rpx;
background: #f8f9fa;
border-radius: 8rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333333;
&::placeholder {
color: #999999;
}
}
&::placeholder {
color: #999999;
.price-range {
display: flex;
align-items: center;
// justify-content: space-between;
}
}
.price-range {
display: flex;
align-items: center;
// justify-content: space-between;
}
.price-input {
width: 15%;
// height: 80rpx;
// background: #f8f9fa;
// border-radius: 8rpx;
padding: 0 10rpx;
font-size: 28rpx;
text-align: center;
}
.price-input {
width: 15%;
// height: 80rpx;
// background: #f8f9fa;
// border-radius: 8rpx;
padding: 0 10rpx;
font-size: 28rpx;
text-align: center;
}
.price-separator {
color: #666666;
font-size: 28rpx;
margin: 0 10rpx;
}
.price-separator {
color: #666666;
font-size: 28rpx;
margin: 0 10rpx;
}
.select-input {
flex: 1;
border-radius: 8rpx;
padding: 0 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
}
.select-input {
flex: 1;
border-radius: 8rpx;
padding: 0 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
}
.select-text {
font-size: 28rpx;
color: #333333;
padding: 0 20rpx;
&.placeholder {
color: #999999;
}
}
.select-text {
font-size: 28rpx;
color: #333333;
padding: 0 20rpx;
&.placeholder {
.select-arrow {
color: #999999;
font-size: 24rpx;
line-height: 1;
}
}
.select-arrow {
color: #999999;
font-size: 24rpx;
line-height: 1;
}
.time-range {
display: flex;
align-items: center;
justify-content: space-between;
}
.time-range {
display: flex;
align-items: center;
justify-content: space-between;
}
.time-input {
width: 45%;
// height: 80rpx;
// background: #f8f9fa;
border-radius: 8rpx;
display: flex;
align-items: center;
}
.time-input {
width: 45%;
// height: 80rpx;
// background: #f8f9fa;
border-radius: 8rpx;
display: flex;
align-items: center;
}
.time-text {
font-size: 28rpx;
color: #333333;
padding: 0 20rpx;
.time-text {
font-size: 28rpx;
color: #333333;
padding: 0 20rpx;
&.placeholder {
color: #999999;
}
}
.time-separator {
color: #666666;
font-size: 28rpx;
margin: 0 10rpx;
}
.upload-area {
margin-top: 10rpx;
}
.custom-uploader {
:deep(.uni-file-picker__container) {
border: 2rpx dashed #d9d9d9;
border-radius: 8rpx;
background: #f8f9fa;
}
}
&.placeholder {
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 200rpx;
color: #999999;
}
}
.time-separator {
color: #666666;
font-size: 28rpx;
margin: 0 10rpx;
}
.upload-icon {
font-size: 48rpx;
margin-bottom: 10rpx;
}
.upload-area {
margin-top: 10rpx;
}
.upload-text {
font-size: 24rpx;
}
.custom-uploader {
:deep(.uni-file-picker__container) {
border: 2rpx dashed #d9d9d9;
border-radius: 8rpx;
background: #f8f9fa;
.submit-section {
background: transparent;
padding: 40rpx 0;
}
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 200rpx;
color: #999999;
.submit-btn {
width: 100%;
height: 88rpx;
background: #5db66f;
border-radius: 44rpx;
color: #ffffff;
font-size: 32rpx;
font-weight: 500;
border: none;
&:active {
background: #4ca85c;
opacity: 0.9;
}
}
}
.upload-icon {
font-size: 48rpx;
margin-bottom: 10rpx;
::v-deep .uni-input-placeholder {
font-size: 28rpx !important;
color: #999999 !important;
}
.upload-text {
font-size: 24rpx;
:deep(.fui-button) {
width: 690rpx;
border-color: #5db66f !important;
background: #5db66f !important;
}
.submit-section {
// 移除fui-form的默认样式
:deep(.fui-form) {
background: transparent;
padding: 40rpx 0;
}
.submit-btn {
width: 100%;
height: 88rpx;
background: #5DB66F;
border-radius: 44rpx;
color: #ffffff;
font-size: 32rpx;
font-weight: 500;
:deep(.fui-form__item) {
background: transparent;
border: none;
&:active {
background: #4ca85c;
opacity: 0.9;
}
margin-bottom: 0;
padding: 0;
}
}
::v-deep .uni-input-placeholder {
font-size: 28rpx !important;
color: #999999 !important;
}
:deep(.fui-button) {
width: 690rpx;
border-color: #5DB66F !important;
background: #5DB66F !important;
}
// 移除fui-form的默认样式
:deep(.fui-form) {
background: transparent;
}
:deep(.fui-form__item) {
background: transparent;
border: none;
margin-bottom: 0;
padding: 0;
}
</style>
......@@ -3,6 +3,7 @@
import { onPullDownRefresh, onLoad } from '@dcloudio/uni-app'
import * as NongzhiAPI from '@/api/model/nongzhi'
import Navigate from '@/utils/page/navigate'
import { url } from 'inspector'
// 下拉刷新
onPullDownRefresh(() => {
......@@ -47,6 +48,7 @@
title: '季节性用工',
description: '三农区域灵活用工服务',
actionText: '去发布',
url: '/pages/nongjifuwu/farm-form',
},
{
id: 2,
......@@ -54,14 +56,15 @@
title: '农机手调度',
description: '专业人员作业安排',
actionText: '去预约',
url: '/pages/nongjifuwu/nongjifuwu',
},
{
id: 3,
image: '/static/images/codefun/06319419d17b7630c1d5bc415bcd26ef.png',
title: '作业质量评价',
description: '农机定位精度≤50米',
actionText: '去评价',
},
// {
// id: 3,
// image: '/static/images/codefun/06319419d17b7630c1d5bc415bcd26ef.png',
// title: '作业质量评价',
// description: '农机定位精度≤50米',
// actionText: '去评价',
// },
],
// 助农金融产品
......@@ -347,7 +350,12 @@
</view>
<view class="codefun-flex-col group_8">
<view class="codefun-flex-col section_4 flex gap-4">
<view v-for="service in pageData.flexibleEmploymentServices" :key="service.id">
<navigator
v-for="service in pageData.flexibleEmploymentServices"
:key="service.id"
:url="service.url"
hover-class="none"
>
<view class="codefun-flex-row codefun-justify-between codefun-items-center">
<view class="codefun-flex-row">
<image class="image_8" :src="service.image" />
......@@ -367,7 +375,7 @@
<text class="font_8" :class="`text_${9 + service.id}`">{{ service.actionText }}</text>
</view>
</view>
</view>
</navigator>
</view>
<view class="codefun-flex-col codefun-mt-24">
<view class="codefun-flex-row codefun-justify-between codefun-items-center group_11">
......@@ -503,7 +511,7 @@
class="codefun-flex-row codefun-justify-between codefun-items-center codefun-self-stretch group_14"
>
<text class="font_5">一站式解决农机问题</text>
<text class="font_6 text_37" @click="onViewAllMachineryCases">全部案例</text>
<!-- <text class="font_6 text_37" @click="onViewAllMachineryCases">全部案例</text> -->
</view>
<view class="codefun-flex-col codefun-self-stretch section_14">
<view class="codefun-flex-row">
......
......@@ -44,8 +44,8 @@
id: '',
name: '',
content: '',
workers: 0,
price: 0,
workers: '',
price: '',
typeText: '',
type: null,
area: '',
......@@ -276,67 +276,122 @@
</script>
<template>
<fui-form ref="formRef" :disabled="form.id ? true : false">
<fui-input required label="名称" placeholder="请输入名称" v-model="form.name"></fui-input>
<fui-input required label="工作内容" borderTop placeholder="请输入工作内容" v-model="form.content"></fui-input>
<fui-input required label="工人数量" borderTop placeholder="请输入工人数量" v-model="form.workers"></fui-input>
<fui-input required label="价钱" borderTop placeholder="请输入价钱" v-model="form.price"></fui-input>
<fui-input
required
label="类型"
placeholder="请选择类型"
v-model="form.typeText"
@click="show.type = true"
></fui-input>
<fui-input
required
label="地区"
placeholder="请选择地区"
v-model="form.areaText"
@click="show.area = true"
></fui-input>
<fui-input label="详细地址" placeholder="请输入详细地址" v-model="form.address"></fui-input>
<fui-input
required
label="紧急程度"
placeholder="请选择紧急程度"
v-model="form.urgentdegreeText"
@click="show.urgentdegree = true"
></fui-input>
<fui-input
required
label="开始时间"
borderTop
placeholder="请选择开始时间"
v-model="form.starttime"
@click="show.time1 = true"
></fui-input>
<fui-input
required
label="结束时间"
borderTop
placeholder="请选择结束时间"
v-model="form.estimatedendtime"
@click="show.time2 = true"
></fui-input>
<view class="bg-white" style="padding: 0.875rem 0.35rem">
<view class="mb-1 flex justify-start">
<text class="pr-1" style="color: #ff2b2b">*</text>
图片
</view>
<uni-file-picker
:value="form.pictureObj"
ref="uploadRef"
limit="1"
:auto-upload="false"
@select="handleUpload"
@delete="handleDelete"
></uni-file-picker>
<view class="page">
<view class="formBox">
<fui-form ref="formRef" label-weight="auto" top="60" :disabled="form.id ? true : false">
<view class="mt20">
<fui-input
required
label="名称"
placeholder="请输入名称"
v-model="form.name"
labelSize="28"
label-width="180"
></fui-input>
<fui-input
required
label="工作内容"
placeholder="请输入工作内容"
v-model="form.content"
labelSize="28"
label-width="180"
></fui-input>
</view>
<view class="mt20">
<fui-input
required
type="number"
:min="0"
label="工人数量"
placeholder="请输入工人数量"
v-model="form.workers"
labelSize="28"
label-width="180"
></fui-input>
<fui-input
required
type="number"
label="价钱"
:min="0"
placeholder="请输入价钱"
v-model="form.price"
labelSize="28"
label-width="180"
></fui-input>
<fui-input
required
label="类型"
placeholder="请选择类型"
v-model="form.typeText"
labelSize="28"
label-width="180"
@click="show.type = true"
></fui-input>
</view>
<view class="mt20">
<fui-input
required
label="地区"
placeholder="请选择地区"
v-model="form.areaText"
labelSize="28"
label-width="180"
@click="show.area = true"
></fui-input>
<fui-input
required
label="详细地址"
placeholder="请输入详细地址"
v-model="form.address"
labelSize="28"
label-width="180"
></fui-input>
<fui-input
required
label="紧急程度"
placeholder="请选择紧急程度"
v-model="form.urgentdegreeText"
labelSize="28"
label-width="180"
@click="show.urgentdegree = true"
></fui-input>
<!-- 时间范围 -->
<view class="form-section" style="padding: 0 30rpx">
<view class="form-item flex align-center">
<text class="label">用工时间</text>
<view class="time-range">
<view class="time-input" @click="show.time1 = true">
<text class="time-text" :class="{ placeholder: !form.starttime }">
{{ form.starttime || '开始时间' }}
</text>
</view>
<text class="time-separator">-</text>
<view class="time-input" @click="show.time2 = true">
<text class="time-text" :class="{ placeholder: !form.estimatedendtime }">
{{ form.estimatedendtime || '结束时间' }}
</text>
</view>
</view>
</view>
</view>
</view>
<view class="bg-white mt20" style="padding: 0.875rem 1rem">
<view class="mb-1 flex justify-start"> 图片 </view>
<uni-file-picker
:value="form.pictureObj"
ref="uploadRef"
limit="1"
:auto-upload="false"
@select="handleUpload"
@delete="handleDelete"
></uni-file-picker>
</view>
<view class="fui-btn__box" v-if="!form.id" style="margin-top: 30rpx">
<fui-button text="发布用工" bold radius="96rpx" @click="submit"></fui-button>
</view>
</fui-form>
</view>
<view class="fui-btn__box bg-white p-4" v-if="!form.id">
<fui-button text="发布用工" bold radius="96rpx" @click="submit"></fui-button>
</view>
</fui-form>
</view>
<fui-date-picker
:show="show.time1"
......@@ -380,8 +435,173 @@
</template>
<style lang="scss" scoped>
:deep(.fui-button) {
border-color: #ff9800 !important;
background: #ff9800 !important;
body {
background-color: #e6f5e8;
}
.page {
background-color: #e6f5e8;
width: 750rpx;
overflow-x: hidden;
.mt20 {
margin-top: 30rpx;
background: #fff;
padding: 20rpx;
border-radius: 10rpx;
}
.formBox {
width: 690rpx;
margin: 30rpx auto;
}
.form-section {
// border-bottom: 1rpx solid #f5f5f5;
}
.form-item {
padding: 30rpx 0;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
&.required .label::before {
content: '*';
color: #ff4d4f;
margin-right: 8rpx;
}
}
.form-row {
display: flex;
justify-content: space-between;
}
.half-width {
width: 48%;
}
.align-center {
align-items: center;
}
.label {
display: block;
font-size: 28rpx;
color: #333333;
font-weight: 500;
width: 180rpx;
}
.input {
width: 100%;
height: 80rpx;
background: #f8f9fa;
border-radius: 8rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333333;
&::placeholder {
color: #999999;
}
}
.time-range {
display: flex;
align-items: center;
justify-content: space-between;
}
.time-input {
width: 45%;
border-radius: 8rpx;
display: flex;
align-items: center;
}
.time-text {
font-size: 28rpx;
color: #333333;
&.placeholder {
color: #999999;
}
}
.time-separator {
color: #666666;
font-size: 28rpx;
margin: 0 10rpx;
}
.upload-area {
margin-top: 10rpx;
}
.custom-uploader {
:deep(.uni-file-picker__container) {
border: 2rpx dashed #d9d9d9;
border-radius: 8rpx;
background: #f8f9fa;
}
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 200rpx;
color: #999999;
}
.upload-icon {
font-size: 48rpx;
margin-bottom: 10rpx;
}
.upload-text {
font-size: 24rpx;
}
.submit-section {
background: transparent;
padding: 40rpx 0;
}
.submit-btn {
width: 100%;
height: 88rpx;
background: #ff9800;
border-radius: 44rpx;
color: #ffffff;
font-size: 32rpx;
font-weight: 500;
border: none;
&:active {
background: #e68900;
opacity: 0.9;
}
}
}
::v-deep .uni-input-placeholder {
font-size: 28rpx !important;
color: #999999 !important;
}
// 移除fui-form的默认样式
:deep(.fui-form) {
background: transparent;
}
:deep(.fui-form__item) {
background: transparent;
border: none;
margin-bottom: 0;
padding: 0;
}
</style>
......@@ -113,23 +113,107 @@
total: 0,
})
// 缓存已处理的区域数据,避免重复计算
const areaCache = new Map()
// 请求重试配置
const requestConfig = {
maxRetries: 2,
retryDelay: 1000,
}
// 带重试机制的API调用
async function fetchWithRetry(apiCall, maxRetries = requestConfig.maxRetries) {
const startTime = Date.now()
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const result = await apiCall()
const endTime = Date.now()
// 记录API性能数据(仅在开发环境)
if (import.meta.env.DEV) {
console.log(`API请求成功,耗时: ${endTime - startTime}ms`)
}
return result
} catch (error) {
console.warn(`API请求失败 (尝试 ${attempt}/${maxRetries}):`, error)
if (attempt === maxRetries) {
const endTime = Date.now()
if (import.meta.env.DEV) {
console.error(`API请求最终失败,总耗时: ${endTime - startTime}ms`)
}
throw error
}
// 指数退避策略
await new Promise((resolve) => setTimeout(resolve, requestConfig.retryDelay * attempt))
}
}
}
function getEmploymentList() {
// 如果正在加载或没有更多数据,直接返回
if (pageData.loading || (pageData.total > 0 && pageData.employmentList.length >= pageData.total)) {
return
}
pageData.loading = true
LinghuoyonggongAPI.employmentList(pageData.search)
.then((res) => {
// 添加请求防抖,避免快速连续请求
if (pageData.requestDebounce) {
clearTimeout(pageData.requestDebounce)
}
pageData.requestDebounce = setTimeout(async () => {
try {
const res = await fetchWithRetry(() => LinghuoyonggongAPI.employmentList(pageData.search))
const { records, total } = res
console.log('records', records)
records.map((item) => {
item.area = item.area.split(',')
item.area = getTextByCode(item.area[0]) + ' ' + getTextByCode(item.area[1])
// 批量处理数据,避免多次DOM操作
const processedRecords = records.map((item) => {
// 缓存区域处理结果
const cacheKey = item.area
if (areaCache.has(cacheKey)) {
item.area = areaCache.get(cacheKey)
} else {
const areaCodes = item.area.split(',')
const areaText = getTextByCode(areaCodes[0]) + ' ' + getTextByCode(areaCodes[1])
areaCache.set(cacheKey, areaText)
item.area = areaText
}
// 计算天数并缓存结果
if (item.starttime && item.estimatedendtime) {
item.daysDiff = getDaysDiff(item.starttime, item.estimatedendtime)
}
return item
})
pageData.employmentList = [...pageData.employmentList, ...records]
// 一次性更新数据,避免多次响应式更新
if (pageData.search.pageNo === 1) {
pageData.employmentList = processedRecords
} else {
// 避免重复数据加载
const existingIds = new Set(pageData.employmentList.map((item) => item.id))
const newRecords = processedRecords.filter((item) => !existingIds.has(item.id))
pageData.employmentList = [...pageData.employmentList, ...newRecords]
}
pageData.total = total
})
.finally(() => {
} catch (error) {
console.error('获取用工列表失败:', error)
// 这里可以添加用户友好的错误提示
// uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' })
} finally {
pageData.loading = false
})
pageData.requestDebounce = null
}
}, 150)
}
// 分类标签点击事件
......@@ -251,7 +335,7 @@
@click="onEmploymentItemClick(item)"
>
<view class="codefun-flex-row">
<image class="image_7" :src="item.picture" />
<image class="image_7" :src="item.picture" lazy-load />
<view class="codefun-flex-col codefun-flex-1 codefun-self-center group_4">
<view class="codefun-flex-row codefun-justify-between codefun-items-center">
<text class="codefun-self-start font">{{ item.name }}</text>
......@@ -269,7 +353,9 @@
<view class="flex codefun-items-center gap-1">
<image class="image_9" src="/src/static/images/time.svg" />
<text class="font_4"
>预计{{ getDaysDiff(item.starttime, item.estimatedendtime) }}</text
>预计{{
item.daysDiff || getDaysDiff(item.starttime, item.estimatedendtime)
}}</text
>
</view>
<view class="flex codefun-items-center gap-1">
......@@ -304,10 +390,11 @@
<!-- <image class="codefun-self-end image_7 image_12 mt-269" :src="pageData.bottomImage" /> -->
</view>
<fui-fab background="#5db66f" position="right" distance="10" bottom="240" width="120" @click="handlePublish">
<fui-fab position="right" distance="10" bottom="240" width="96" @click="handlePublish">
<view class="text-white text-center">
<image src="/src/static/images/chanxiao/notepad.svg" style="width: 40rpx" mode="widthFix"></image>
<view style="font-size: 24rpx">发布用工</view>
<!-- <image src="/src/static/images/chanxiao/notepad.svg" style="width: 40rpx" mode="widthFix"></image> -->
<view class="fab-icon"></view>
<view style="font-size: 24rpx">发布</view>
</view>
</fui-fab>
<register-dialog ref="registerDialogRef"></register-dialog>
......@@ -315,6 +402,9 @@
</template>
<style scoped lang="scss">
body {
background-color: #e6f5e8;
}
.mt-19 {
margin-top: 38rpx;
}
......@@ -331,7 +421,7 @@
margin-top: 538rpx;
}
.page {
padding-bottom: 128rpx;
// padding-bottom: 128rpx;
background-color: #e6f5e8;
mix-blend-mode: NOTTHROUGH;
width: 100%;
......@@ -544,9 +634,14 @@
.image_7 {
width: 96rpx;
height: 96rpx;
border-radius: 50%;
}
.image_12 {
margin-right: 58rpx;
}
}
::v-deep .fui-fab__btn-main {
background: linear-gradient(124.25deg, #a5d63f 0%, #5db66f 100%) !important;
box-shadow: 0px 1px 8px #5db66f;
}
</style>
......@@ -5,6 +5,7 @@
import { useGlobSetting } from '/@/hooks/setting'
import * as nongjifuwu from '@/api/model/nongjifuwu'
import { useDictStore } from '@/store/modules/dict'
import { areaTree } from '@/utils/areaData'
const dictStore = useDictStore()
const userStore = useUserStore()
......@@ -34,6 +35,10 @@
show: {
time1: false,
time2: false,
address: false,
},
options: {
address: [],
},
form: {
id: '',
......@@ -87,10 +92,11 @@
],
})
const { show, form } = toRefs(pageData)
const { show, options, form } = toRefs(pageData)
function initDict() {
console.log(dictStore.getDictList)
pageData.options.address = areaTree
}
function getDetails(id) {
......@@ -131,6 +137,11 @@
pageData.form.endTime = e.result
pageData.show.time2 = false
}
function handleChangeAddress(e) {
pageData.form.scope = e.text.join('/')
pageData.show.address = false
}
const toastRef = ref()
const uploadRef = ref()
// 文件上传
......@@ -191,64 +202,336 @@
</script>
<template>
<fui-form ref="formRef" :disabled="form.id ? true : false">
<fui-input required label="服务名称" placeholder="请输入服务名称" v-model="form.name"></fui-input>
<fui-input required label="服务范围" placeholder="请输入服务范围" v-model="form.scope"></fui-input>
<fui-input required label="详细地址" placeholder="请输入详细地址" v-model="form.address"></fui-input>
<fui-input required label="联系方式" borderTop placeholder="请输入联系方式" v-model="form.phone"></fui-input>
<fui-input required label="作业需求" borderTop placeholder="请输入作业需求" v-model="form.demand"></fui-input>
<fui-input
required
label="作业开始时间"
borderTop
placeholder="请选择开始时间"
v-model="form.startTime"
@click="show.time1 = true"
></fui-input>
<fui-input
required
label="作业结束时间"
borderTop
placeholder="请选择结束时间"
v-model="form.endTime"
@click="show.time2 = true"
></fui-input>
<view class="bg-white" style="padding: 0.875rem 0.35rem">
<view class="mb-1 flex justify-start"> 图片 </view>
<uni-file-picker
:value="form.pictureObj"
ref="uploadRef"
limit="1"
:auto-upload="false"
@select="handleUpload"
@delete="handleDelete"
></uni-file-picker>
</view>
<view class="fui-btn__box bg-white p-4" v-if="!form.id">
<fui-button text="发布作业" bold radius="96rpx" @click="submit"></fui-button>
<view class="page">
<view class="formBox">
<fui-form ref="formRef" label-weight="auto" top="60" :disabled="form.id ? true : false">
<view class="mt20">
<fui-input
required
label="服务名称"
placeholder="请输入服务名称"
v-model="form.name"
labelSize="28"
label-width="180"
></fui-input>
<view class="form-item required flex align-center" style="padding: 20rpx 10rpx">
<text class="label">服务范围</text>
<view class="time-input" @click="show.address = true">
<text class="select-text" :class="{ placeholder: !form.scope }">
{{ form.scope || '请选择省/市/区县' }}
</text>
</view>
</view>
<view class="form-item required flex align-center" style="padding: 20rpx 10rpx">
<text class="label">所在地区</text>
<view class="time-input" @click="show.address = true">
<text class="select-text" :class="{ placeholder: !form.scope }">
{{ form.scope || '请选择省/市/区县' }}
</text>
</view>
</view>
<fui-input
required
label="详细地址"
placeholder="请输入详细地址"
v-model="form.address"
labelSize="28"
label-width="180"
></fui-input>
<fui-input
required
label="联系方式"
placeholder="请输入联系方式"
v-model="form.phone"
labelSize="28"
label-width="180"
></fui-input>
</view>
<view class="mt20">
<fui-input
required
label="作业需求"
placeholder="请输入作业需求"
v-model="form.demand"
labelSize="28"
label-width="180"
></fui-input>
<!-- 作业时间 -->
<view class="form-section" style="padding: 0 10rpx">
<view class="form-item flex align-center">
<text class="label">作业时间</text>
<view class="time-range">
<view class="time-input" @click="show.time1 = true">
<text class="time-text" :class="{ placeholder: !form.startTime }">
{{ form.startTime || '作业开始时间' }}
</text>
</view>
<text class="time-separator">-</text>
<view class="time-input" @click="show.time2 = true">
<text class="time-text" :class="{ placeholder: !form.endTime }">
{{ form.endTime || '作业结束时间' }}
</text>
</view>
</view>
</view>
</view>
</view>
<view class="bg-white mt20" style="padding: 0.875rem 1rem">
<view class="mb-1 flex justify-start"> 图片 </view>
<uni-file-picker
:value="form.pictureObj"
ref="uploadRef"
limit="1"
:auto-upload="false"
@select="handleUpload"
@delete="handleDelete"
></uni-file-picker>
</view>
<view class="fui-btn__box" v-if="!form.id" style="margin-top: 30rpx">
<fui-button text="发布作业" bold radius="96rpx" @click="submit"></fui-button>
</view>
</fui-form>
<fui-date-picker
:show="show.time1"
type="3"
@change="handleChangeTime1"
@cancel="show.time1 = false"
minDate="2025-01-01"
></fui-date-picker>
<fui-date-picker
:show="show.time2"
type="3"
@change="handleChangeTime2"
@cancel="show.time2 = false"
minDate="2025-01-01"
></fui-date-picker>
<fui-toast ref="toastRef"></fui-toast>
<fui-loading isFixed v-if="pageData.loading" backgroundColor="rgba(0, 0, 0, 0.4)"></fui-loading>
<fui-picker
:show="show.address"
:options="options.address"
:linkage="true"
:layer="3"
@change="handleChangeAddress"
@cancel="show.address = false"
></fui-picker>
</view>
</fui-form>
<fui-date-picker
:show="show.time1"
type="3"
@change="handleChangeTime1"
@cancel="show.time1 = false"
></fui-date-picker>
<fui-date-picker
:show="show.time2"
type="3"
@change="handleChangeTime2"
@cancel="show.time2 = false"
></fui-date-picker>
<fui-toast ref="toastRef"></fui-toast>
<fui-loading isFixed v-if="pageData.loading" backgroundColor="rgba(0, 0, 0, 0.4)"></fui-loading>
</view>
</template>
<style lang="scss" scoped>
body {
background-color: #e6f5e8;
min-height: 100vh;
}
.page {
background-color: #e6f5e8;
width: 750rpx;
overflow-x: hidden;
.mt20 {
margin-top: 30rpx;
background: #fff;
padding: 20rpx;
border-radius: 10rpx;
}
.formBox {
width: 690rpx;
margin: 30rpx auto;
}
.form-section {
// border-bottom: 1rpx solid #f5f5f5;
}
.form-item {
padding: 30rpx 0;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
&.required .label::before {
content: '*';
color: #ff4d4f;
margin-right: 8rpx;
}
}
.form-row {
display: flex;
justify-content: space-between;
}
.half-width {
width: 48%;
}
.align-center {
align-items: center;
}
.label {
display: block;
font-size: 28rpx;
color: #333333;
font-weight: 500;
width: 180rpx;
}
.input {
width: 100%;
height: 80rpx;
background: #f8f9fa;
border-radius: 8rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333333;
&::placeholder {
color: #999999;
}
}
.time-range {
display: flex;
align-items: center;
justify-content: space-between;
}
.time-input {
width: 45%;
border-radius: 8rpx;
display: flex;
align-items: center;
}
.time-text {
font-size: 28rpx;
color: #333333;
&.placeholder {
color: #999999;
}
}
.time-separator {
color: #666666;
font-size: 28rpx;
margin: 0 10rpx;
}
.upload-area {
margin-top: 10rpx;
}
.custom-uploader {
:deep(.uni-file-picker__container) {
border: 2rpx dashed #d9d9d9;
border-radius: 8rpx;
background: #f8f9fa;
}
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 200rpx;
color: #999999;
}
.upload-icon {
font-size: 48rpx;
margin-bottom: 10rpx;
}
.upload-text {
font-size: 24rpx;
}
.submit-section {
background: transparent;
padding: 40rpx 0;
}
.submit-btn {
width: 100%;
height: 88rpx;
background: #5db66f;
border-radius: 44rpx;
color: #ffffff;
font-size: 32rpx;
font-weight: 500;
border: none;
&:active {
background: #4ca85c;
opacity: 0.9;
}
}
}
::v-deep .uni-input-placeholder {
font-size: 28rpx !important;
color: #999999 !important;
}
:deep(.fui-button) {
border-color: #ff9800 !important;
background: #ff9800 !important;
border-color: #5db66f !important;
background: #5db66f !important;
}
// 移除fui-form的默认样式
:deep(.fui-form) {
background: transparent;
}
:deep(.fui-form__item) {
background: transparent;
border: none;
margin-bottom: 0;
padding: 0;
}
.time-input {
width: 45%;
border-radius: 8rpx;
display: flex;
align-items: center;
}
.time-text {
font-size: 28rpx;
color: #333333;
padding: 0 20rpx;
&.placeholder {
color: #999999;
}
}
.select-input {
flex: 1;
border-radius: 8rpx;
padding: 0 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
}
.select-text {
font-size: 28rpx;
color: #333333;
padding: 0 20rpx;
&.placeholder {
color: #999999;
}
}
</style>
......@@ -5,7 +5,7 @@
import { useGlobSetting } from '/@/hooks/setting'
import * as nongjifuwu from '@/api/model/nongjifuwu'
import { useDictStore } from '@/store/modules/dict'
import { areaTree } from '@/utils/areaData'
const dictStore = useDictStore()
const userStore = useUserStore()
const globSetting = useGlobSetting()
......@@ -31,11 +31,20 @@
const pageData = reactive({
title: '农机表单',
loading: false,
show: {
time: false,
classify: false,
address: false,
},
options: {
address: [],
classify: [],
},
form: {
id: '',
name: '',
phone: '',
price: 0,
price: '',
scope: '',
type: '',
picture: '',
......@@ -70,10 +79,10 @@
],
})
const { form } = toRefs(pageData)
const { show, options, form } = toRefs(pageData)
function initDict() {
console.log(dictStore.getDictList)
pageData.options.address = areaTree
}
function getDetails(id) {
......@@ -164,47 +173,304 @@
}
})
}
function handleChangeAddress(e) {
pageData.form.scope = e.text.join('/')
pageData.show.address = false
}
</script>
<template>
<fui-form ref="formRef" :disabled="form.id ? true : false">
<fui-input required label="农机名称" placeholder="请输入农机名称" v-model="form.name"></fui-input>
<fui-input required label="联系方式" placeholder="请输入联系方式" v-model="form.phone"></fui-input>
<fui-input required label="服务范围" placeholder="请输入服务范围" v-model="form.scope"></fui-input>
<fui-input
required
label="价格(元/亩)"
borderTop
placeholder="请输入价格"
number
v-model="form.price"
></fui-input>
<view class="bg-white" style="padding: 0.875rem 0.35rem">
<view class="mb-1 flex justify-start">
<text class="pr-1" style="color: #ff2b2b">*</text>
图片
</view>
<uni-file-picker
:value="form.pictureObj"
:max-size="1024"
ref="uploadRef"
limit="1"
:auto-upload="false"
@select="handleUpload"
@delete="handleDelete"
></uni-file-picker>
</view>
<view class="fui-btn__box bg-white p-4" v-if="!form.id">
<fui-button text="发布作业" bold radius="96rpx" @click="submit"></fui-button>
</view>
</fui-form>
<view class="page">
<view class="formBox">
<fui-form ref="formRef" label-weight="auto" top="60" :disabled="form.id ? true : false">
<view class="mt20">
<fui-input
required
label="农机名称"
placeholder="请输入农机名称"
v-model="form.name"
labelSize="28"
label-width="180"
></fui-input>
<fui-input
required
label="联系方式"
placeholder="请输入联系方式"
v-model="form.phone"
labelSize="28"
label-width="180"
></fui-input>
<view class="form-item required flex align-center" style="padding: 20rpx 10rpx">
<text class="label">服务范围</text>
<view class="time-input" @click="show.address = true">
<text class="select-text" :class="{ placeholder: !form.scope }">
{{ form.scope || '请选择省/市/区县' }}
</text>
</view>
</view>
<!-- <fui-input
required
label="服务范围"
placeholder="请输入服务范围"
v-model="form.scope"
labelSize="28"
label-width="180"
></fui-input> -->
<fui-input
required
type="number"
label="价格(元/亩)"
placeholder="请输入价格"
number
v-model="form.price"
labelSize="28"
label-width="180"
></fui-input>
</view>
<view class="bg-white mt20" style="padding: 0.875rem 1rem">
<view class="mb-1 flex justify-start"> 图片 </view>
<uni-file-picker
:value="form.pictureObj"
:max-size="1024"
ref="uploadRef"
limit="1"
:auto-upload="false"
@select="handleUpload"
@delete="handleDelete"
></uni-file-picker>
</view>
<view class="fui-btn__box" v-if="!form.id" style="margin-top: 30rpx">
<fui-button text="发布作业" bold radius="96rpx" @click="submit"></fui-button>
</view>
</fui-form>
<fui-toast ref="toastRef"></fui-toast>
<fui-loading isFixed v-if="pageData.loading" backgroundColor="rgba(0, 0, 0, 0.4)"></fui-loading>
<fui-toast ref="toastRef"></fui-toast>
<fui-loading isFixed v-if="pageData.loading" backgroundColor="rgba(0, 0, 0, 0.4)"></fui-loading>
<fui-picker
:show="show.address"
:options="options.address"
:linkage="true"
:layer="3"
@change="handleChangeAddress"
@cancel="show.address = false"
></fui-picker>
</view>
</view>
</template>
<style lang="scss" scoped>
body {
background-color: #e6f5e8;
}
.page {
background-color: #e6f5e8;
width: 750rpx;
overflow-x: hidden;
.mt20 {
margin-top: 30rpx;
background: #fff;
padding: 20rpx;
border-radius: 10rpx;
}
.formBox {
width: 690rpx;
margin: 30rpx auto;
}
.form-section {
border-bottom: 1rpx solid #f5f5f5;
}
.form-item {
padding: 30rpx 0;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
&.required .label::before {
content: '*';
color: #ff4d4f;
margin-right: 8rpx;
}
}
.form-row {
display: flex;
justify-content: space-between;
}
.half-width {
width: 48%;
}
.align-center {
align-items: center;
}
.label {
display: block;
font-size: 28rpx;
color: #333333;
font-weight: 500;
width: 180rpx;
}
.input {
width: 100%;
height: 80rpx;
background: #f8f9fa;
border-radius: 8rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333333;
&::placeholder {
color: #999999;
}
}
.time-range {
display: flex;
align-items: center;
justify-content: space-between;
}
.time-input {
width: 45%;
border-radius: 8rpx;
display: flex;
align-items: center;
}
.time-text {
font-size: 28rpx;
color: #333333;
&.placeholder {
color: #999999;
}
}
.time-separator {
color: #666666;
font-size: 28rpx;
margin: 0 10rpx;
}
.upload-area {
margin-top: 10rpx;
}
.custom-uploader {
:deep(.uni-file-picker__container) {
border: 2rpx dashed #d9d9d9;
border-radius: 8rpx;
background: #f8f9fa;
}
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 200rpx;
color: #999999;
}
.upload-icon {
font-size: 48rpx;
margin-bottom: 10rpx;
}
.upload-text {
font-size: 24rpx;
}
.submit-section {
background: transparent;
padding: 40rpx 0;
}
.submit-btn {
width: 100%;
height: 88rpx;
background: #5db66f;
border-radius: 44rpx;
color: #ffffff;
font-size: 32rpx;
font-weight: 500;
border: none;
&:active {
background: #4ca85c;
opacity: 0.9;
}
}
}
::v-deep .uni-input-placeholder {
font-size: 28rpx !important;
color: #999999 !important;
}
:deep(.fui-button) {
border-color: #ff9800 !important;
background: #ff9800 !important;
width: 690rpx;
border-color: #5db66f !important;
background: #5db66f !important;
}
// 移除fui-form的默认样式
:deep(.fui-form) {
background: transparent;
}
:deep(.fui-form__item) {
background: transparent;
border: none;
margin-bottom: 0;
padding: 0;
}
.time-input {
width: 45%;
// height: 80rpx;
// background: #f8f9fa;
border-radius: 8rpx;
display: flex;
align-items: center;
}
.time-text {
font-size: 28rpx;
color: #333333;
padding: 0 20rpx;
&.placeholder {
color: #999999;
}
}
.select-input {
flex: 1;
border-radius: 8rpx;
padding: 0 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
}
.select-text {
font-size: 28rpx;
color: #333333;
padding: 0 20rpx;
&.placeholder {
color: #999999;
}
}
</style>
......@@ -126,7 +126,7 @@
:src="item.picture"
@click="handleDetails(item)"
/>
<view style="width: 75%">
<view style="width: 70%">
<view
class="codefun-flex-col codefun-items-start codefun-flex-1 codefun-self-center"
@click="handleDetails(item)"
......@@ -270,12 +270,10 @@
</view> -->
</view>
</view>
<fui-fab background="#5db66f" position="right" distance="10" bottom="240" width="130" @click="handlePublish">
<fui-fab position="right" distance="10" bottom="240" width="96" @click="handlePublish">
<view class="text-white text-center">
<image src="/src/static/images/chanxiao/notepad.svg" style="width: 40rpx" mode="widthFix"></image>
<view style="font-size: 24rpx"
>发布{{ pageData.categoryTabs.find((item) => item.id === pageData.search.serviceType)?.name }}</view
>
<view class="fab-icon"></view>
<view style="font-size: 24rpx">发布</view>
</view>
</fui-fab>
......@@ -462,6 +460,8 @@
.image_8 {
width: 160rpx;
height: 160rpx;
border-radius: 10rpx;
margin-right: 20rpx;
}
.font_6 {
font-size: 24rpx;
......@@ -641,4 +641,9 @@
color: #333333;
}
}
::v-deep .fui-fab__btn-main {
background: linear-gradient(124.25deg, #a5d63f 0%, #5db66f 100%) !important;
box-shadow: 0px 1px 8px #5db66f;
}
</style>
......@@ -54,8 +54,17 @@ export const convertToTree = (): AreaNode[] => {
return tree
}
// 导出树形结构数据
export const areaTree = convertToTree()
// 导出树形结构数据(懒加载)
let areaTreeCache: AreaNode[] | null = null
export const getAreaTree = (): AreaNode[] => {
if (!areaTreeCache) {
areaTreeCache = convertToTree()
}
return areaTreeCache
}
// 向后兼容的导出
export const areaTree = getAreaTree()
/**
* 根据地区代码获取完整的地区名称(如:广东省广州市天河区)
......@@ -85,46 +94,28 @@ export const getFullAreaName = (code: string): string => {
// 根据编号获取文本
export function getTextByCode(code) {
// 遍历省份
for (const provinceCode in areaList.province_list) {
if (provinceCode === code) {
return areaList.province_list[provinceCode]
}
// 遍历城市
for (const cityCode in areaList.city_list) {
if (cityCode === code) {
return areaList.city_list[cityCode]
}
// 遍历区县
for (const countyCode in areaList.county_list) {
if (countyCode === code) {
return areaList.county_list[countyCode]
}
}
}
// 直接查询,避免多层嵌套循环
if (areaList.province_list[code]) {
return areaList.province_list[code]
}
if (areaList.city_list[code]) {
return areaList.city_list[code]
}
if (areaList.county_list[code]) {
return areaList.county_list[code]
}
return null
}
// 根据文本获取编号
export function getCodeByText(text) {
// 遍历省份
for (const provinceCode in areaList.province_list) {
if (areaList.province_list[provinceCode] === text) {
return provinceCode
}
}
// 遍历城市
for (const cityCode in areaList.city_list) {
if (areaList.city_list[cityCode] === text) {
return cityCode
}
}
// 遍历区县
for (const countyCode in areaList.county_list) {
if (areaList.county_list[countyCode] === text) {
return countyCode
}
// 使用Object.entries和find方法优化性能
const findCode = (obj: Record<string, string>) => {
const entry = Object.entries(obj).find(([_, value]) => value === text)
return entry ? entry[0] : null
}
return null
return findCode(areaList.province_list)
|| findCode(areaList.city_list)
|| findCode(areaList.county_list)
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论