Compare commits

...

4 Commits

Author SHA1 Message Date
ihzero 12da016e25 打包 2023-09-13 09:27:31 +08:00
ihzero a8d7b6de00 添加基础数据 2023-09-13 05:50:39 +08:00
ihzero e1e4dcce03 城镇基础数据 2023-09-13 02:37:06 +08:00
ihzero b9845d3065 城镇基础数据 2023-09-12 21:08:29 +08:00
77 changed files with 4217 additions and 244 deletions

3
.gitignore vendored
View File

@ -1,7 +1,8 @@
.DS_Store
node_modules/
unpackage/
dist/
dist/build/*
!dist/build/h5
# local env files
.env.local

2
dist/build/h5/index.html vendored 100644
View File

@ -0,0 +1,2 @@
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title></title><script>var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')</script><link rel="stylesheet" href="/static/index.97465e7b.css"></head><body><noscript><strong>Please enable JavaScript to continue.</strong></noscript><div id="app"></div><script src="/static/js/chunk-vendors.6e372103.js"></script><script src="/static/js/index.d13f8774.js"></script></body></html>

File diff suppressed because one or more lines are too long

BIN
dist/build/h5/static/head.png vendored 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["pages-user-password-edit"],{"0771":function(n,t,o){"use strict";o.d(t,"b",(function(){return a})),o.d(t,"c",(function(){return e})),o.d(t,"a",(function(){return s}));var s={uForm:o("aa8f").default,uFormItem:o("e0a3").default,uInput:o("d5da").default,uButton:o("d9ad").default},a=function(){var n=this,t=n.$createElement,o=n._self._c||t;return o("v-uni-view",{staticClass:"password-page"},[o("u-form",{ref:"uForm",attrs:{model:n.form}},[o("u-form-item",{attrs:{label:"密码:","label-width":"100"}},[o("u-input",{attrs:{type:n.type,"password-icon":n.passwordIcon,clearable:!0},model:{value:n.form.password,callback:function(t){n.$set(n.form,"password",t)},expression:"form.password"}})],1),o("u-form-item",{attrs:{label:"确认密码:","label-width":"150"}},[o("u-input",{attrs:{type:n.type,"password-icon":n.passwordIcon,clearable:!0},model:{value:n.form.password_confirmation,callback:function(t){n.$set(n.form,"password_confirmation",t)},expression:"form.password_confirmation"}})],1),o("v-uni-view",{staticClass:"btns",staticStyle:{"margin-top":"68rpx"}},[o("u-button",{attrs:{type:"primary"},on:{click:function(t){arguments[0]=t=n.$handleEvent(t),n.passwordEditFn()}}},[n._v("确定")])],1)],1)],1)},e=[]},"37df":function(n,t,o){"use strict";o.r(t);var s=o("0771"),a=o("b082");for(var e in a)["default"].indexOf(e)<0&&function(n){o.d(t,n,(function(){return a[n]}))}(e);o("ad0e");var r,i=o("f0c5"),u=Object(i["a"])(a["default"],s["b"],s["c"],!1,null,"c5bae556",null,!1,s["a"],r);t["default"]=u.exports},"413f":function(n,t,o){var s=o("24fb");t=s(!1),t.push([n.i,'@charset "UTF-8";\n/**\n * 这里是uni-app内置的常用样式变量\n *\n * uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量\n * 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App\n *\n */\n/**\n * 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能\n *\n * 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件\n */\n/* 颜色变量 */\n/* 行为相关颜色 */\n/* 文字基本颜色 */\n/* 背景颜色 */\n/* 边框颜色 */\n/* 尺寸变量 */\n/* 文字尺寸 */\n/* 图片尺寸 */\n/* Border Radius */\n/* 水平间距 */\n/* 垂直间距 */\n/* 透明度 */\n/* 文章场景相关 */.password-page[data-v-c5bae556]{padding:%?32?%}',""]),n.exports=t},5947:function(n,t,o){var s=o("413f");s.__esModule&&(s=s.default),"string"===typeof s&&(s=[[n.i,s,""]]),s.locals&&(n.exports=s.locals);var a=o("4f06").default;a("c342612e",s,!0,{sourceMap:!1,shadowMode:!1})},"95f7":function(n,t,o){"use strict";o("7a82"),Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var s=o("815d"),a={data:function(){return{form:{password:"",password_confirmation:""},type:"password",passwordIcon:!0}},onLoad:function(){},methods:{passwordEditFn:function(){console.log(this.form),this.form.password?this.form.password_confirmation?this.form.password==this.form.password_confirmation?((0,s.showLoading)("请稍等..."),this.$http.put("/api/users/reset-password",this.form).then((function(n){var t=n.data;(0,s.hideLoading)(),console.log(t),200==t.code?uni.showToast({title:"修改成功",icon:"none"}):uni.showToast({title:t.message,icon:"none"})})).catch((function(){(0,s.hideLoading)()}))):uni.showToast({title:"两次密码不一致",icon:"none"}):uni.showToast({title:"请输入确认密码",icon:"none"}):uni.showToast({title:"请输入新密码",icon:"none"})}}};t.default=a},ad0e:function(n,t,o){"use strict";var s=o("5947"),a=o.n(s);a.a},b082:function(n,t,o){"use strict";o.r(t);var s=o("95f7"),a=o.n(s);for(var e in s)["default"].indexOf(e)<0&&function(n){o.d(t,n,(function(){return s[n]}))}(e);t["default"]=a.a}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -31,6 +31,15 @@ export default {
body, uni-page-body {
background-color: #f8f8f8;
}
.cu-form {
.u-form-item--left {
// min-height: 76rpx;
// align-items: center !important;
// line-height: 42rpx;
}
}
.bg-page {
width: 100%;
min-height: 100%;
@ -637,4 +646,10 @@ body, uni-page-body {
}
}
}
.dropdownClose{
.u-dropdown__content{
pointer-events: none;
}
}
</style>

View File

@ -1,6 +1,6 @@
import Request from './luch-request/index.js'
import jwt from './jwt.js'
import {toast} from '@/com/utils.js'
import { toast } from '@/com/utils.js'
//测试地址
// const baseApi = 'http://36.133.205.221:81';
const baseApi = 'http://lcny.sk797.cn';
@ -9,59 +9,62 @@ const http = new Request();
http.setConfig((config) => { /* 设置全局配置 */
config.baseURL = baseApi
config.header = {
...config.header,
'Accept': 'application/json'
...config.header,
'Accept': 'application/json'
}
config.custom = {
auth: true, // 是否传token
// loading: false // 是否使用loading
}
config.imeout = 30000
return config
})
/* 请求之前拦截器 */
http.interceptors.request.use((config, cancel) => {
if (config.custom.auth) {
// 需要权限认证的路由 需携带自定义参数 {custom: {auth: true}}
config.header.Authorization = 'Bearer '+jwt.getAccessToken();
// 需要权限认证的路由 需携带自定义参数 {custom: {auth: true}}
config.header.Authorization = 'Bearer ' + jwt.getAccessToken();
}
return config
})
/* 请求之后拦截器 */
/* 请求之后拦截器 */
let isRefreshing = false;//多次锁
http.interceptors.response.use((response) => { /* 请求之后拦截器*/
const {code} = response.data
console.log(response)
if(code ==4024){
toast(response.data.msg)
}else if(code ==401){
toast('请关闭,重新进入')
} else{
const { code } = response.data
if (code != 200) {
if (code == 4024) {
toast(response.data.msg)
} else if (code == 401) {
toast('请关闭,重新进入')
} else {
}
return Promise.reject(response)
}
return response
}, (err) => { // 请求错误
const {code} = err.data
console.log(code)
if(code == 401){//过期未登录
const config = err.config
if(!isRefreshing){
isRefreshing = true
}else{
}
}else {
}
console.log(err,'======')
return Promise.reject(err)
const { code } = err.data
console.log(code)
if (code == 401) {//过期未登录
const config = err.config
if (!isRefreshing) {
isRefreshing = true
} else {
}
} else {
}
console.log(err, '======')
return Promise.reject(err)
})
const getFullUrl = (url,params,header) => {
return http.post(url, params,{...header});
const getFullUrl = (url, params, header) => {
return http.post(url, params, { ...header });
};
export {
http,

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

@ -0,0 +1,93 @@
<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 columsList"
:key="i"
>
<slot :name="item.dataIndex" :data="item">
<u-cell-item
:title="item.title"
:value="item.value.toString()"
:arrow="false"
></u-cell-item>
</slot>
</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
},
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: {
isFunction(fn) {
return typeof fn === 'function'
},
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

@ -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,126 @@
<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,
isFirstLoad: true,
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) {
if (!e.length) return
const { value } = e[0]
if (value == null) return
this.$emit('change', value)
this.$emit('input', value)
},
isFunction(fn) {
return typeof fn === 'function'
},
},
watch: {
params: {
handler() {
!this.isFirstLoad && this.fetch()
},
deep: true,
},
},
}
</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

@ -0,0 +1,84 @@
<template>
<view class="w-full">
<view @click="show = true">
<u-input
class="w-full !pointer-events-none"
:placeholder="placeholder"
:value="status"
type="select"
/>
</view>
<u-picker
@confirm="handleConfirm"
mode="time"
v-model="show"
:params="{ year: true }"
></u-picker>
</view>
</template>
<script>
import { omit } from 'lodash-es'
export default {
props: {
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,
isFirstLoad: true,
status: '',
}
},
computed: {},
created() {
this.fetch()
},
methods: {
async fetch() {},
emitChange() {
this.$emit('options-change', this.getOptions)
},
handleConfirm(e) {
let str = ''
Object.keys(e).forEach((key) => {
str += e[key]
})
this.status = str
this.$emit('change', str)
this.$emit('input', str)
},
isFunction(fn) {
return typeof fn === 'function'
},
},
watch: {
value: {
handler(e) {
this.status = e
},
deep: true,
immediate: true,
},
},
}
</script>

View File

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

View File

@ -1,3 +1,107 @@
<template>
<u-dropdown-item title="se"></u-dropdown-item>
</template>
<u-dropdown-item
:title="label"
v-model="status"
@change="handleChange"
:options="getOptions"
></u-dropdown-item>
</template>
<script>
import { omit } from 'lodash-es'
export default {
props: {
options: {
type: Array,
default: () => [],
},
label: {
type: String,
default: '',
},
value: {
type: [Array, Object, String, Number],
},
params: {
type: Object,
default: () => ({}),
},
labelField: {
type: String,
default: 'label',
},
valueField: {
type: String,
default: 'value',
},
},
computed: {
status: {
get() {
return this.value
},
set(val) {
this.$emit('change', val)
this.$emit('input', val)
},
},
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
}, [])
},
},
data() {
return {
emitData: null,
isFirstLoad: true,
}
},
created() {
this.fetch()
},
methods: {
async fetch() {
const data = this.options
try {
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)
},
handleChange(e) {
const args = this.getOptions.filter((item) => item.value == e)
this.emitData = args
},
isFunction(fn) {
return typeof fn === 'function'
},
},
watch: {
params: {
handler() {
//
!this.isFirstLoad && this.fetch()
},
deep: true,
},
},
}
</script>

View File

@ -0,0 +1,122 @@
<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: {
options: {
type: Array,
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,
isFirstLoad: true,
}
},
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 data = this.options
try {
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) {
if (!e.length) return
const { value } = e[0]
if (value == null) return
this.$emit('change', value)
this.$emit('input', value)
},
isFunction(fn) {
return typeof fn === 'function'
},
},
watch: {
params: {
handler() {
!this.isFirstLoad && this.fetch()
},
deep: true,
},
},
}
</script>

View File

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

View File

@ -214,6 +214,53 @@
"enablePullDownRefresh": false
}
},{
"path" : "pages/basics/town-base",
"style" :
{
"navigationBarTitleText": "城镇数据",
"enablePullDownRefresh": false
}
},{
"path" : "pages/basics/basics-base",
"style" :
{
"navigationBarTitleText": "基地数据",
"enablePullDownRefresh": false,
"navigationStyle":"custom"
}
},{
"path" : "pages/crop/town-crop",
"style" :
{
"navigationBarTitleText": "城镇农作物",
"enablePullDownRefresh": false,
"navigationStyle":"custom"
}
},{
"path" : "pages/crop/basics-crop",
"style" :
{
"navigationBarTitleText": "基地农作物",
"enablePullDownRefresh": false,
"navigationStyle":"custom"
}
},{
"path" : "pages/yield/town-yield",
"style" :
{
"navigationBarTitleText": "城镇产量",
"enablePullDownRefresh": false,
"navigationStyle":"custom"
}
},{
"path" : "pages/yield/basics-yield",
"style" :
{
"navigationBarTitleText": "基地产量",
"enablePullDownRefresh": false,
"navigationStyle":"custom"
}
}
],
"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,218 @@
<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) {
await this.onUpdate(params)
} else {
await 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) {
if (val) {
this.setDefaultForm(val)
}
},
immediate: true,
deep: true,
},
},
}
</script>

View File

@ -0,0 +1,305 @@
<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" 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>
</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>
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,188 @@
<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" 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>
</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 { 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,248 @@
<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
},
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

@ -0,0 +1,237 @@
<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 class="flex">
<view class="flex-1">单位{{ item.unit }}</view>
<view class="flex-1"
>是否是结点{{ item.is_end ? '是' : '否' }}</view
>
</view>
</view>
</view>
</u-swipe-action>
</view>
</mescroll-body>
<!-- 详情 -->
<BaseTablePopup
v-model="baseShow"
:colums="baseTableColums"
:data="currentData"
@onEdit="handleEdit"
@onDel="handleDel"
>
<!-- <template #extends="{ data }">
<view
class="flex justify-between w-full px-30rpx py-20rpx"
v-for="(item, i) in data.value"
:key="i"
>
<view> 名称{{ item.name }}</view>
<view> 单位{{ item.unit }}</view>
</view>
</template> -->
</BaseTablePopup>
<!-- 编辑 -->
<cuPopup v-model="formShow" :title="currentData ? '编辑农作物' : '新增农作物'">
<BasicsEdit
@cancel="formShow = false"
@confirm="handleEditConfirm"
:data="currentData"
:crop_type="1"
></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: 'unit',
},
{
title: '是否是结点',
dataIndex: 'is_end',
format: (text) => {
return text == 1 ? '是' : '否'
},
},
// {
// title: '',
// dataIndex: 'extends',
// },
]
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: '请输入名称',
},
},
],
}
},
methods: {
handleSubmit(e) {
this.filterParmas = e
this.mescroll.resetUpScroll()
},
upCallback({ num, size }) {
this.getData({
...this.filterParmas,
page: num,
per_page: size,
type: 'all',
crop_type: 1,
})
},
async getData(e) {
try {
const { data } = await http.get(`/api/crops`, {
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/crops/${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,229 @@
<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="产业">
<ApiSelect
v-model="form.category_id"
v-bind="categorySelectOption"
></ApiSelect>
</u-form-item>
<u-form-item label="名称">
<u-input v-model="form.name"></u-input>
</u-form-item>
<u-form-item label="上级">
<ApiSelect
v-model="form.parent_id"
v-bind="parentSelectOption"
@options-change="handleParentChange"
></ApiSelect>
</u-form-item>
<u-form-item label="单位">
<u-input v-model="form.unit"></u-input>
</u-form-item>
<u-form-item label="是否是结点">
<u-switch v-model="form.is_end"></u-switch>
</u-form-item>
<u-form-item v-if="form.is_end" label="">
<view>
<view
class="w-full flex my-10rpx"
v-for="(arr, j) in form.extends"
:key="j"
>
<view class="flex-1 mr-20rpx">
<u-input
:clearable="false"
border
v-model="arr.name"
placeholder="请输入名称"
/>
</view>
<view class="flex-1 flex items-center">
<u-input
:clearable="false"
border
v-model="arr.unit"
placeholder="请输入单位"
/>
</view>
<view v-if="j == 0" class="px-10rpx">
<u-icon @click="addDomain()" name="plus" size="34"></u-icon>
</view>
<view class="px-10rpx" v-else>
<u-icon
@click="removeDomain(j)"
name="minus"
size="34"
></u-icon>
</view>
</view>
</view>
</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 categorySelectOption = {
api: async (e) => {
const { data } = await http.get('/api/keywords-crops-cate', {
params: e,
})
return data.data
},
labelField: 'name',
valueField: 'id',
}
const parentSelectOption = {
api: async (e) => {
const { data } = await http.get('/api/crops', {
params: e,
})
return data.data.filter(({ is_end }) => is_end != 1)
},
labelField: 'name',
valueField: 'id',
}
export default {
props: {
data: {
type: Object,
default: () => {},
},
crop_type: {
type: Number,
default: 2,
},
},
components: {
ApiSelect,
ApiCheckbox,
},
computed: {
isEdit() {
return !!this.data
},
parentSelectOption() {
return {
...parentSelectOption,
params: {
type: 'all',
crop_type: this.crop_type,
category: this.form.category_id,
},
}
},
},
data() {
return {
categorySelectOption,
form: {
id: '',
category_id: '',
name: '',
parent_id: '',
unit: '',
is_end: false,
extends: [
{
name: '',
unit: '',
},
],
},
}
},
methods: {
addDomain() {
this.form.extends.push({
name: '',
unit: '',
})
},
removeDomain(index) {
this.form.extends.splice(index, 1)
},
handleParentChange(e) {
// this.form.parent_id = ''
},
handleCancel() {
this.$emit('cancel')
},
async handleSubmit() {
const params = { ...this.form, crop_type: this.crop_type }
if (this.isEdit) {
await this.onUpdate(params)
} else {
await this.onCreate(params)
}
this.$emit('confirm')
},
async onUpdate(params) {
try {
await this.$http.put(`/api/crops/${params.id}`, params)
this.$u.toast('操作成功')
} catch ({ data }) {
data && this.$u.toast(data?.message)
}
},
async onCreate(params) {
try {
await this.$http.post('/api/crops', params)
this.$u.toast('操作成功')
} catch ({ data }) {
data && this.$u.toast(data?.message)
}
},
async setDefaultForm(e) {
const { data } = await this.$http.get(`/api/crops/${e.id}`)
const { data: resData } = data
Object.keys(e).forEach((key) => {
let value = e[key]
if (key == 'is_end') value = value == 1
if (key == 'extends') {
if (value.length == 0) value = [{ name: '', unit: '' }]
}
if (this.form[key] !== undefined) this.form[key] = value
})
this.form.category_id = resData?.category?.id
this.form.parent_id = resData?.parent_id > 0 ? resData?.parent_id : null
},
},
watch: {
data: {
handler(val) {
console.log(val)
if (val) {
this.setDefaultForm(val)
}
},
immediate: true,
deep: true,
},
},
}
</script>

View File

@ -0,0 +1,236 @@
<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 class="flex">
<view class="flex-1">单位{{ item.unit }}</view>
<view class="flex-1"
>是否是结点{{ item.is_end ? '是' : '否' }}</view
>
</view>
</view>
</view>
</u-swipe-action>
</view>
</mescroll-body>
<!-- 详情 -->
<BaseTablePopup
v-model="baseShow"
:colums="baseTableColums"
:data="currentData"
@onEdit="handleEdit"
@onDel="handleDel"
>
<!-- <template #extends="{ data }">
<view
class="flex justify-between w-full px-30rpx py-20rpx"
v-for="(item, i) in data.value"
:key="i"
>
<view> 名称{{ item.name }}</view>
<view> 单位{{ item.unit }}</view>
</view>
</template> -->
</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: 'unit',
},
{
title: '是否是结点',
dataIndex: 'is_end',
format: (text) => {
return text == 1 ? '是' : '否'
},
},
// {
// title: '',
// dataIndex: 'extends',
// },
]
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: '请输入名称',
},
},
],
}
},
methods: {
handleSubmit(e) {
this.filterParmas = e
this.mescroll.resetUpScroll()
},
upCallback({ num, size }) {
this.getData({
...this.filterParmas,
page: num,
per_page: size,
type: 'all',
crop_type: 2,
})
},
async getData(e) {
try {
const { data } = await http.get(`/api/crops`, {
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/crops/${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,213 +1,225 @@
<template>
<view class="index-page bg-page">
<view class="banner-section">
<image class="banner_img" mode="scaleToFill" src="../../static/img/banner_img.png"></image>
</view>
<view class="content-box">
<view class="menus-section" v-for="(menu,index) in menuList" :key="index">
<view class="title-t" v-if="menu.parent">{{menu.parent}}-{{menu.label}}</view>
<view class="title-t" v-else>{{menu.label}}</view>
<view class="menu-ul">
<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>
<view class="index-page bg-page">
<view class="banner-section">
<image
class="banner_img"
mode="scaleToFill"
src="../../static/img/banner_img.png"
></image>
</view>
<view class="content-box">
<view
class="menus-section"
v-for="(menu, index) in menuList"
:key="index"
>
<view class="title-t" v-if="menu.parent"
>{{ menu.parent }}-{{ menu.label }}</view
>
<view class="title-t" v-else>{{ menu.label }}</view>
<view class="menu-ul">
<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>
<script>
export default {
data() {
return {
title: 'Hello',
menuList:[
{
label:'监测数据管理',
children:[
{
label:'气象监测',
url:"/pages/index/meteorological"
},
{
label:'智能监控',
url:'/pages/index/monitor'
},
{
label:'土壤监控',
url:'/pages/index/soil-monitoring'
},
{
label:'水质监控',
url:'/pages/index/water-quality'
},
{
label:'昆虫性诱监测',
url:'/pages/index/insect-monitors'
},
{
label:'虫情监测',
url:'/pages/index/pests'
},
{
label:'杀虫灯检测',
url:'/pages/index/insecticidal-lamp'
},
],
},
// {
// label:'',
// children:[
// {
// label:'',
// },
// {
// label:'',
// },
// ],
// },
{
label:'全市基础数据',
parent:'基础数据管理',
children:[
{
label:'城镇数据',
},
{
label:'基地数据',
},
],
},
{
label:'农作物数据',
parent:'基础数据管理',
children:[
{
label:'城镇农作物',
},
{
label:'基地农作物',
}
],
},
{
label:'农作物产量',
parent:'基础数据管理',
children:[
{
label:'城镇产量',
},
{
label:'基地产量',
},
],
},
{
label:'重点产业',
parent:'基础数据管理',
children:[
{
label:'稻虾价格',
url:'/pages/estate/estate-price'
},
{
label:'稻虾每周价格',
url:'/pages/estate/estate-week-price'
},
{
label:'稻虾产业',
url:'/pages/estate/estate-industry'
},
{
label:'稻虾流向',
url:'/pages/estate/estate-flows'
},
{
label:'大宗物资',
url:'/pages/estate/estate-materiels'
},
]
},
{
label:'设备管理',
children:[
{
label:'设备管理',
url:'/pages/device/index'
},
{
label:'警报明细',
url:'/pages/device/warning'
}
],
},
]
}
},
onLoad() {
},
methods: {
linknavFn(item){
console.log(item)
uni.navigateTo({
url:`${item.url}`
})
}
}
}
export default {
data() {
return {
title: 'Hello',
menuList: [
{
label: '监测数据管理',
children: [
{
label: '气象监测',
url: '/pages/index/meteorological',
},
{
label: '智能监控',
url: '/pages/index/monitor',
},
{
label: '土壤监控',
url: '/pages/index/soil-monitoring',
},
{
label: '水质监控',
url: '/pages/index/water-quality',
},
{
label: '昆虫性诱监测',
url: '/pages/index/insect-monitors',
},
{
label: '虫情监测',
url: '/pages/index/pests',
},
{
label: '杀虫灯检测',
url: '/pages/index/insecticidal-lamp',
},
],
},
// {
// label:'',
// children:[
// {
// label:'',
// },
// {
// label:'',
// },
// ],
// },
{
label: '全市基础数据',
parent: '基础数据管理',
children: [
{
label: '城镇数据',
url: '/pages/basics/town-base',
},
{
label: '基地数据',
url: '/pages/basics/basics-base',
},
],
},
{
label: '农作物数据',
parent: '基础数据管理',
children: [
{
label: '城镇农作物',
url: '/pages/crop/town-crop',
},
{
label: '基地农作物',
url: '/pages/crop/basics-crop',
},
],
},
{
label: '农作物产量',
parent: '基础数据管理',
children: [
{
label: '城镇产量',
url: '/pages/yield/town-yield',
},
{
label: '基地产量',
url: '/pages/yield/basics-yield',
},
],
},
{
label: '重点产业',
parent: '基础数据管理',
children: [
{
label: '稻虾价格',
url: '/pages/estate/estate-price',
},
{
label: '稻虾每周价格',
url: '/pages/estate/estate-week-price',
},
{
label: '稻虾产业',
url: '/pages/estate/estate-industry',
},
{
label: '稻虾流向',
url: '/pages/estate/estate-flows',
},
{
label: '大宗物资',
url: '/pages/estate/estate-materiels',
},
],
},
{
label: '设备管理',
children: [
{
label: '设备管理',
url: '/pages/device/index',
},
{
label: '警报明细',
url: '/pages/device/warning',
},
],
},
],
}
},
onLoad() {},
methods: {
linknavFn(item) {
console.log(item)
uni.navigateTo({
url: `${item.url}`,
})
},
},
}
</script>
<style lang="scss" scoped>
.banner-section{
.banner_img{
width: 100%;
height: 280rpx;
}
.banner-section {
.banner_img {
width: 100%;
height: 280rpx;
}
}
.index-page{
background-color: #f8f8f8;
.content-box{
padding-top: 30rpx;
padding-bottom: 150rpx;
}
.index-page {
background-color: #f8f8f8;
.content-box {
padding-top: 30rpx;
padding-bottom: 150rpx;
}
}
.menus-section{
padding: 20rpx;
font-size: 28rpx;
margin-top: -18rpx;
.title-t{
margin-bottom: 24rpx;
padding: 0 10rpx;
font-size: 28rpx;
font-weight: bold;
}
.menus-section {
padding: 20rpx;
font-size: 28rpx;
margin-top: -18rpx;
.title-t {
margin-bottom: 24rpx;
padding: 0 10rpx;
font-size: 28rpx;
font-weight: bold;
}
}
.menu-ul{
display: flex;
flex-wrap: wrap;
.menu-li{
flex: 0 0 25%;
text-align: center;
padding: 0 10rpx;
margin-bottom: 18rpx;
.menu_item{
background-color: #fff;
box-shadow:0 0 20rpx rgba(0,0,0,0.15);
min-height: 90rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10rpx 15rpx;
height: 100%;
}
}
.menu-ul {
display: flex;
flex-wrap: wrap;
.menu-li {
flex: 0 0 25%;
text-align: center;
padding: 0 10rpx;
margin-bottom: 18rpx;
.menu_item {
background-color: #fff;
box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.15);
min-height: 90rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10rpx 15rpx;
height: 100%;
}
}
}
</style>

View File

@ -0,0 +1,281 @@
<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.base_name }} </view>
<view>农作物名称{{ item.crop_name }}</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.yield }}</view>
<view class="text-center">{{ item.output }}</view>
<view class="text-center">{{ item.cultivated }}</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
:type="1"
@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: 'base_name',
},
{
title: '农作物名称',
dataIndex: 'crop_name',
},
{
title: '年份',
dataIndex: 'time_year',
format: (text) => {
return text + '年'
},
},
{
title: '季度',
dataIndex: 'quarter',
format: (e) => {
const map = {
1: '第一季度',
2: '第二季度',
3: '第三季度',
4: '第四季度',
}
return map[e]
},
},
{
title: '产量',
dataIndex: 'yield',
},
{
title: '产值',
dataIndex: 'output',
},
{
title: '耕种面积',
dataIndex: 'cultivated',
},
]
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: 'quarter',
label: '季度',
component: 'Select',
componentProps: {
options: [
{ label: '第一季度', value: '1' },
{ label: '第二季度', value: '2' },
{ label: '第三季度', value: '3' },
{ label: '第四季度', value: '4' },
],
},
},
{
field: 'type',
label: '农作物',
component: 'ApiSelect',
componentProps: ({ formActionType }) => {
return {
api: async (e) => {
const { data } = await http.get('/api/crops', {
params: e,
})
return data.data
},
labelField: 'name',
valueField: 'id',
params: {
type: 'all',
crop_type: 1,
},
}
},
},
],
}
},
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/crop-yields`, {
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/crop-yields/${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,193 @@
<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="农作物">
<ApiSelect
v-model="form.crop_id"
v-bind="cropSelectOption"
></ApiSelect>
</u-form-item>
<u-form-item label="区域">
<ApiSelect
v-model="form.base_id"
v-bind="baseSelectOption"
></ApiSelect>
</u-form-item>
<u-form-item label="年份">
<Picker v-model="form.time_year"></Picker>
</u-form-item>
<u-form-item label="季度">
<Select v-model="form.quarter" v-bind="quarterOption"></Select>
</u-form-item>
<u-form-item label="产量">
<u-input v-model="form.yield"></u-input>
</u-form-item>
<u-form-item label="产值">
<u-input v-model="form.output"></u-input>
</u-form-item>
<u-form-item label="耕种面积">
<u-input v-model="form.cultivated"></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'
import Select from '@/components/search-form/components/Select1.vue'
import Picker from '@/components/search-form/components/Picker.vue'
const quarterOption = {
options: [
{ label: '第一季度', value: '1' },
{ label: '第二季度', value: '2' },
{ label: '第三季度', value: '3' },
{ label: '第四季度', value: '4' },
],
}
export default {
props: {
data: {
type: Object,
default: () => {},
},
type:{
type: Number,
default: 1,
}
},
components: {
ApiSelect,
ApiCheckbox,
Select,
Picker,
},
computed: {
isEdit() {
return !!this.data
},
cropSelectOption() {
return {
api: async (e) => {
const { data } = await http.get('/api/crops', {
params: e,
})
return data.data
},
labelField: 'name',
valueField: 'id',
params: {
type: 'all',
// crop_type: this.type,
},
}
},
baseSelectOption() {
return {
api: async (e) => {
const { data } = await http.get('/api/agricultural-basic', {
params: e,
})
return data.data
},
labelField: 'name',
valueField: 'id',
params: {
// type: this.type,
page: 1,
per_page: 99999,
},
}
},
},
data() {
return {
quarterOption,
form: {
id: '',
crop_id: '',
base_id: '',
time_year: '',
quarter: '',
yield: '',
output: '',
cultivated: '',
},
}
},
methods: {
handleCancel() {
this.$emit('cancel')
},
async handleSubmit() {
const params = { ...this.form, type: 2 }
if (this.isEdit) {
await this.onUpdate(params)
} else {
await this.onCreate(params)
}
this.$emit('confirm')
},
async onUpdate(params) {
try {
await this.$http.put(`/api/crop-yields/${params.id}`, params)
this.$u.toast('操作成功')
} catch ({ data }) {
data && this.$u.toast(data?.message)
}
},
async onCreate(params) {
try {
await this.$http.post('/api/crop-yields', params)
this.$u.toast('操作成功')
} catch ({ data }) {
data && this.$u.toast(data?.message)
}
},
async setDefaultForm(e) {
if (!e.id) return
try {
const { data } = await this.$http.get(`/api/crop-yields/${e.id}`)
const { data: resData } = data
Object.keys(resData).forEach((key) => {
const value = resData[key]
if (this.form[key] !== undefined) this.form[key] = value
})
} catch (error) {}
},
},
watch: {
data: {
handler(val) {
if (val) {
this.setDefaultForm(val)
}
},
immediate: true,
deep: true,
},
},
}
</script>

View File

@ -0,0 +1,280 @@
<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.base_name }} </view>
<view>农作物名称{{ item.crop_name }}</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.yield }}</view>
<view class="text-center">{{ item.output }}</view>
<view class="text-center">{{ item.cultivated }}</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: 'base_name',
},
{
title: '农作物名称',
dataIndex: 'crop_name',
},
{
title: '年份',
dataIndex: 'time_year',
format: (text) => {
return text + '年'
},
},
{
title: '季度',
dataIndex: 'quarter',
format: (e) => {
const map = {
1: '第一季度',
2: '第二季度',
3: '第三季度',
4: '第四季度',
}
return map[e]
},
},
{
title: '产量',
dataIndex: 'yield',
},
{
title: '产值',
dataIndex: 'output',
},
{
title: '耕种面积',
dataIndex: 'cultivated',
},
]
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: 'quarter',
label: '季度',
component: 'Select',
componentProps: {
options: [
{ label: '第一季度', value: '1' },
{ label: '第二季度', value: '2' },
{ label: '第三季度', value: '3' },
{ label: '第四季度', value: '4' },
],
},
},
{
field: 'type',
label: '农作物',
component: 'ApiSelect',
componentProps: ({ formActionType }) => {
return {
api: async (e) => {
const { data } = await http.get('/api/crops', {
params: e,
})
return data.data
},
labelField: 'name',
valueField: 'id',
params: {
type: 'all',
crop_type: 2,
},
}
},
},
],
}
},
methods: {
handleSubmit(e) {
this.filterParmas = e
this.mescroll.resetUpScroll()
},
upCallback({ num, size }) {
this.getData({
...this.filterParmas,
page: num,
per_page: size,
type: 2,
})
},
async getData(e) {
try {
const { data } = await http.get(`/api/crop-yields`, {
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/crop-yields/${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>