城镇基础数据

wechat
ihzero 2023-09-12 21:08:29 +08:00
parent 378d2a60e1
commit b9845d3065
10 changed files with 902 additions and 32 deletions

View File

@ -31,6 +31,15 @@ export default {
body, uni-page-body { body, uni-page-body {
background-color: #f8f8f8; background-color: #f8f8f8;
} }
.cu-form {
.u-form-item--left {
// min-height: 76rpx;
// align-items: center !important;
// line-height: 42rpx;
}
}
.bg-page { .bg-page {
width: 100%; width: 100%;
min-height: 100%; min-height: 100%;

View File

@ -34,7 +34,7 @@ let isRefreshing = false;//多次锁
http.interceptors.response.use((response) => { /* 请求之后拦截器*/ http.interceptors.response.use((response) => { /* 请求之后拦截器*/
const { code } = response.data const { code } = response.data
console.log(response) if (code != 200) {
if (code == 4024) { if (code == 4024) {
toast(response.data.msg) toast(response.data.msg)
} else if (code == 401) { } else if (code == 401) {
@ -42,6 +42,9 @@ http.interceptors.response.use((response) => { /* 请求之后拦截器*/
} else { } else {
} }
return Promise.reject(response)
}
return response return response
}, (err) => { // 请求错误 }, (err) => { // 请求错误
const { code } = err.data const { code } = err.data

View File

@ -0,0 +1,69 @@
<template>
<u-popup v-model="show" mode="bottom" border-radius="20">
<view class="">
<view class="h-90rpx w-full flex justify-between items-center px-20rpx">
<slot name="head" :data="data">
<view class="text-hex-fa3534 text-base">
<text @click="handleDel" v-if="isDel"></text>
</view>
<view class="text-hex-2979ff text-base" v-if="isEdit">
<text @click="handleEdit"></text>
</view>
</slot>
</view>
<scroll-view scroll-y="true" class="max-h-1200rpx">
<view v-if="colums.length && data && Object.keys(data).length">
<view class="flex items-center" v-for="(item, i) in colums" :key="i">
<u-cell-item
:title="item.title"
:value="data[item.dataIndex]"
:arrow="false"
></u-cell-item>
</view>
</view>
</scroll-view>
</view>
</u-popup>
</template>
<script>
export default {
props: {
value: {
type: Boolean,
default: false,
},
data: {
type: Object,
default: () => {},
},
colums: {
type: Array,
default: () => [],
},
},
computed: {
show: {
get() {
return this.value
},
set(e) {
this.$emit('input', e)
},
},
isEdit() {
return !!this.$listeners.onEdit
},
isDel() {
return !!this.$listeners.onDel
},
},
methods: {
handleEdit() {
this.$emit('onEdit', this.data)
},
handleDel() {
this.$emit('onDel', this.data)
},
},
}
</script>

View File

@ -0,0 +1,52 @@
<template>
<u-popup v-model="show" closeable :width="width" :height="width" mode="center">
<view class="relative h-full flex flex-col overflow-hidden">
<view class="h-86rpx leading-86rpx flex-center w-full">
<slot name="title">
<view class="text-34rpx">{{ title }}</view>
</slot>
</view>
<view class="flex-1 overflow-y-auto w-full">
<slot></slot>
</view>
<view>
<slot name="bottom"></slot>
</view>
</view>
</u-popup>
</template>
<script>
export default {
props: {
value: {
type: Boolean,
default: false,
},
title: {
type: String,
default: '',
},
width: {
type: String,
default: '100%',
},
height: {
type: String,
default: '100%',
},
},
computed: {
show: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
},
},
},
data() {
return {}
},
}
</script>

View File

@ -214,6 +214,13 @@
"enablePullDownRefresh": false "enablePullDownRefresh": false
} }
},{
"path" : "pages/basics/town-base",
"style" :
{
"navigationBarTitleText": "城镇数据",
"enablePullDownRefresh": false
}
} }
], ],
"globalStyle": { "globalStyle": {

View File

@ -0,0 +1,289 @@
<template>
<view class="p-20rpx h-full overflow-hidden flex flex-col">
<view class="overflow-y-auto">
<u-form ref="uForm" class="cu-form" label-width="200">
<u-form-item v-for="(item, i) in template" :key="i" :label="item.name">
<template v-if="!item.isMore">
<view class="flex items-center flex-1">
<template v-if="item.component == 'InputTextArea'">
<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 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
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 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>
const defaultData = {
chart_nongye: {
label: '统计数据-农业',
unit: '万元',
},
chart_yuye: {
label: '统计数据-渔业',
unit: '万元',
},
chart_xumuye: {
label: '统计数据-畜牧业',
unit: '万元',
},
chart_lingye: {
label: '统计数据-林业',
unit: '万元',
},
chart_activity: {
label: '统计数据-其他',
unit: '万元',
},
}
import { concat, cloneDeep, template } from 'lodash-es'
const formList = [
{
field: 'id',
label: '街镇ID',
required: false,
component: 'Input',
readonly: true,
},
{
field: 'name',
label: '街镇名称',
required: true,
component: 'Input',
},
{
field: 'address',
label: '街镇地址',
required: true,
component: 'Input',
},
{
field: 'areas',
label: '街镇面积',
required: true,
component: 'Input',
},
{
field: 'cultivated',
label: '耕地面积',
required: true,
component: 'Input',
},
{
field: 'workforce',
label: '街镇人数',
required: true,
component: 'Input',
},
{
field: 'description',
label: '街镇介绍',
required: false,
component: 'InputTextArea',
},
]
export default {
props: {
data: {
type: Object,
default: () => {},
},
},
computed: {
isEdit() {
return !!this.data
},
},
data() {
return {
template: [],
form: {
id: '',
name: '',
address: '',
areas: '',
cultivated: '',
workforce: '',
description: '',
extends: '',
},
}
},
methods: {
isObject(val) {
return Object.prototype.toString.call(val) === '[object Object]'
},
isArray(val) {
return Object.prototype.toString.call(val) === '[object Array]'
},
addDomain(item) {
item.value.push({
value: '',
year: '',
})
},
removeDomain(item, index) {
item.value.splice(index, 1)
},
handleCancel() {
this.$emit('cancel')
},
async handleSubmit() {
const params = {}
this.template.forEach((e) => {
if (e.isMore) {
const temp = {}
e.value.forEach((el) => {
if (el.year) temp[el.year] = el.value
})
if (!params.extends) params.extends = {}
params['extends'][e.slug] = temp
} else {
params[e.slug] = e.value
}
})
await this.citydataEdit(params)
this.$emit('confirm')
},
async citydataEdit(params) {
try {
await this.$http.put(`api/agricultural-basic/${params.id}`, {
...params,
type: 2,
})
this.$u.toast('修改成功')
} catch ({ data }) {
this.$u.toast(data.message)
}
},
isObject(val) {
return Object.prototype.toString.call(val) === '[object Object]'
},
isArray(val) {
return Object.prototype.toString.call(val) === '[object Array]'
},
},
watch: {
data: {
handler(val) {
const data = val ?? {}
const defaultObj = {}
Object.keys(defaultData).forEach((item) => {
defaultObj[item] = data.extends[item] ?? {}
})
const tempData = Object.keys(defaultObj).reduce((pre, cur) => {
const currentData = defaultData[cur]
const obj = {
name: currentData.label,
unit: currentData.unit,
slug: cur,
}
const extend = defaultObj[cur]
if (this.isObject(extend) || this.isArray(extend)) {
const temp = []
if (Object.keys(extend).length === 0) {
temp.push({
value: '',
year: null,
})
}
for (const key in extend) {
temp.push({
value: extend[key],
year: key,
})
}
return concat(pre, {
...obj,
isMore: true,
value: temp,
})
}
}, [])
const extendsData = formList.reduce((pre, cur) => {
const currentData = data[cur.field]
const obj = {
isMore: false,
name: cur.label,
slug: cur.field,
value: currentData,
readonly: cur.readonly,
component: cur.component,
}
return pre.concat([obj])
}, [])
this.template = extendsData.concat(tempData)
},
immediate: true,
deep: true,
},
},
}
</script>

View File

@ -0,0 +1,170 @@
<template>
<view class="p-20rpx h-full overflow-hidden flex flex-col">
<view class="overflow-y-auto">
<u-form ref="uForm" class="cu-form" label-width="200">
<u-form-item v-for="(item, i) in template" :key="i" :label="item.name">
<template v-if="!item.isMore">
<view class="flex items-center">
<u-input
border
v-model="item.value"
:suffix="item.unit"
placeholder="请输入"
/>
<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
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 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 { concat, cloneDeep } from 'lodash-es'
export default {
props: {
data: {
type: Array,
default: () => [],
},
},
data() {
return {
template: [],
}
},
methods: {
handleCancel() {
this.$emit('cancel')
},
async handleSubmit() {
const params = {}
this.template.forEach((e) => {
if (e.isMore) {
const temp = {}
e.value.forEach((el) => {
if (el.year) temp[el.year] = el.value
})
params[e.slug] = temp
} else {
params[e.slug] = e.value
}
})
await this.citydataEdit(params)
this.$emit('confirm')
},
async citydataEdit(params) {
try {
await this.$http.put('/api/citydata-statistics-edit', params)
} catch (error) {
this.$u.toast(error.message)
}
},
isObject(val) {
return Object.prototype.toString.call(val) === '[object Object]'
},
isArray(val) {
return Object.prototype.toString.call(val) === '[object Array]'
},
addDomain(item) {
item.value.push({
value: '',
year: '',
})
},
removeDomain(item, index) {
item.value.splice(index, 1)
},
},
watch: {
data: {
handler(val) {
const arr = cloneDeep(val)
const template = arr.reduce((pre, cur) => {
const obj = {
name: cur.name,
slug: cur.slug,
unit: cur.unit,
}
if (this.isObject(cur.value) || this.isArray(cur.value)) {
// cur.value[2023] = ''
const temp = []
// if(Object.keys(cur.value).length === 1))
if (Object.keys(cur.value).length === 0) {
temp.push({
value: '',
year: null,
})
}
for (const key in cur.value) {
temp.push({
value: cur.value[key],
// year: dayjs(key + '', 'YYYY'),
year: key,
})
}
return concat(pre, {
...obj,
isMore: true,
value: temp,
})
}
return concat(pre, {
...obj,
isMore: false,
value: cur.value,
})
}, [])
this.template = template
},
immediate: true,
deep: true,
},
},
}
</script>
<style lang="scss"></style>

View File

@ -0,0 +1,21 @@
<template>
<view class="border-0.5px border-solid p-20rpx">
<div class="flex">
<view>{{ data.name }}</view>
</div>
<view class="mt-20rpx">
<text class="text-42rpx font-bold">{{ data.value }}</text>
<text class="text-24rpx ml-4rpx">{{ data.unit }}</text>
</view>
</view>
</template>
<script>
export default {
props: {
data: {
type: Object,
default: () => {},
},
},
}
</script>

View File

@ -0,0 +1,249 @@
<template>
<view>
<view class="bg-white p-30rpx">
<view class="flex justify-between items-center">
<view class="text-32rpx">全市数据统计</view>
<u-button size="mini" @click="cityEditShow = true">编辑</u-button>
</view>
<view class="grid grid-cols-2 mt-20rpx">
<CountItem
v-for="(item, i) in showCityList"
:key="i"
:data="item"
></CountItem>
</view>
</view>
<view class="w-full h-20rpx"></view>
<u-sticky>
<view class="bg-white">
<view class="flex items-center p-20rpx">
<u-input
v-model="filter.name"
placeholder="请输入名称"
class="w-full"
></u-input>
<u-button size="medium" @click="onFilterSubmit"></u-button>
</view>
</view>
</u-sticky>
<mescroll-body
@init="mescrollInit"
@up="upCallback"
:up="upOption"
:down="downOption"
>
<u-swipe-action
v-for="(item, i) in dataList"
:show="item.show"
:index="i"
:key="i"
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.address }}</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>
</mescroll-body>
<!-- 全市数据统计编辑 -->
<cuPopup v-model="cityEditShow" title="编辑统计">
<CountEdit
:data="cityList"
@cancel="cityEditShow = false"
@confirm="handleCityEditConfirm"
></CountEdit>
</cuPopup>
<cuPopup v-model="cityItemShow" title="编辑街镇">
<CityEdit
:data="currentData"
@cancel="cityItemShow = false"
@confirm="handleCityConfirm"
></CityEdit>
</cuPopup>
<BaseTablePopup
v-model="baseTablePopupShow"
@onEdit="handleEdit"
:colums="baseTableColums"
:data="currentData"
>
</BaseTablePopup>
</view>
</template>
<script>
import CountItem from './components/town-count-item.vue'
import cuPopup from '@/components/cu-popup/index.vue'
import CountEdit from './components/town-count-edit.vue'
import BaseTablePopup from '@/components/base-table/popup.vue'
import CityEdit from './components/town-city-edit'
const filterCityCount = [
'city_data_chart_nongye',
'city_data_chart_yuye',
'city_data_chart_xumuye',
'city_data_chart_lingye',
'city_data_chart_activity',
]
const baseTableColums = [
{
title: '街镇名称',
dataIndex: 'name',
},
{
title: '街镇地址',
dataIndex: 'address',
},
{
title: '街镇面积',
dataIndex: 'areas',
},
{
title: '耕地面积',
dataIndex: 'cultivated',
},
{
title: '街镇人数',
dataIndex: 'workforce',
},
{
title: '街镇描述',
dataIndex: 'description',
},
]
import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js'
export default {
mixins: [MescrollMixin],
components: {
CountItem,
cuPopup,
CountEdit,
BaseTablePopup,
CityEdit,
},
computed: {
showCityList() {
return this.cityList.filter(
(item) => !filterCityCount.includes(item.slug)
)
},
},
data() {
return {
baseTablePopupShow: false,
baseTableColums,
cityItemShow: false,
options: [
{
text: '编辑',
style: {
backgroundColor: '#007aff',
},
},
],
cityList: [],
cityEditShow: false,
dataList: [],
downOption: {
use: false,
},
upOption: {
auto: true,
page: {
size: 20,
},
},
filter: {
name: '',
type: 2,
},
currentData: null,
}
},
onLoad() {
this.getCityData()
},
methods: {
handleEdit(e) {
this.currentData = e
this.baseTablePopupShow = false
this.cityItemShow = true
},
onFilterSubmit() {
this.mescroll.resetUpScroll()
},
handleClick(index1, index) {
this.currentData = this.dataList[index1]
this.cityItemShow = true
console.log(index1, index)
},
handleContentClick(e) {
this.currentData = this.dataList[e]
this.baseTablePopupShow = true
},
upCallback({ num, size }) {
this.getData({
...this.filter,
page: num,
per_page: size,
})
},
async getData(params) {
try {
const { data } = await this.$http.get(`/api/agricultural-basic`, {
params,
})
if (params.page == 1) this.dataList = []
const { data: list, meta } = data
this.dataList = this.dataList.concat(list)
this.mescroll.endByPage(list.length, meta.total)
} catch (error) {
this.mescroll.endErr()
}
},
//
async getCityData() {
try {
const { data } = await this.$http.get('/api/citydata-statistics')
const { data: resData } = data
this.cityList = resData
} catch (error) {}
},
handleCityEditConfirm() {
this.cityEditShow = false
this.getCityData()
},
handleCityConfirm() {
this.cityItemShow = false
this.mescroll.resetUpScroll()
},
// /api/agricultural-basic?type=2&page=1&per_page=20
},
}
</script>

View File

@ -77,6 +77,7 @@
children:[ children:[
{ {
label:'城镇数据', label:'城镇数据',
url:'/pages/basics/town-base'
}, },
{ {
label:'基地数据', label:'基地数据',