城镇基础数据

wechat
ihzero 2023-09-13 02:37:06 +08:00
parent b9845d3065
commit e1e4dcce03
17 changed files with 1754 additions and 319 deletions

View File

@ -646,4 +646,10 @@ body, uni-page-body {
} }
} }
} }
.dropdownClose{
.u-dropdown__content{
pointer-events: none;
}
}
</style> </style>

View File

@ -0,0 +1,37 @@
<template>
<u-navbar
:title="title"
:background="background"
:custom-back="goback"
:title-color="titleColor"
:back-icon-color="titleColor"
>
<template #right>
<slot name="right"></slot>
</template>
</u-navbar>
</template>
<script>
import { navigateBack } from '@/com/utils.js'
export default {
props: {
title: {
type: String,
default: '',
},
},
data() {
return {
background: {
backgroundColor: '#2a7dc9',
},
titleColor: '#ffffff',
}
},
methods: {
goback() {
navigateBack()
},
},
}
</script>

View File

@ -13,10 +13,14 @@
</view> </view>
<scroll-view scroll-y="true" class="max-h-1200rpx"> <scroll-view scroll-y="true" class="max-h-1200rpx">
<view v-if="colums.length && data && Object.keys(data).length"> <view v-if="colums.length && data && Object.keys(data).length">
<view class="flex items-center" v-for="(item, i) in colums" :key="i"> <view
class="flex items-center"
v-for="(item, i) in columsList"
:key="i"
>
<u-cell-item <u-cell-item
:title="item.title" :title="item.title"
:value="data[item.dataIndex]" :value="item.value"
:arrow="false" :arrow="false"
></u-cell-item> ></u-cell-item>
</view> </view>
@ -56,8 +60,26 @@ export default {
isDel() { isDel() {
return !!this.$listeners.onDel return !!this.$listeners.onDel
}, },
columsList() {
const arr = []
this.colums.forEach((e) => {
const { dataIndex, format } = e
let str = this.data[dataIndex]
if (this.isFunction(format)) {
str = format(str)
}
arr.push({
...e,
value: str,
})
})
return arr
},
}, },
methods: { methods: {
isFunction(fn) {
return typeof fn === 'function'
},
handleEdit() { handleEdit() {
this.$emit('onEdit', this.data) this.$emit('onEdit', this.data)
}, },

View File

@ -0,0 +1,114 @@
<template>
<view>
<u-checkbox-group @change="checkboxGroupChange">
<u-checkbox
v-model="item.checked"
@change="checkboxChange"
v-for="(item, index) in getOptions"
:key="item.value"
:name="item.value"
>{{ item.label }}</u-checkbox
>
</u-checkbox-group>
</view>
</template>
<script>
import { omit } from 'lodash-es'
export default {
props: {
api: {
type: Function,
default: () => {},
},
value: {
type: [Array, Object, String, Number],
},
params: {
type: Object,
default: () => ({}),
},
labelField: {
type: String,
default: 'label',
},
valueField: {
type: String,
default: 'value',
},
placeholder: {
type: String,
default: '请选择',
},
},
data() {
return {
checkValue: [],
options: [],
getOptions: [],
}
},
computed: {},
created() {
this.fetch()
},
methods: {
getOptionsFun() {
const { labelField, valueField } = this
return this.options.reduce((prev, next) => {
if (next) {
const value = next[valueField]
prev.push({
...omit(next, [labelField, valueField]),
label: next[labelField],
value: value,
key: value,
checked: this.checkValue.includes(value),
})
}
return prev
}, [])
},
checkboxChange(e) {},
checkboxGroupChange(e) {
this.checkValue = e
this.$emit('change', e)
this.$emit('input', e)
},
async fetch() {
const api = this.api
if (!api || !this.isFunction(api)) return
this.options = []
try {
const data = await api(this.params)
this.isFirstLoad = false
if (Array.isArray(data)) {
this.options = data
this.getOptions = this.getOptionsFun()
this.emitChange()
return
}
this.emitChange()
} catch (error) {
console.warn(error)
}
},
emitChange() {
this.$emit('options-change', this.getOptions)
},
isFunction(fn) {
return typeof fn === 'function'
},
},
watch: {
value: {
handler(val) {
this.checkValue = val ?? []
this.getOptionsFun()
},
immediate: true,
deep: true,
},
},
}
</script>

View File

@ -0,0 +1,115 @@
<template>
<view class="w-full">
<view @click="show = true">
<u-input
class="w-full !pointer-events-none"
:placeholder="placeholder"
:value="showText"
type="select"
/>
</view>
<u-select
@confirm="handleConfirm"
:default-value="defaultValue"
v-model="show"
:list="getOptions"
></u-select>
</view>
</template>
<script>
import { omit } from 'lodash-es'
export default {
props: {
api: {
type: Function,
default: () => {},
},
value: {
type: [Array, Object, String, Number],
},
params: {
type: Object,
default: () => ({}),
},
labelField: {
type: String,
default: 'label',
},
valueField: {
type: String,
default: 'value',
},
placeholder: {
type: String,
default: '请选择',
},
},
data() {
return {
show: false,
options: [],
}
},
computed: {
currentOption() {
const item = this.getOptions.find((e) => e.value == this.value)
return item ?? {}
},
showText() {
return this.currentOption?.label ?? this.value
},
defaultValue() {
const index = this.getOptions.findIndex((e) => e.value == this.value)
return [index > -1 ? index : 0]
},
getOptions() {
const { labelField, valueField } = this
return this.options.reduce((prev, next) => {
if (next) {
const value = next[valueField]
prev.push({
...omit(next, [labelField, valueField]),
label: next[labelField],
value: value,
})
}
return prev
}, [])
},
},
created() {
this.fetch()
},
methods: {
async fetch() {
const api = this.api
if (!api || !this.isFunction(api)) return
this.options = []
try {
const data = await api(this.params)
this.isFirstLoad = false
if (Array.isArray(data)) {
this.options = data
this.emitChange()
return
}
this.emitChange()
} catch (error) {
console.warn(error)
}
},
emitChange() {
this.$emit('options-change', this.getOptions)
},
handleConfirm(e) {
const { value } = e[0]
this.$emit('change', value)
this.$emit('input', value)
},
isFunction(fn) {
return typeof fn === 'function'
},
},
}
</script>

View File

@ -0,0 +1,62 @@
<template>
<u-dropdown-item :title="label">
<view class="bg-white p-30rpx">
<u-input v-model="status" :placeholder="placeholder" class="flex-1" />
<view class="my-20rpx">
<u-line></u-line>
</view>
<u-button type="primary" @click="handleChange"></u-button>
</view>
</u-dropdown-item>
</template>
<script>
export default {
props: {
label: {
type: String,
default: '',
},
value: {
type: [Array, Object, String, Number],
},
placeholder: {
type: [Array, String],
default: '请输入',
},
isOpen: {
type: Boolean,
},
},
computed: {
// status: {
// get() {
// console.log(this.value);
// return this.value
// },
// set(val) {
// // this.$emit('change', val)
// // this.$emit('input', val)
// },
// },
},
data() {
return {
status: '',
}
},
methods: {
handleChange() {
this.$emit('change', this.status)
this.$emit('close-dropdown', this.status)
},
},
watch: {
isOpen: {
handler(e) {
this.status = this.value
},
immediate: true,
},
},
}
</script>

View File

@ -1,13 +1,14 @@
<template> <template>
<component v-bind="getBindValue.bind" v-on="getBindValue.on"></component> <component v-bind="getBindValue.bind" v-on="getBindValue.on"></component>
</template> </template>
<script> <script>
import ApiSelect from './ApiSelect.vue' import ApiSelect from './ApiSelect.vue'
import Calendar from './Calendar.vue' import Calendar from './Calendar.vue'
import Input from './Input.vue'
import { upperFirst, kebabCase } from 'lodash-es' import { upperFirst, kebabCase } from 'lodash-es'
export default { export default {
props: { props: {
schema: { schema: {
type: Object, type: Object,
default: () => {}, default: () => {},
}, },
@ -23,10 +24,14 @@ export default {
type: Object, type: Object,
default: () => {}, default: () => {},
}, },
isOpen: {
type: Boolean,
},
}, },
components: { components: {
ApiSelect, ApiSelect,
Calendar Calendar,
Input,
}, },
created() { created() {
// this.fetch() // this.fetch()
@ -92,6 +97,7 @@ export default {
...propsData, ...propsData,
...bindValue, ...bindValue,
...on, ...on,
isOpen: this.isOpen,
} }
const onEventsObject = {} const onEventsObject = {}
const bindObject = {} const bindObject = {}

View File

@ -1,6 +1,11 @@
<template> <template>
<view> <view>
<u-dropdown ref="dropdownRef"> <u-dropdown
ref="dropdownRef"
:class="{ dropdownClose: !isOpen }"
@open="isOpen = true"
@close="isOpen = false"
>
<SearchItem <SearchItem
v-for="schema in getSchema" v-for="schema in getSchema"
:key="schema.field" :key="schema.field"
@ -8,6 +13,7 @@
:formModel="formModel" :formModel="formModel"
:setFormModel="setFormModel" :setFormModel="setFormModel"
:formActionType="formActionType" :formActionType="formActionType"
:isOpen="isOpen"
@close-dropdown="handleCloseDropdown" @close-dropdown="handleCloseDropdown"
></SearchItem> ></SearchItem>
</u-dropdown> </u-dropdown>
@ -92,6 +98,7 @@ export default {
}, },
data() { data() {
return { return {
isOpen: false,
formModel: {}, formModel: {},
} }
}, },
@ -99,6 +106,9 @@ export default {
this.initFormModel() this.initFormModel()
}, },
methods: { methods: {
handleOpen() {
console.log('====')
},
handleCloseDropdown() { handleCloseDropdown() {
this.$refs.dropdownRef?.close() this.$refs.dropdownRef?.close()
}, },
@ -155,15 +165,14 @@ export default {
if (pattern.test(key)) { if (pattern.test(key)) {
const keyArr = key.match(pattern)[1].split(',') const keyArr = key.match(pattern)[1].split(',')
keyArr.forEach((item, index) => { keyArr.forEach((item, index) => {
const _val = value?.[index] ?? '' const _val = value?.[index] ?? ''
if(_val) { if (_val) {
res[item.trim()] = _val res[item.trim()] = _val
} }
}) })
}else { } else {
value && (res[key] = value) value && (res[key] = value)
} }
} }
return Object.assign({}, res) return Object.assign({}, res)
}, },

View File

@ -221,6 +221,14 @@
"navigationBarTitleText": "城镇数据", "navigationBarTitleText": "城镇数据",
"enablePullDownRefresh": false "enablePullDownRefresh": false
} }
},{
"path" : "pages/basics/basics-base",
"style" :
{
"navigationBarTitleText": "基地数据",
"enablePullDownRefresh": false,
"navigationStyle":"custom"
}
} }
], ],
"globalStyle": { "globalStyle": {

View File

@ -0,0 +1,289 @@
<template>
<view>
<Appbar title="基地数据">
<template #right>
<view class="text-white mr-20px" @click="handleCreate"></view>
</template>
</Appbar>
<u-sticky>
<view class="bg-white">
<SearchForm
:schemas="searchFormSchema"
@submit="handleSubmit"
></SearchForm>
</view>
</u-sticky>
<mescroll-body
@init="mescrollInit"
@up="upCallback"
:up="upOption"
:down="downOption"
>
<view>
<u-swipe-action
v-for="(item, i) in dataList"
:show="item.show"
:index="i"
:key="item.id"
class="my-20rpx mx-30rpx rounded-md overflow-hidden"
:options="options"
@click="handleClick"
@content-click="handleContentClick"
>
<view>
<view class="bg-white p-20rpx">
<view>基地名称{{ item.name }} </view>
<view>农业类型{{ item.industry_label }}</view>
<view class="my-12rpx">
<u-line></u-line>
</view>
<view class="grid grid-cols-3">
<view class="text-center">基地面积</view>
<view class="text-center">种养殖面积</view>
<view class="text-center">就业人数</view>
</view>
<view class="grid grid-cols-3">
<view class="text-center">{{ item.areas }}</view>
<view class="text-center">{{ item.cultivated }}</view>
<view class="text-center">{{ item.workforce }}</view>
</view>
</view>
</view>
</u-swipe-action>
</view>
</mescroll-body>
<!-- 详情 -->
<BaseTablePopup
v-model="baseShow"
:colums="baseTableColums"
:data="currentData"
@onEdit="handleEdit"
@onDel="handleDel"
></BaseTablePopup>
<!-- 编辑 -->
<cuPopup v-model="formShow" :title="currentData ? '编辑基地' : '新增基地'">
<BasicsEdit
@cancel="formShow = false"
@confirm="handleEditConfirm"
:data="currentData"
></BasicsEdit>
</cuPopup>
</view>
</template>
<script>
import Appbar from '@/components/Appbar'
import SearchForm from '@/components/search-form'
import { http } from '@/api/index.js'
import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js'
import cuPopup from '@/components/cu-popup/index.vue'
import BaseTablePopup from '@/components/base-table/popup.vue'
import BasicsEdit from './components/basics-edit.vue'
const baseTableColums = [
{
title: '基地名称',
dataIndex: 'name',
},
{
title: '农业类型',
dataIndex: 'industry_label',
},
{
title: '是否外部链接',
dataIndex: 'is_blank',
format: (text) => {
return text ? '是' : '否'
},
},
{
title: '排序',
dataIndex: 'sort',
},
{
title: '基地负责人',
dataIndex: 'person',
},
{
title: '基地农作物',
dataIndex: 'crops',
format: (arr) => {
return arr?.map((e) => e.name).join(',') ?? ''
},
},
{
title: '基地经度',
dataIndex: 'address_lng',
},
{
title: '基地纬度',
dataIndex: 'address_lat',
},
{
title: '基地地址',
dataIndex: 'address',
},
{
title: '基地面积',
dataIndex: 'areas',
},
{
title: '种养殖面积',
dataIndex: 'cultivated',
},
{
title: '基地就业人数',
dataIndex: 'workforce',
},
{
title: '基地描述',
dataIndex: 'description',
},
]
export default {
mixins: [MescrollMixin],
components: {
SearchForm,
Appbar,
cuPopup,
BaseTablePopup,
BasicsEdit,
},
data() {
return {
baseTableColums,
currentData: null,
filterParmas: {},
downOption: {
use: false,
},
upOption: {
auto: false,
page: {
size: 20,
},
},
dataList: [],
options: [
{
text: '编辑',
opt: 'edit',
style: {
backgroundColor: '#007aff',
},
},
{
text: '删除',
opt: 'delete',
style: {
backgroundColor: '#dd524d',
},
},
],
formShow: false,
baseShow: false,
searchFormSchema: [
{
field: 'name',
label: '名称',
component: 'Input',
componentProps: {
placeholder: '请输入名称',
},
},
{
field: 'type',
label: '农业类型',
component: 'ApiSelect',
componentProps: ({ formActionType }) => {
return {
api: async (e) => {
const { data } = await http.get('/api/keywords-industry', {
params: e,
})
return data.data
},
labelField: 'name',
valueField: 'id',
}
},
},
],
}
},
methods: {
handleSubmit(e) {
this.filterParmas = e
this.mescroll.resetUpScroll()
},
upCallback({ num, size }) {
this.getData({
...this.filterParmas,
page: num,
per_page: size,
type: 1,
})
},
async getData(e) {
try {
const { data } = await http.get(`/api/agricultural-basic`, {
params: e,
})
if (e.page == 1) this.dataList = []
const { data: list, meta } = data
this.dataList = this.dataList.concat(
list.map((e) => Object.assign({ show: false }, e))
)
this.mescroll.endByPage(list.length, meta.total)
} catch (error) {
this.mescroll.endErr()
}
},
handleClick(index1, index) {
const { opt } = this.options[index]
const item = this.dataList[index1]
this.currentData = item
if (opt == 'edit') {
this.handleEdit(item)
} else if (opt == 'delete') {
this.handleDel(item)
}
},
handleContentClick(e) {
this.currentData = this.dataList[e]
this.baseShow = true
},
handleEdit(item) {
this.currentData = item
this.formShow = true
this.baseShow = false
},
async handleDel(item) {
uni.showModal({
title: '提示',
content: '是否确定删除?',
success: async (res) => {
if (res.confirm) {
try {
await this.$http.delete(`/api/agricultural-basic/${item.id}`)
this.mescroll.resetUpScroll()
this.baseShow = false
} catch ({ data }) {
this.$u.toast(data.message)
}
}
},
})
},
async handleCreate() {
this.currentData = null
this.formShow = true
this.baseShow = false
},
handleEditConfirm() {
this.mescroll.resetUpScroll()
this.formShow = false
},
},
}
</script>

View File

@ -0,0 +1,219 @@
<template>
<view class="p-20rpx h-full overflow-hidden flex flex-col">
<view class="flex-1 relative">
<view class="absolute top-0 left-0 w-full h-full">
<scroll-view scroll-y="true" class="h-full">
<u-form ref="uForm" :model="form" class="cu-form" label-width="200">
<u-form-item label="ID" v-if="form.id">
<u-input disabled v-model="form.id"></u-input>
</u-form-item>
<u-form-item label="外部链接">
<u-switch v-model="form.is_blank"></u-switch>
</u-form-item>
<u-form-item label="外部链接" v-if="form.is_blank">
<u-input v-model="form.blank_url" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="农业类型">
<ApiSelect
v-model="form.industry_key"
v-bind="industrySelectOption"
></ApiSelect>
</u-form-item>
<u-form-item label="基地名称">
<u-input v-model="form.name" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="排序">
<u-input v-model="form.sort" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="基地负责人">
<u-input v-model="form.person" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="基地面积">
<u-input v-model="form.areas" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="种养殖面积">
<u-input v-model="form.cultivated" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="基地人数">
<u-input v-model="form.workforce" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="城镇">
<ApiSelect
v-model="form.parent_id"
v-bind="parentSelectOption"
></ApiSelect>
</u-form-item>
<u-form-item label="基地农作物">
<ApiCheckbox
v-model="form.crops_ids"
v-bind="cropsSelectOption"
></ApiCheckbox>
</u-form-item>
<u-form-item label="基地地址">
<u-input v-model="form.address"></u-input>
</u-form-item>
<u-form-item label="基地介绍">
<u-input type="textarea" v-model="form.description"></u-input>
</u-form-item>
<u-form-item label="基地经度">
<u-input v-model="form.address_lng"></u-input>
</u-form-item>
<u-form-item label="基地纬度">
<u-input v-model="form.address_lat"></u-input>
</u-form-item>
</u-form>
</scroll-view>
</view>
</view>
<view class="grid grid-cols-2 gap-x-20rpx">
<u-button class="mt-20rpx" round @click="handleCancel"> </u-button>
<u-button class="mt-20rpx" type="primary" round @click="handleSubmit">
保存
</u-button>
</view>
</view>
</template>
<script>
import { http } from '@/api/index.js'
import ApiSelect from '@/components/search-form/components/ApiSelect1.vue'
import ApiCheckbox from '@/components/search-form/components/ApiCheckbox.vue'
const industrySelectOption = {
api: async (e) => {
const { data } = await http.get('/api/keywords-industry', {
params: e,
})
return data.data
},
labelField: 'name',
valueField: 'key',
}
const parentSelectOption = {
api: async (e) => {
const { data } = await http.get('/api/agricultural-basic', {
params: {
type: 2,
},
})
console.log(data)
return data.data
},
labelField: 'name',
valueField: 'id',
}
const cropsSelectOption = {
api: async (e) => {
const { data } = await http.get('/api/crops', {
params: { type: 'all', crop_type: 1 },
})
console.log(data)
return data.data.map((e) => {
return {
...e,
disabled: e.is_end === 0,
}
})
},
labelField: 'name',
valueField: 'id',
}
export default {
props: {
data: {
type: Object,
default: () => {},
},
},
components: {
ApiSelect,
ApiCheckbox,
},
computed: {
isEdit() {
return !!this.data
},
},
data() {
return {
industrySelectOption,
parentSelectOption,
cropsSelectOption,
form: {
id: '',
is_blank: false,
blank_url: '',
industry_key: '',
name: '',
sort: 0,
person: '',
areas: '',
cultivated: '',
workforce: '',
parent_id: '',
crops_ids: [],
address: '',
description: '',
address_lng: '',
address_lat: '',
},
}
},
methods: {
handleCancel() {
this.$emit('cancel')
},
async handleSubmit() {
const params = { ...this.form, type: 1 }
if (this.isEdit) {
this.onUpdate(params)
} else {
this.onCreate(params)
}
this.$emit('confirm')
},
async onUpdate(params) {
try {
await this.$http.put(`/api/agricultural-basic/${params.id}`, params)
this.$u.toast('操作成功')
} catch ({ data }) {
data && this.$u.toast(data?.message)
}
},
async onCreate(params) {
try {
await this.$http.post('/api/agricultural-basic', params)
this.$u.toast('操作成功')
} catch ({ data }) {
data && this.$u.toast(data?.message)
}
},
setDefaultForm(data) {
Object.keys(data).forEach((key) => {
const value = data[key]
if (key == 'blank_url') {
this.form.is_blank = data[key] ? true : false
} else if (key == 'crops') {
this.form.crops_ids = value.map((e) => e.id)
}
if (this.form[key] !== undefined) this.form[key] = value
})
},
},
watch: {
data: {
handler(val) {
console.log(val)
if (val) {
this.setDefaultForm(val)
}
},
immediate: true,
deep: true,
},
},
}
</script>

View File

@ -1,69 +1,85 @@
<template> <template>
<view class="p-20rpx h-full overflow-hidden flex flex-col"> <view class="p-20rpx h-full overflow-hidden flex flex-col">
<view class="overflow-y-auto"> <view class="flex-1 relative">
<u-form ref="uForm" class="cu-form" label-width="200"> <view class="absolute top-0 left-0 w-full h-full">
<u-form-item v-for="(item, i) in template" :key="i" :label="item.name"> <scroll-view scroll-y="true" class="h-full">
<template v-if="!item.isMore"> <u-form ref="uForm" class="cu-form" label-width="200">
<view class="flex items-center flex-1"> <u-form-item
<template v-if="item.component == 'InputTextArea'"> v-for="(item, i) in template"
<u-input :key="i"
border :label="item.name"
class="flex-1" >
type="textarea" <template v-if="!item.isMore">
v-model="item.value" <view class="flex items-center flex-1">
:suffix="item.unit" <template v-if="item.component == 'InputTextArea'">
placeholder="请输入" <u-input
/> border
class="flex-1"
type="textarea"
v-model="item.value"
:suffix="item.unit"
placeholder="请输入"
/>
</template>
<template v-else>
<u-input
border
:disabled="item.readonly"
class="w-full"
v-model="item.value"
:suffix="item.unit"
placeholder="请输入"
/>
</template>
</view>
</template> </template>
<template v-else> <template v-else>
<u-input <view class="w-full">
border <view
:disabled="item.readonly" class="w-full flex my-10rpx"
class="w-full" v-for="(arr, j) in item.value"
v-model="item.value" :key="j"
:suffix="item.unit" >
placeholder="请输入" <view class="w-140rpx mr-20rpx">
/> <u-input
type="number"
:clearable="false"
border
v-model="arr.year"
placeholder="请输入"
/>
</view>
<view class="flex-1 flex items-center">
<u-input
type="number"
:clearable="false"
border
v-model="arr.value"
placeholder="请输入"
/>
<!-- <view class="opacity-50 ml-10rpx">{{ item.unit }}</view> -->
</view>
<view
@click="addDomain(item)"
v-if="j == 0"
class="px-10rpx"
>
<u-icon name="plus" size="34"></u-icon>
</view>
<view
@click="removeDomain(item, j)"
class="px-10rpx"
v-else
>
<u-icon name="minus" size="34"></u-icon>
</view>
</view>
</view>
</template> </template>
</view> </u-form-item>
</template> </u-form>
<template v-else> </scroll-view>
<view class="w-full"> </view>
<view
class="w-full flex my-10rpx"
v-for="(arr, j) in item.value"
:key="j"
>
<view class="w-140rpx mr-20rpx">
<u-input
type="number"
:clearable="false"
border
v-model="arr.year"
placeholder="请输入"
/>
</view>
<view class="flex-1 flex items-center">
<u-input
type="number"
:clearable="false"
border
v-model="arr.value"
placeholder="请输入"
/>
<!-- <view class="opacity-50 ml-10rpx">{{ item.unit }}</view> -->
</view>
<view @click="addDomain(item)" v-if="j == 0" class="px-10rpx">
<u-icon name="plus" size="34"></u-icon>
</view>
<view @click="removeDomain(item, j)" class="px-10rpx" v-else>
<u-icon name="minus" size="34"></u-icon>
</view>
</view>
</view>
</template>
</u-form-item>
</u-form>
</view> </view>
<view class="grid grid-cols-2 gap-x-20rpx"> <view class="grid grid-cols-2 gap-x-20rpx">
<u-button class="mt-20rpx" round @click="handleCancel"> </u-button> <u-button class="mt-20rpx" round @click="handleCancel"> </u-button>

View File

@ -1,56 +1,74 @@
<template> <template>
<view class="p-20rpx h-full overflow-hidden flex flex-col"> <view class="p-20rpx h-full overflow-hidden flex flex-col">
<view class="overflow-y-auto"> <view class="flex-1 relative">
<u-form ref="uForm" class="cu-form" label-width="200"> <view class="absolute top-0 left-0 w-full h-full">
<u-form-item v-for="(item, i) in template" :key="i" :label="item.name"> <scroll-view scroll-y="true" class="h-full">
<template v-if="!item.isMore"> <u-form ref="uForm" class="cu-form" label-width="200">
<view class="flex items-center"> <u-form-item
<u-input v-for="(item, i) in template"
border :key="i"
v-model="item.value" :label="item.name"
:suffix="item.unit" >
placeholder="请输入" <template v-if="!item.isMore">
/> <view class="flex items-center">
<view class="w-120rpx opacity-50 ml-10rpx">{{ item.unit }}</view>
</view>
</template>
<template v-else>
<view class="w-full">
<view
class="w-full flex my-10rpx"
v-for="(arr, j) in item.value"
:key="j"
>
<view class="w-140rpx mr-20rpx">
<u-input <u-input
type="number"
:clearable="false"
border border
v-model="arr.year" v-model="item.value"
:suffix="item.unit"
placeholder="请输入" placeholder="请输入"
/> />
<view class="w-120rpx opacity-50 ml-10rpx">{{
item.unit
}}</view>
</view> </view>
<view class="flex-1 flex items-center"> </template>
<u-input <template v-else>
type="number" <view class="w-full">
:clearable="false" <view
border class="w-full flex my-10rpx"
v-model="arr.value" v-for="(arr, j) in item.value"
placeholder="请输入" :key="j"
/> >
<!-- <view class="opacity-50 ml-10rpx">{{ item.unit }}</view> --> <view class="w-140rpx mr-20rpx">
<u-input
type="number"
:clearable="false"
border
v-model="arr.year"
placeholder="请输入"
/>
</view>
<view class="flex-1 flex items-center">
<u-input
type="number"
:clearable="false"
border
v-model="arr.value"
placeholder="请输入"
/>
<!-- <view class="opacity-50 ml-10rpx">{{ item.unit }}</view> -->
</view>
<view
@click="addDomain(item)"
v-if="j == 0"
class="px-10rpx"
>
<u-icon name="plus" size="34"></u-icon>
</view>
<view
@click="removeDomain(item, j)"
class="px-10rpx"
v-else
>
<u-icon name="minus" size="34"></u-icon>
</view>
</view>
</view> </view>
<view @click="addDomain(item)" v-if="j == 0" class="px-10rpx"> </template>
<u-icon name="plus" size="34"></u-icon> </u-form-item>
</view> </u-form>
<view @click="removeDomain(item, j)" class="px-10rpx" v-else> </scroll-view>
<u-icon name="minus" size="34"></u-icon> </view>
</view>
</view>
</view>
</template>
</u-form-item>
</u-form>
</view> </view>
<view class="grid grid-cols-2 gap-x-20rpx"> <view class="grid grid-cols-2 gap-x-20rpx">
<u-button class="mt-20rpx" round @click="handleCancel"> </u-button> <u-button class="mt-20rpx" round @click="handleCancel"> </u-button>

View File

@ -196,7 +196,6 @@ export default {
handleClick(index1, index) { handleClick(index1, index) {
this.currentData = this.dataList[index1] this.currentData = this.dataList[index1]
this.cityItemShow = true this.cityItemShow = true
console.log(index1, index)
}, },
handleContentClick(e) { handleContentClick(e) {

View File

@ -0,0 +1,219 @@
<template>
<view class="p-20rpx h-full overflow-hidden flex flex-col">
<view class="flex-1 relative">
<view class="absolute top-0 left-0 w-full h-full">
<scroll-view scroll-y="true" class="h-full">
<u-form ref="uForm" :model="form" class="cu-form" label-width="200">
<u-form-item label="ID" v-if="form.id">
<u-input disabled v-model="form.id"></u-input>
</u-form-item>
<u-form-item label="外部链接">
<u-switch v-model="form.is_blank"></u-switch>
</u-form-item>
<u-form-item label="外部链接" v-if="form.is_blank">
<u-input v-model="form.blank_url" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="农业类型">
<ApiSelect
v-model="form.industry_key"
v-bind="industrySelectOption"
></ApiSelect>
</u-form-item>
<u-form-item label="基地名称">
<u-input v-model="form.name" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="排序">
<u-input v-model="form.sort" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="基地负责人">
<u-input v-model="form.person" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="基地面积">
<u-input v-model="form.areas" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="种养殖面积">
<u-input v-model="form.cultivated" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="基地人数">
<u-input v-model="form.workforce" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="城镇">
<ApiSelect
v-model="form.parent_id"
v-bind="parentSelectOption"
></ApiSelect>
</u-form-item>
<u-form-item label="基地农作物">
<ApiCheckbox
v-model="form.crops_ids"
v-bind="cropsSelectOption"
></ApiCheckbox>
</u-form-item>
<u-form-item label="基地地址">
<u-input v-model="form.address"></u-input>
</u-form-item>
<u-form-item label="基地介绍">
<u-input type="textarea" v-model="form.description"></u-input>
</u-form-item>
<u-form-item label="基地经度">
<u-input v-model="form.address_lng"></u-input>
</u-form-item>
<u-form-item label="基地纬度">
<u-input v-model="form.address_lat"></u-input>
</u-form-item>
</u-form>
</scroll-view>
</view>
</view>
<view class="grid grid-cols-2 gap-x-20rpx">
<u-button class="mt-20rpx" round @click="handleCancel"> </u-button>
<u-button class="mt-20rpx" type="primary" round @click="handleSubmit">
保存
</u-button>
</view>
</view>
</template>
<script>
import { http } from '@/api/index.js'
import ApiSelect from '@/components/search-form/components/ApiSelect1.vue'
import ApiCheckbox from '@/components/search-form/components/ApiCheckbox.vue'
const industrySelectOption = {
api: async (e) => {
const { data } = await http.get('/api/keywords-industry', {
params: e,
})
return data.data
},
labelField: 'name',
valueField: 'key',
}
const parentSelectOption = {
api: async (e) => {
const { data } = await http.get('/api/agricultural-basic', {
params: {
type: 2,
},
})
console.log(data)
return data.data
},
labelField: 'name',
valueField: 'id',
}
const cropsSelectOption = {
api: async (e) => {
const { data } = await http.get('/api/crops', {
params: { type: 'all', crop_type: 1 },
})
console.log(data)
return data.data.map((e) => {
return {
...e,
disabled: e.is_end === 0,
}
})
},
labelField: 'name',
valueField: 'id',
}
export default {
props: {
data: {
type: Object,
default: () => {},
},
},
components: {
ApiSelect,
ApiCheckbox,
},
computed: {
isEdit() {
return !!this.data
},
},
data() {
return {
industrySelectOption,
parentSelectOption,
cropsSelectOption,
form: {
id: '',
is_blank: false,
blank_url: '',
industry_key: '',
name: '',
sort: 0,
person: '',
areas: '',
cultivated: '',
workforce: '',
parent_id: '',
crops_ids: [],
address: '',
description: '',
address_lng: '',
address_lat: '',
},
}
},
methods: {
handleCancel() {
this.$emit('cancel')
},
async handleSubmit() {
const params = { ...this.form, type: 1 }
if (this.isEdit) {
this.onUpdate(params)
} else {
this.onCreate(params)
}
this.$emit('confirm')
},
async onUpdate(params) {
try {
await this.$http.put(`/api/agricultural-basic/${params.id}`, params)
this.$u.toast('操作成功')
} catch ({ data }) {
data && this.$u.toast(data?.message)
}
},
async onCreate(params) {
try {
await this.$http.post('/api/agricultural-basic', params)
this.$u.toast('操作成功')
} catch ({ data }) {
data && this.$u.toast(data?.message)
}
},
setDefaultForm(data) {
Object.keys(data).forEach((key) => {
const value = data[key]
if (key == 'blank_url') {
this.form.is_blank = data[key] ? true : false
} else if (key == 'crops') {
this.form.crops_ids = value.map((e) => e.id)
}
if (this.form[key] !== undefined) this.form[key] = value
})
},
},
watch: {
data: {
handler(val) {
console.log(val)
if (val) {
this.setDefaultForm(val)
}
},
immediate: true,
deep: true,
},
},
}
</script>

View File

@ -0,0 +1,289 @@
<template>
<view>
<Appbar title="基地数据">
<template #right>
<view class="text-white mr-20px" @click="handleCreate"></view>
</template>
</Appbar>
<u-sticky>
<view class="bg-white">
<SearchForm
:schemas="searchFormSchema"
@submit="handleSubmit"
></SearchForm>
</view>
</u-sticky>
<mescroll-body
@init="mescrollInit"
@up="upCallback"
:up="upOption"
:down="downOption"
>
<view>
<u-swipe-action
v-for="(item, i) in dataList"
:show="item.show"
:index="i"
:key="item.id"
class="my-20rpx mx-30rpx rounded-md overflow-hidden"
:options="options"
@click="handleClick"
@content-click="handleContentClick"
>
<view>
<view class="bg-white p-20rpx">
<view>基地名称{{ item.name }} </view>
<view>农业类型{{ item.industry_label }}</view>
<view class="my-12rpx">
<u-line></u-line>
</view>
<view class="grid grid-cols-3">
<view class="text-center">基地面积</view>
<view class="text-center">种养殖面积</view>
<view class="text-center">就业人数</view>
</view>
<view class="grid grid-cols-3">
<view class="text-center">{{ item.areas }}</view>
<view class="text-center">{{ item.cultivated }}</view>
<view class="text-center">{{ item.workforce }}</view>
</view>
</view>
</view>
</u-swipe-action>
</view>
</mescroll-body>
<!-- 详情 -->
<BaseTablePopup
v-model="baseShow"
:colums="baseTableColums"
:data="currentData"
@onEdit="handleEdit"
@onDel="handleDel"
></BaseTablePopup>
<!-- 编辑 -->
<cuPopup v-model="formShow" :title="currentData ? '编辑基地' : '新增基地'">
<BasicsEdit
@cancel="formShow = false"
@confirm="handleEditConfirm"
:data="currentData"
></BasicsEdit>
</cuPopup>
</view>
</template>
<script>
import Appbar from '@/components/Appbar'
import SearchForm from '@/components/search-form'
import { http } from '@/api/index.js'
import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js'
import cuPopup from '@/components/cu-popup/index.vue'
import BaseTablePopup from '@/components/base-table/popup.vue'
import BasicsEdit from './components/basics-edit.vue'
const baseTableColums = [
{
title: '基地名称',
dataIndex: 'name',
},
{
title: '农业类型',
dataIndex: 'industry_label',
},
{
title: '是否外部链接',
dataIndex: 'is_blank',
format: (text) => {
return text ? '是' : '否'
},
},
{
title: '排序',
dataIndex: 'sort',
},
{
title: '基地负责人',
dataIndex: 'person',
},
{
title: '基地农作物',
dataIndex: 'crops',
format: (arr) => {
return arr?.map((e) => e.name).join(',') ?? ''
},
},
{
title: '基地经度',
dataIndex: 'address_lng',
},
{
title: '基地纬度',
dataIndex: 'address_lat',
},
{
title: '基地地址',
dataIndex: 'address',
},
{
title: '基地面积',
dataIndex: 'areas',
},
{
title: '种养殖面积',
dataIndex: 'cultivated',
},
{
title: '基地就业人数',
dataIndex: 'workforce',
},
{
title: '基地描述',
dataIndex: 'description',
},
]
export default {
mixins: [MescrollMixin],
components: {
SearchForm,
Appbar,
cuPopup,
BaseTablePopup,
BasicsEdit,
},
data() {
return {
baseTableColums,
currentData: null,
filterParmas: {},
downOption: {
use: false,
},
upOption: {
auto: false,
page: {
size: 20,
},
},
dataList: [],
options: [
{
text: '编辑',
opt: 'edit',
style: {
backgroundColor: '#007aff',
},
},
{
text: '删除',
opt: 'delete',
style: {
backgroundColor: '#dd524d',
},
},
],
formShow: false,
baseShow: false,
searchFormSchema: [
{
field: 'name',
label: '名称',
component: 'Input',
componentProps: {
placeholder: '请输入名称',
},
},
{
field: 'type',
label: '农业类型',
component: 'ApiSelect',
componentProps: ({ formActionType }) => {
return {
api: async (e) => {
const { data } = await http.get('/api/keywords-industry', {
params: e,
})
return data.data
},
labelField: 'name',
valueField: 'id',
}
},
},
],
}
},
methods: {
handleSubmit(e) {
this.filterParmas = e
this.mescroll.resetUpScroll()
},
upCallback({ num, size }) {
this.getData({
...this.filterParmas,
page: num,
per_page: size,
type: 1,
})
},
async getData(e) {
try {
const { data } = await http.get(`/api/agricultural-basic`, {
params: e,
})
if (e.page == 1) this.dataList = []
const { data: list, meta } = data
this.dataList = this.dataList.concat(
list.map((e) => Object.assign({ show: false }, e))
)
this.mescroll.endByPage(list.length, meta.total)
} catch (error) {
this.mescroll.endErr()
}
},
handleClick(index1, index) {
const { opt } = this.options[index]
const item = this.dataList[index1]
this.currentData = item
if (opt == 'edit') {
this.handleEdit(item)
} else if (opt == 'delete') {
this.handleDel(item)
}
},
handleContentClick(e) {
this.currentData = this.dataList[e]
this.baseShow = true
},
handleEdit(item) {
this.currentData = item
this.formShow = true
this.baseShow = false
},
async handleDel(item) {
uni.showModal({
title: '提示',
content: '是否确定删除?',
success: async (res) => {
if (res.confirm) {
try {
await this.$http.delete(`/api/agricultural-basic/${item.id}`)
this.mescroll.resetUpScroll()
this.baseShow = false
} catch ({ data }) {
this.$u.toast(data.message)
}
}
},
})
},
async handleCreate() {
this.currentData = null
this.formShow = true
this.baseShow = false
},
handleEditConfirm() {
this.mescroll.resetUpScroll()
this.formShow = false
},
},
}
</script>

View File

@ -1,214 +1,221 @@
<template> <template>
<view class="index-page bg-page"> <view class="index-page bg-page">
<view class="banner-section"> <view class="banner-section">
<image class="banner_img" mode="scaleToFill" src="../../static/img/banner_img.png"></image> <image
</view> class="banner_img"
<view class="content-box"> mode="scaleToFill"
<view class="menus-section" v-for="(menu,index) in menuList" :key="index"> src="../../static/img/banner_img.png"
<view class="title-t" v-if="menu.parent">{{menu.parent}}-{{menu.label}}</view> ></image>
<view class="title-t" v-else>{{menu.label}}</view> </view>
<view class="menu-ul"> <view class="content-box">
<view class="menu-li" v-for="(cdm,i) in menu.children" :key="i"> <view
<view class="menu_item" @click="linknavFn(cdm)"> class="menus-section"
<view class="icon"></view> v-for="(menu, index) in menuList"
<view class="name">{{cdm.label}}</view> :key="index"
</view> >
</view> <view class="title-t" v-if="menu.parent"
>{{ menu.parent }}-{{ menu.label }}</view
</view> >
</view> <view class="title-t" v-else>{{ menu.label }}</view>
</view> <view class="menu-ul">
</view> <view class="menu-li" v-for="(cdm, i) in menu.children" :key="i">
<view class="menu_item" @click="linknavFn(cdm)">
<view class="icon"></view>
<view class="name">{{ cdm.label }}</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template> </template>
<script> <script>
export default { export default {
data() { data() {
return { return {
title: 'Hello', title: 'Hello',
menuList:[ menuList: [
{ {
label:'监测数据管理', label: '监测数据管理',
children:[ children: [
{ {
label:'气象监测', label: '气象监测',
url:"/pages/index/meteorological" url: '/pages/index/meteorological',
}, },
{ {
label:'智能监控', label: '智能监控',
url:'/pages/index/monitor' url: '/pages/index/monitor',
}, },
{ {
label:'土壤监控', label: '土壤监控',
url:'/pages/index/soil-monitoring' url: '/pages/index/soil-monitoring',
}, },
{ {
label:'水质监控', label: '水质监控',
url:'/pages/index/water-quality' url: '/pages/index/water-quality',
}, },
{ {
label:'昆虫性诱监测', label: '昆虫性诱监测',
url:'/pages/index/insect-monitors' url: '/pages/index/insect-monitors',
}, },
{ {
label:'虫情监测', label: '虫情监测',
url:'/pages/index/pests' url: '/pages/index/pests',
}, },
{ {
label:'杀虫灯检测', label: '杀虫灯检测',
url:'/pages/index/insecticidal-lamp' url: '/pages/index/insecticidal-lamp',
}, },
], ],
}, },
// { // {
// label:'', // label:'',
// children:[ // children:[
// { // {
// label:'', // label:'',
// }, // },
// { // {
// label:'', // label:'',
// }, // },
// ], // ],
// }, // },
{ {
label:'全市基础数据', label: '全市基础数据',
parent:'基础数据管理', parent: '基础数据管理',
children:[ children: [
{ {
label:'城镇数据', label: '城镇数据',
url:'/pages/basics/town-base' url: '/pages/basics/town-base',
}, },
{ {
label:'基地数据', label: '基地数据',
}, url: '/pages/basics/basics-base',
], },
}, ],
{ },
label:'农作物数据', {
parent:'基础数据管理', label: '农作物数据',
children:[ parent: '基础数据管理',
{ children: [
label:'城镇农作物', {
}, label: '城镇农作物',
{ },
label:'基地农作物', {
} label: '基地农作物',
], },
}, ],
{ },
label:'农作物产量', {
parent:'基础数据管理', label: '农作物产量',
children:[ parent: '基础数据管理',
{ children: [
label:'城镇产量', {
}, label: '城镇产量',
{ },
label:'基地产量', {
}, label: '基地产量',
], },
}, ],
{ },
label:'重点产业', {
parent:'基础数据管理', label: '重点产业',
children:[ parent: '基础数据管理',
{ children: [
label:'稻虾价格', {
url:'/pages/estate/estate-price' label: '稻虾价格',
}, url: '/pages/estate/estate-price',
{ },
label:'稻虾每周价格', {
url:'/pages/estate/estate-week-price' label: '稻虾每周价格',
}, url: '/pages/estate/estate-week-price',
{ },
label:'稻虾产业', {
url:'/pages/estate/estate-industry' label: '稻虾产业',
}, url: '/pages/estate/estate-industry',
{ },
label:'稻虾流向', {
url:'/pages/estate/estate-flows' label: '稻虾流向',
}, url: '/pages/estate/estate-flows',
{ },
label:'大宗物资', {
url:'/pages/estate/estate-materiels' label: '大宗物资',
}, url: '/pages/estate/estate-materiels',
] },
}, ],
{ },
label:'设备管理', {
children:[ label: '设备管理',
{ children: [
label:'设备管理', {
url:'/pages/device/index' label: '设备管理',
}, url: '/pages/device/index',
{ },
label:'警报明细', {
url:'/pages/device/warning' label: '警报明细',
} url: '/pages/device/warning',
], },
}, ],
] },
],
} }
}, },
onLoad() { onLoad() {},
methods: {
}, linknavFn(item) {
methods: { console.log(item)
linknavFn(item){ uni.navigateTo({
console.log(item) url: `${item.url}`,
uni.navigateTo({ })
url:`${item.url}` },
}) },
} }
}
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.banner-section{ .banner-section {
.banner_img{ .banner_img {
width: 100%; width: 100%;
height: 280rpx; height: 280rpx;
} }
} }
.index-page{ .index-page {
background-color: #f8f8f8; background-color: #f8f8f8;
.content-box{ .content-box {
padding-top: 30rpx; padding-top: 30rpx;
padding-bottom: 150rpx; padding-bottom: 150rpx;
} }
} }
.menus-section{ .menus-section {
padding: 20rpx; padding: 20rpx;
font-size: 28rpx; font-size: 28rpx;
margin-top: -18rpx; margin-top: -18rpx;
.title-t{ .title-t {
margin-bottom: 24rpx; margin-bottom: 24rpx;
padding: 0 10rpx; padding: 0 10rpx;
font-size: 28rpx; font-size: 28rpx;
font-weight: bold; font-weight: bold;
} }
} }
.menu-ul{ .menu-ul {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
.menu-li{ .menu-li {
flex: 0 0 25%; flex: 0 0 25%;
text-align: center; text-align: center;
padding: 0 10rpx; padding: 0 10rpx;
margin-bottom: 18rpx; margin-bottom: 18rpx;
.menu_item{ .menu_item {
background-color: #fff; background-color: #fff;
box-shadow:0 0 20rpx rgba(0,0,0,0.15); box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.15);
min-height: 90rpx; min-height: 90rpx;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 10rpx 15rpx; padding: 10rpx 15rpx;
height: 100%; height: 100%;
} }
} }
} }
</style> </style>