2 Révisions

Auteur SHA1 Message Date
  张泽亮 61856e3cdd PC端详情页面字段增加 il y a 2 mois
  张泽亮 86a91fca29 移动端操作组件 il y a 2 mois
11 fichiers modifiés avec 1362 ajouts et 55 suppressions
  1. +160
    -0
      src/components/form/CommonUpload.vue
  2. +107
    -0
      src/components/form/FieldCalender.vue
  3. +216
    -0
      src/components/form/FieldCascadeSelect.vue
  4. +262
    -0
      src/components/form/FieldCascader.vue
  5. +91
    -0
      src/components/form/FieldCheckbox.vue
  6. +196
    -0
      src/components/form/FieldDatePicker.vue
  7. +111
    -0
      src/components/form/FieldRadio.vue
  8. +190
    -0
      src/components/form/FieldSelect.vue
  9. +15
    -55
      src/views/app/project/operate_edit.vue
  10. +7
    -0
      src/views/resource/land/index.vue
  11. +7
    -0
      src/views/resource/operation/index.vue

+ 160
- 0
src/components/form/CommonUpload.vue Voir le fichier

@@ -0,0 +1,160 @@
<!-- 通用上传组件 zhao -->

<template>
<van-uploader
v-model="fileList"
:multiple="multiple"
:after-read="afterRead"
:show-upload="showUpload"
:deletable="deletable"
@delete="deleteFile"
:accept="accept || null"
/>
</template>

<script>

import {commonUpload} from "@/api/sunVillage_info/fixedAssets";

export default {
name: "commonUpload",
props: {
name: String,
value: { // 绑定值 字符串 ,分隔 可监听
type: String,
default: null,
},
accept: { // 上传类型限制: 默认图片, * = 任意类型
type: String,
},
multiple: { // 多文件上传
type: Boolean,
default: false,
},
deletable: { // 允许删除
type: Boolean,
default: true,
},
showUpload: { // 显示上传按钮
type: Boolean,
default: true,
},
formData: { // 额外请求参数
type: Object,
default: function() {
return {};
},
},
file: { // 上传文件字段名
type: String,
default: 'file',
},
host: {
type: String, // 文件地址前缀
default: '/api',
},
},
watch: {
value: function (newVal, oldVal) {
if(newVal != this.internalValue)
this.setInternalValue(newVal);
},
},
created() {
this.parseValue(this.value);
},
data() {
return {
internalValue: this.value,
fileList: [],
pathList: [],
};
},
methods: {
setInternalValue(newVal) {
this.parseValue(newVal);
this.internalValue = newVal;
},
parseValue(data) {
if(data)
{
this.pathList = data.split(',');
}
else
{
this.pathList = [];
}
this.fileList = this.pathList.map((x) => {
return {
url: this.host + x,
};
});
},
makeFormData() {
let fd = new FormData();
if(this.formData)
{
for(let k of Object.keys(this.formData))
{
fd.set(k, this.formData[k]);
}
}
return fd;
},
upload(file) {
let params1 = this.makeFormData();
params1.append(this.file, file.file);
return commonUpload(params1).then((resp) => {
this.pathList.push(resp.fileName);
this.updateInternalValue();
this.$emit('upload', resp.fileName);
});
},
afterRead(file) {
this.$toast.loading({
message: "上传中...",
forbidClick: true,
duration: 0,
});
// 此时可以自行将文件上传至服务器
if (file instanceof Array) {//判断是否为数组,单张图片为array,多张为数组,数组返回true否则为false
if(file.length > 0)
{
let index = 0;
const f = () => {
if(index >= file.length)
return;
let up = file[index];
//console.log(up);
console.log(`上传文件: ${index} -> ${up.file.name}`);
this.upload(up).then(() => {
index++;
if(index < file.length)
f();
});
};
f();
}
} else {
this.upload(file);
}
},
deleteFile(detail){
this.pathList.splice(detail.index,1);
this.updateInternalValue();
this.$emit('remove', detail.index);
},
updateInternalValue() {
let files = this.pathList.join(',');
console.log(files);
this.internalValue = files;
if(this.internalValue != this.value)
this.$emit('input', this.internalValue);
},
},
}
</script>

<style scoped>

</style>

+ 107
- 0
src/components/form/FieldCalender.vue Voir le fichier

@@ -0,0 +1,107 @@
<!-- 日历表单组件 zhao -->
<template>
<!-- !!!注: 不支持逝去的日子, 以`FieldDatePicker`代替 !!! -->
<div>
<van-field
:readonly="true"
:clickable="!readonly"
:name="name"
:value="visibleValue"
:label="label"
:placeholder="placeholder"
@click="openPopup"
input-align="right"
right-icon="arrow-down"
:rules="rules"
:required="required"
:label-width="labelWidth || 'auto'"
>
<!-- <template #button>
<van-icon name="notes-o" size="20"/>
</template>-->
</van-field>
<van-calendar
ref="calender"
v-model="popupVisible"
:title="label"
:default-date="internalValue"
:readonly="readonly"
@confirm="onConfirm" />
</div>
</template>

<script>

import { formatDate } from "element-ui/src/utils/date-util.js"

export default {
name: "FieldCalender",
props: [
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'labelWidth',
'formatter', // value的格式化 String|Function|undefined 字符串为格式字符串, 函数则必须有返回 undefined则不转换
],
watch: {
value: function (newVal, oldVal) {
this.visibleValue = newVal;
this.internalValue = new Date(newVal);
},
},
created() {
if(this.value)
{
this.visibleValue = this.value;
this.internalValue = new Date(this.value);
}
},
data() {
return {
popupVisible: false,
internalValue: new Date(this.value || Date.now()),
visibleValue: this.value,
loading: false,
};
},
methods: {
openPopup() {
if(!this.readonly)
{
this.popupVisible = true;
this.$nextTick(() => {
this.$refs.calender.scrollToDate(this.internalValue);
})
}
},
closePopup() {
this.popupVisible = false;
},
onConfirm(data) {
this.syncValue(data);
this.$emit('input', this.visibleValue);
this.$emit('confirm', this.visibleValue, this.internalValue);
this.closePopup();
},
onCancel() {
this.closePopup();
this.$emit('cancel');
},
getValue(data) {
let type = typeof(this.formatter);
if(type === 'function')
return this.formatter(data);
else if(type === 'string')
return formatDate(data, this.formatter);
else
return data;
},
syncValue(data) {
this.internalValue = data;
this.visibleValue = this.getValue(data);
console.log(this.internalValue, this.visibleValue);
},
},
}
</script>

<style scoped>

</style>

+ 216
- 0
src/components/form/FieldCascadeSelect.vue Voir le fichier

@@ -0,0 +1,216 @@
<!-- 下拉列表表单组件 zhao -->
<template>
<div>
<van-field
:readonly="true"
:clickable="!readonly"
:name="name"
:value="visibleValue"
:label="label"
:placeholder="placeholder"
@click="openPopup"
input-align="right"
right-icon="arrow-down"
:rules="rules"
:required="required"
:label-width="labelWidth || 'auto'"
>
</van-field>
<van-popup v-model="popupVisible" position="bottom">
<van-picker
ref="picker"
:title="label"
show-toolbar
:columns="columns ? columns : remoteColumns"
:readonly="readonly"
:value-key="valueKey"
:loading="loading"
@confirm="onConfirm"
@cancel="onCancel"
@change="onChanged"
/>
</van-popup>
</div>
</template>

<script>
import request from "@/utils/request";

export default {
name: "fieldCascadeSelect",
props: [
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'labelWidth',
'columns', // 列表数据 Array
'valueKey', // 名称键名 String
'dataKey', // 值键名 String
'remoteUrl', // 远程列表加载地址 String
'onRemoteResponse', // 远程获取到结果的处理回调 String|Function 如果是函数需返回数组, 如果是字符串支持.分割
'clearable', // 点击取消时清空绑定值
],
watch: {
value: function (newVal, oldVal) {
this.internalValue = newVal;
this.visibleValue = newVal ? newVal.join(' / ') : '';
this.syncIndex();
},
columns: function (newVal, oldVal) {
this.syncIndex();
},
remoteUrl: function (newVal, oldVal) {
this.requestRemote();
},
onRemoteResponse: function (newVal, oldVal) {
this.parseRemote();
}
},
created() {
if(this.remoteUrl)
this.requestRemote();
},
data() {
return {
popupVisible: false,
internalValue: this.value,
visibleValue: '',
defaultIndex: [],
remoteColumns: null,
loading: false,
remoteResponse: null,
};
},
methods: {
openPopup() {
if(!this.readonly)
{
this.popupVisible = true;
this.$nextTick(() => {
this.$refs.picker.setIndexes(this.defaultIndex);
})
}
},
closePopup() {
this.popupVisible = false;
},
onChanged(data) {
this.$emit('change', data);
},
onConfirm(data) {
this.syncValue(data);
this.$emit('input', this.internalValue);
this.$emit('confirm', this.internalValue);
this.closePopup();
},
onCancel() {
this.closePopup();
this.$emit('cancel');
if(this.clearable)
{
this.visibleValue = '';
this.internalValue = [];
this.$emit('input', this.internalValue);
}
},
getValue(data) {
return typeof(data) === 'object' && this.dataKey ? data[this.dataKey] : data;
},
getLabel(data) {
return typeof(data) === 'object' && this.valueKey ? data[this.valueKey] : data;
},
syncValue(data) {
let res = [];
for(let a of data)
{
res.push(this.getValue(a));
}
this.internalValue = res;
res = [];
for(let a of data)
{
res.push(this.getLabel(a));
}
this.visibleValue = res.join(' / ');
},
syncIndex() {
let columns = this.getColumns();
if(!columns)
return -1;
let arr = [];
let dataArr = [];
let ptr = columns;
for(let i = 0; i < this.internalValue.length; i++)
{
if(!ptr)
break;
let p = null;
for(let m = 0; m < ptr.length; m++)
{
if(this.getValue(ptr[m]) == this.internalValue[i]) {
arr.push(m);
dataArr.push(ptr[m]);
p = ptr[m];
break;
}
}
if(p)
ptr = p.children;
}
if(arr.length)
{
this.defaultIndex = arr;
this.visibleValue = dataArr.map((x) => this.getLabel(x)).join(' / ');
this.onChanged(dataArr);
return dataArr;
}
if(1) // 不存在
{
this.defaultIndex = [];
this.visibleValue = (this.internalValue || []).join(' / ');
this.onChanged([]);
}
return -1;
},
getColumns() {
return this.columns ? this.columns : this.remoteColumns;
},
requestRemote() {
if(!this.remoteUrl)
return;
this.loading = true;
this.remoteColumns = [];
let promise = typeof(this.remoteUrl) === 'function' ? this.remoteUrl() : (this.remoteUrl instanceof Promise ? this.remoteUrl : request(this.remoteUrl));
promise.then((resp) => {
this.remoteResponse = resp;
this.parseRemote();
this.syncIndex();
}).catch((e) => {
console.error(e);
}).finally(() => {
this.loading = false;
})
},
parseRemote() {
if(!this.remoteResponse)
return;
let type = typeof(this.onRemoteResponse);
if(type === 'function')
this.remoteColumns = this.onRemoteResponse(this.remoteResponse);
else if(type === 'string')
{
let arr = this.onRemoteResponse.split('.');
let ptr = this.remoteResponse;
for(let i in arr)
{
ptr = this.remoteResponse[arr[i]];
}
this.remoteColumns = ptr;
}
else
this.remoteColumns = this.remoteResponse;
},
},
}
</script>

<style scoped>

</style>

+ 262
- 0
src/components/form/FieldCascader.vue Voir le fichier

@@ -0,0 +1,262 @@
<!-- 级联树选择器表单组件 zhao -->
<template>
<div>
<van-field
:readonly="true"
:clickable="!readonly"
:name="name"
:value="visibleValue"
:label="label"
:placeholder="placeholder"
@click="openPopup"
input-align="right"
right-icon="arrow-down"
:rules="rules"
:required="required"
:label-width="labelWidth || 'auto'"
>
</van-field>
<van-popup v-model="popupVisible" position="bottom">
<van-cascader
ref="picker"
:title="label"
v-model="internalValue"
:placeholder="placeholder || '请选择'"
:options="internalOptions"
:readonly="readonly"
:loading="loading"
:field-names="{
text: textName || 'text',
value: valueName || 'value',
children: childrenName || 'children',
}"
@finish="onConfirm"
@close="onCancel"
@change="onChanged"
/>
</van-popup>
</div>
</template>

<script>
import request from "@/utils/request";

export default {
name: "fieldCascader",
props: [
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'labelWidth',
'options', // 树结构数组/普通数组
'textName', // 名称键名 String 默认text
'valueName', // 值键名 String 默认value
'remoteUrl', // 远程列表加载地址 String
'onRemoteResponse', // 远程获取到结果的处理回调 String|Function 如果是函数需返回数组, 如果是字符串支持.分割
'childrenName', // 子级数组键名 String 默认children
'parentName', // 父的值键名 String 如果不为空 则自动转数组为树树结构数组 String
'showTextAndValue', // 是否显示值和键 Bool|String 字符串为分隔符, true为空字符串
'showHasChildren', // 是否显示存在子级的标识 Bool|String 字符串为标识符, true为` >`
'clearable', // 点击取消时清空绑定值
],
watch: {
value: function (newVal, oldVal) {
if(newVal != this.internalValue)
{
this.internalValue = newVal;
this.syncIndex();
}
},
options: function (newVal, oldVal) {
this.internalOptions = this.makeTree(JSON.parse(JSON.stringify(newVal)));
this.handleTree(this.internalOptions);
this.syncIndex();
},
remoteUrl: function (newVal, oldVal) {
this.requestRemote();
},
onRemoteResponse: function (newVal, oldVal) {
this.parseRemote();
}
},
created() {
if(this.options && Array.isArray(this.options) && this.options.length > 0)
{
this.internalOptions = this.makeTree(JSON.parse(JSON.stringify(this.options)));
this.handleTree(this.internalOptions);
this.syncIndex();
}
else if(this.remoteUrl)
this.requestRemote();
},
data() {
return {
popupVisible: false,
internalValue: this.value,
visibleValue: '',
defaultIndex: 0,
internalOptions: [],
loading: false,
remoteResponse: null,
};
},
methods: {
openPopup() {
if(!this.readonly)
{
this.popupVisible = true;
this.$nextTick(() => {
//this.$refs.picker.setIndexes([this.defaultIndex]);
})
}
},
closePopup() {
this.popupVisible = false;
},
onChanged({ value, selectedOptions, tabIndex }) {
this.$emit('change', { value, selectedOptions, });
},
onConfirm({ value, selectedOptions, tabIndex }) {
this.syncValue(value, selectedOptions[selectedOptions.length - 1]);
this.$emit('input', this.internalValue);
this.$emit('confirm', this.internalValue);
this.closePopup();
},
onCancel() {
this.closePopup();
this.$emit('cancel');
if(this.clearable)
{
this.visibleValue = '';
this.internalValue = null;
this.$emit('input', this.internalValue);
}
},
getValue(data) {
return typeof(data) === 'object' && this.valueName ? data[this.valueName] : data;
},
getLabel(data) {
return typeof(data) === 'object' && this.textName ? data[this.textName] : data;
},
syncValue(value, data) {
this.internalValue = value;
this.visibleValue = this.getLabel(data);
},
requestRemote() {
if(!this.remoteUrl)
return;
this.loading = true;
this.internalOptions = [];
let promise = typeof(this.remoteUrl) === 'function' ? this.remoteUrl() : (this.remoteUrl instanceof Promise ? this.remoteUrl : request(this.remoteUrl));
promise.then((resp) => {
this.remoteResponse = resp;
this.parseRemote();
}).catch((e) => {
console.error(e);
}).finally(() => {
this.loading = false;
})
},
parseRemote() {
if(!this.remoteResponse)
return;
let type = typeof(this.onRemoteResponse);
if(type === 'function')
this.internalOptions = this.makeTree(this.onRemoteResponse(this.remoteResponse));
else if(type === 'string')
{
let arr = this.onRemoteResponse.split('.');
let ptr = this.remoteResponse;
for(let i in arr)
{
ptr = this.remoteResponse[arr[i]];
}
this.internalOptions = this.makeTree(ptr);
}
else
this.internalOptions = this.makeTree(this.remoteResponse);
this.handleTree(this.internalOptions);
this.syncIndex();
},
makeTree(list) {
let parentName = this.parentName;
let valueName = this.valueName || 'value';
let childrenName = this.childrenName || 'children';
function isnull(p) {
return p === null || p === undefined || p === '';
}
function makeTree_r(l, p) {
const isRoot = isnull(p);
let res = [];
for(let v of l)
{
const parentValue = v[parentName];
const value = v[valueName];
if((isRoot && isnull(parentValue)) || (!isRoot && parentValue == p))
{
let arr = makeTree_r(l, value);
if(arr && arr.length > 0)
v[childrenName] = arr;
else
delete v[childrenName];
res.push(v);
}
}
return res;
}
if(this.parentName)
return makeTree_r(list);
else
return list;
},
handleTree(tree) {
if(!this.showTextAndValue && !this.showHasChildren)
return;
let split = this.showTextAndValue === false || this.showTextAndValue === undefined || this.showTextAndValue === null ? false : (typeof(this.showTextAndValue) === 'boolean' ? "" : this.showTextAndValue);
let hasChildren = this.showHasChildren === false || this.showHasChildren === undefined || this.showHasChildren === null ? false : (typeof(this.showHasChildren) === 'boolean' ? " >" : this.showHasChildren);
let textName = this.textName || 'text';
let valueName = this.valueName || 'value';
let childrenName = this.childrenName || 'children';
function handleTree_r(l) {
for(let v of l)
{
if(split !== false)
v[textName] = v[valueName] + split + v[textName];
if(v[childrenName] && Array.isArray(v[childrenName]) && v[childrenName].length > 0)
{
if(hasChildren !== false)
v[textName] = v[textName] + hasChildren;
handleTree_r(v[childrenName]);
}
}
}
handleTree_r(tree);
},
findTree(tree, value) {
let valueName = this.valueName || 'value';
let childrenName = this.childrenName || 'children';
function findTree_r(l) {
for(let v of l)
{
if(value == v[valueName])
return v;
if(v[childrenName] && Array.isArray(v[childrenName]) && v[childrenName].length > 0)
{
let res = findTree_r(v[childrenName]);
if(res !== undefined)
return res;
}
}
return;
}
return findTree_r(tree);
},
syncIndex() {
let item = this.findTree(this.internalOptions, this.internalValue);
if(item)
this.visibleValue = item[this.textName || 'text'];
}
},
}
</script>

<style scoped>

</style>

+ 91
- 0
src/components/form/FieldCheckbox.vue Voir le fichier

@@ -0,0 +1,91 @@
<!-- 状态单选框表单组件 zhao -->
<template>
<div>
<van-field
:readonly="true"
:clickable="!readonly"
:name="name"
:label="label"
:placeholder="placeholder"
input-align="right"
:required="required"
:label-width="labelWidth || 'auto'"
@click="toggle"
>
<template #right-icon>
<van-checkbox v-model="checked"
:disabled="readonly"
shape="square"
></van-checkbox>
</template>
</van-field>
</div>
</template>

<script>

export default {
name: "fieldCheckbox",
props: [
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules',
'labelWidth',
'trueLabel', // 选中的值
'falseLabel', // 未选中的值
],
watch: {
value: function (newVal, oldVal) {
this.parseValue(newVal);
},
checked: function (newVal, oldVal) {
if(newVal !== undefined)
this.onChanged(newVal);
},
},
created() {
this.parseValue(this.value);
},
data() {
return {
internalValue: this.value,
remoteColumns: null,
remoteResponse: null,
checked: false,
};
},
methods: {
onChanged(data) {
let trueLabel = this.getTrueLabel();
let falseLabel = this.getFalseLabel();
let res = data ? trueLabel : falseLabel;
if(res != this.internalValue)
{
this.internalValue = res;
this.$emit('change', this.internalValue);
this.$emit("input", this.internalValue);
}
},
getFalseLabel() {
return this.falseLabel !== undefined ? this.falseLabel : false;
},
getTrueLabel() {
return this.trueLabel !== undefined ? this.trueLabel : true;
},
parseValue(data) {
let trueLabel = this.getTrueLabel();
let falseLabel = this.getFalseLabel();
let res = data == trueLabel;
this.internalValue = res ? trueLabel : falseLabel;
this.checked = res;
},
toggle() {
console.log(123);
if(!this.readonly)
this.checked = !this.checked;
},
},
}
</script>

<style scoped>

</style>

+ 196
- 0
src/components/form/FieldDatePicker.vue Voir le fichier

@@ -0,0 +1,196 @@
<!-- 日期选择表单组件 zhao -->
<template>
<div>
<van-field
:readonly="true"
:clickable="!readonly"
:name="name"
:value="visibleValue"
:label="label"
:placeholder="placeholder"
@click="openPopup"
input-align="right"
right-icon="arrow-down"
:rules="rules"
:required="required"
:label-width="labelWidth || 'auto'"
:input-align="inputAlign || 'left'"
:size="size || ''"
>
<!-- <template #button>
<van-icon name="notes-o" size="20"/>
</template>-->
</van-field>

<van-popup v-model="popupVisible" position="bottom" v-if="type === 'year'">
<van-picker
ref="picker"
:title="label"
show-toolbar
:columns="yearColumns"
:readonly="readonly"
v-model="internalValue"
@confirm="onConfirm"
@cancel="onCancel"
@change="onChanged"
/>
</van-popup>
<van-popup v-model="popupVisible" position="bottom" v-else>
<van-datetime-picker
ref="picker"
v-model="internalValue"
:type="type || 'date'"
:readonly="readonly"
:title="label || ''"
:min-date="minDate"
:max-date="maxDate"
@confirm="onConfirm"
@cancel="onCancel"
@change="onChanged"
/>
</van-popup>
</div>
</template>

<script>

import { formatDate } from "element-ui/src/utils/date-util.js"
import {strtotime} from "@/utils";

export default {
name: "fieldDatePicker",
props: [
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'labelWidth', 'inputAlign',
'type', // 类型, 仅支持 datetime date time year-month month-day datehour, 额外支持year(但formatter必须为yyyy, 可以提供yearRangeLength=<Number>指定年范围)
'formatter', // value的格式化 String|Function|undefined 字符串为格式字符串, 函数则必须有返回 undefined则不转换
'clearable', // 点击取消时清空绑定值
'yearRangeLength', // type === 'year' 时生成的年份数量范围 [YEAR - yearRangeLength, YEAR + yearRangeLength]
'minDate', 'maxDate',
'size',
],
watch: {
value: function (newVal, oldVal) {
this.visibleValue = newVal;
this.internalValue = new Date(newVal);
},
},
created() {
if(this.value)
{
this.visibleValue = this.value;
this.internalValue = new Date(this.value);
}
// 默认当前
/* else {
this.syncValue(new Date);
}*/
},
data() {
return {
popupVisible: false,
internalValue: new Date(this.value || Date.now()),
visibleValue: this.value,
loading: false,
};
},
methods: {
openPopup() {
if(!this.readonly)
{
//console.log(this.internalValue);
this.popupVisible = true;
this.$nextTick(() => {
try
{
if(1)
{
let values = (this.visibleValue || this.getValue(new Date)).split(/\D+/); //TODO: 按非数字符号粗略分割解析初始值, 仅对于类似yyyy-MM-dd
//console.log(values);
let picker = this.$refs.picker.getPicker ? this.$refs.picker.getPicker() : this.$refs.picker;
picker.setValues(values);
}
else {
//TODO: 打开时保存初始值, 取消或点击遮罩未确定的时候恢复该初始值到v-model
}
}
catch (e)
{
console.error(e);
}
})
}
},
closePopup() {
this.popupVisible = false;
},
onConfirm(data) {
this.syncValue(data);
this.$emit('input', this.visibleValue);
this.$emit('confirm', this.visibleValue, this.internalValue);
this.closePopup();
},
onCancel() {
this.closePopup();
this.$emit('cancel');
if(this.clearable)
{
this.visibleValue = '';
this.internalValue = null;
this.$emit('input', this.internalValue);
}
},
onChanged(data) {
this.$emit('change', this.getValue(data), data);
},
getValue(data) {
let type = typeof(this.formatter);
if(type === 'function')
return this.formatter(data);
else if(type === 'string')
return formatDate(data, this.formatter);
else
return data;
},
syncValue(data) {
this.internalValue = data;
this.visibleValue = this.getValue(data);
},
genYearColumns(num) {
let d;
try
{
if(this.value)
{
d = strtotime(this.value, 'yyyy');
}
else
d = new Date;
}
catch(e)
{
d = new Date;
}
let y = d.getFullYear();
let arr = ['' + y];
for(let i = 1; i <= num; i++)
{
arr.push('' + (y + i));
arr.splice(0, 0, '' + (y - i));
}
return arr;
},
strtotime,
},
computed: {
yearColumns() {
if(this.type !== 'year')
return [];
return this.genYearColumns(this.yearRangeLength || 100);
},
}
}
</script>

<style scoped>

</style>

+ 111
- 0
src/components/form/FieldRadio.vue Voir le fichier

@@ -0,0 +1,111 @@
<!-- 单选框组表单组件 zhao -->
<template>
<div>
<van-field
:readonly="true"
:name="name"
:label="label"
:placeholder="placeholder"
input-align="right"
:required="required"
:label-width="labelWidth || 'auto'"
>
<template #right-icon>
<van-radio-group :disabled="readonly" @change="onChanged" v-model="internalValue" direction="horizontal" :rules="rules">
<van-radio v-for="(item, index) in (columns ? columns : remoteColumns)" :name="getValue(item)" :key="index">{{getLabel(item)}}</van-radio>
</van-radio-group>
</template>
</van-field>
</div>
</template>

<script>
import request from "@/utils/request";

export default {
name: "fieldRadio",
props: [
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'labelWidth',
'columns', // 列表数据 Array
'valueKey', // 名称键名 String
'dataKey', // 值键名 String
'remoteUrl', // 远程列表加载地址 String
'onRemoteResponse', // 远程获取到结果的处理回调 String|Function 如果是函数需返回数组, 如果是字符串支持.分割
],
watch: {
value: function (newVal, oldVal) {
this.internalValue = newVal;
},
columns: function (newVal, oldVal) {
},
remoteUrl: function (newVal, oldVal) {
this.requestRemote();
},
onRemoteResponse: function (newVal, oldVal) {
this.parseRemote();
}
},
created() {
if(this.remoteUrl)
this.requestRemote();
},
data() {
return {
internalValue: this.value,
remoteColumns: null,
remoteResponse: null,
};
},
methods: {
onChanged(data) {
this.$emit("input", this.internalValue);
this.$emit('change', this.internalValue);
},
getValue(data) {
return typeof(data) === 'object' && this.dataKey ? data[this.dataKey] : data;
},
getLabel(data) {
return typeof(data) === 'object' && this.valueKey ? data[this.valueKey] : data;
},
getColumns() {
return this.columns ? this.columns : this.remoteColumns;
},
requestRemote() {
if(!this.remoteUrl)
return;
this.remoteColumns = [];
let promise = typeof(this.remoteUrl) === 'function' ? this.remoteUrl() : (this.remoteUrl instanceof Promise ? this.remoteUrl : request(this.remoteUrl));
promise.then((resp) => {
this.remoteResponse = resp;
this.parseRemote();
}).catch((e) => {
console.error(e);
}).finally(() => {
})
},
parseRemote() {
if(!this.remoteResponse)
return;
let type = typeof(this.onRemoteResponse);
if(type === 'function')
this.remoteColumns = this.onRemoteResponse(this.remoteResponse);
else if(type === 'string')
{
let arr = this.onRemoteResponse.split('.');
let ptr = this.remoteResponse;
for(let i in arr)
{
ptr = this.remoteResponse[arr[i]];
}
this.remoteColumns = ptr;
}
else
this.remoteColumns = this.remoteResponse;
},
},
}
</script>

<style scoped>

</style>

+ 190
- 0
src/components/form/FieldSelect.vue Voir le fichier

@@ -0,0 +1,190 @@
<!-- 下拉列表表单组件 zhao -->
<template>
<div>
<van-field
:readonly="true"
:clickable="!readonly"
:name="name"
:value="visibleValue"
:label="label"
:placeholder="placeholder"
@click="openPopup"
input-align="right"
right-icon="arrow-down"
:rules="rules"
:required="required"
:label-width="labelWidth || 'auto'"
:size="size || ''"
>
</van-field>
<van-popup v-model="popupVisible" position="bottom">
<van-picker
ref="picker"
:title="label"
show-toolbar
:columns="columns ? columns : remoteColumns"
:readonly="readonly"
:value-key="valueKey"
:loading="loading"
@confirm="onConfirm"
@cancel="onCancel"
@change="onChanged"
/>
</van-popup>
</div>
</template>

<script>
import request from "@/utils/request";

export default {
name: "fieldSelect",
props: [
'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'labelWidth',
'columns', // 列表数据 Array
'valueKey', // 名称键名 String
'dataKey', // 值键名 String
'remoteUrl', // 远程列表加载地址 String
'onRemoteResponse', // 远程获取到结果的处理回调 String|Function 如果是函数需返回数组, 如果是字符串支持.分割
'clearable', // 点击取消时清空绑定值
'size',
],
watch: {
value: function (newVal, oldVal) {
this.internalValue = newVal;
this.visibleValue = newVal;
this.syncIndex();
},
columns: function (newVal, oldVal) {
this.syncIndex();
},
remoteUrl: function (newVal, oldVal) {
this.requestRemote();
},
onRemoteResponse: function (newVal, oldVal) {
this.parseRemote();
}
},
created() {
if(this.remoteUrl)
this.requestRemote();
},
data() {
return {
popupVisible: false,
internalValue: this.value,
visibleValue: '',
defaultIndex: 0,
remoteColumns: null,
loading: false,
remoteResponse: null,
};
},
methods: {
openPopup() {
if(!this.readonly)
{
this.popupVisible = true;
this.$nextTick(() => {
this.$refs.picker.setIndexes([this.defaultIndex]);
})
}
},
closePopup() {
this.popupVisible = false;
},
onChanged(data) {
this.$emit('change', data);
},
onConfirm(data) {
this.syncValue(data);
this.$emit('input', this.internalValue);
this.$emit('confirm', this.internalValue);
this.closePopup();
},
onCancel() {
this.closePopup();
this.$emit('cancel');
if(this.clearable)
{
this.visibleValue = '';
this.internalValue = null;
this.$emit('input', this.internalValue);
}
},
getValue(data) {
return typeof(data) === 'object' && this.dataKey ? data[this.dataKey] : data;
},
getLabel(data) {
return typeof(data) === 'object' && this.valueKey ? data[this.valueKey] : data;
},
syncValue(data) {
this.internalValue = this.getValue(data);
this.visibleValue = this.getLabel(data);
},
syncIndex() {
let columns = this.getColumns();
if(!columns)
return -1;
for(let i in columns)
{
if(this.getValue(columns[i]) == this.internalValue) {
this.defaultIndex = i;
this.visibleValue = this.getLabel(columns[i]);
this.onChanged(columns[i]);
return i;
}
}
if(1) // 不存在
{
this.defaultIndex = -1;
this.visibleValue = this.internalValue;
this.onChanged(null);
}
return -1;
},
getColumns() {
return this.columns ? this.columns : this.remoteColumns;
},
requestRemote() {
if(!this.remoteUrl)
return;
this.loading = true;
this.remoteColumns = [];
let promise = typeof(this.remoteUrl) === 'function' ? this.remoteUrl() : (this.remoteUrl instanceof Promise ? this.remoteUrl : request(this.remoteUrl));
promise.then((resp) => {
this.remoteResponse = resp;
this.parseRemote();
this.syncIndex();
}).catch((e) => {
console.error(e);
}).finally(() => {
this.loading = false;
})
},
parseRemote() {
if(!this.remoteResponse)
return;
let type = typeof(this.onRemoteResponse);
if(type === 'function')
this.remoteColumns = this.onRemoteResponse(this.remoteResponse);
else if(type === 'string')
{
let arr = this.onRemoteResponse.split('.');
let ptr = this.remoteResponse;
for(let i in arr)
{
ptr = this.remoteResponse[arr[i]];
}
this.remoteColumns = ptr;
}
else
this.remoteColumns = this.remoteResponse;
},
},
}
</script>

<style scoped>

</style>

+ 15
- 55
src/views/app/project/operate_edit.vue Voir le fichier

@@ -1,12 +1,6 @@
<template>
<div class="home_wrapper">
<van-nav-bar
title="经营信息维护"
left-arrow
placeholder
safe-area-inset-top
@click-left="onClickLeft"
/>
<van-nav-bar title="经营信息维护" left-arrow placeholder safe-area-inset-top @click-left="onClickLeft"/>

<van-form @submit="onSubmit">
<div class="main">
@@ -20,77 +14,39 @@
<van-field readonly v-model="form.dkbz" label="地块北至" placeholder="请输入" input-align="right" label-width="auto" />

<van-field required :rules="[{ required: true }]" v-model="form.jymj" label="经营面积" placeholder="请输入" input-align="right" label-width="auto" />

<van-field required :rules="[{ required: true }]" readonly @click="showJyfsPicker = true" v-model="form.jyfsText" label="经营方式" placeholder="请输入" input-align="right" label-width="auto" />
<van-popup v-model="showJyfsPicker" round position="bottom">
<van-picker
show-toolbar
:columns="dict.type.jyfs"
value-key="label"
@cancel="showJyfsPicker = false"
@confirm="onConfirmJyfs"
/>
<van-picker show-toolbar :columns="dict.type.jyfs" value-key="label" @cancel="showJyfsPicker = false" @confirm="onConfirmJyfs"/>
</van-popup>

<van-field readonly @click="showJydxlxPicker = true" v-model="form.jydxlxText" label="经营对象类型" placeholder="请输入" input-align="right" label-width="auto" />
<van-popup v-model="showJydxlxPicker" round position="bottom">
<van-picker
show-toolbar
:columns="dict.type.jydxlx"
value-key="label"
@cancel="showJydxlxPicker = false"
@confirm="onConfirmJydxlx"
/>
<van-picker show-toolbar :columns="dict.type.jydxlx" value-key="label" @cancel="showJydxlxPicker = false" @confirm="onConfirmJydxlx"/>
</van-popup>

<van-field required :rules="[{ required: true }]" v-model="form.jydxmc" label="经营对象名称" placeholder="请输入" input-align="right" label-width="auto" />

<van-field readonly @click="showJydxzjlxPicker = true" v-model="form.jydxzjlxText" label="经营对象证件类型" placeholder="请输入" input-align="right" label-width="auto" />
<van-popup v-model="showJydxzjlxPicker" round position="bottom">
<van-picker
show-toolbar
:columns="dict.type.zjlx"
value-key="label"
@cancel="showJydxzjlxPicker = false"
@confirm="onConfirmJydxzjlx"
/>
<van-picker show-toolbar :columns="dict.type.zjlx" value-key="label" @cancel="showJydxzjlxPicker = false" @confirm="onConfirmJydxzjlx"/>
</van-popup>

<van-field v-model="form.jydxzjhm" label="经营对象证件号码" placeholder="请输入" input-align="right" label-width="auto" />

<van-field readonly @click="showSfqdhtPicker = true" v-model="form.sfqdhtText" label="是否签订合同" placeholder="请输入" input-align="right" label-width="auto" />
<van-popup v-model="showSfqdhtPicker" round position="bottom">
<van-picker
show-toolbar
:columns="dict.type.is_common"
value-key="label"
@cancel="showSfqdhtPicker = false"
@confirm="onConfirmSfqdht"
/>
<van-picker show-toolbar :columns="dict.type.is_common" value-key="label" @cancel="showSfqdhtPicker = false" @confirm="onConfirmSfqdht"/>
</van-popup>

<van-field required :rules="[{ required: true }]" readonly @click="showJykssjPicker = true" v-model="form.jykssj" label="经营开始时间" placeholder="请输入" input-align="right" label-width="auto" />
<van-popup v-model="showJykssjPicker" round position="bottom">
<van-datetime-picker
v-model="jykssj"
type="date"
title="选择年月日"
:min-date="minDate"
:max-date="maxDate"
@cancel="showJykssjPicker = false"
@confirm="onConfirmJykssj"
/>
<van-datetime-picker v-model="jykssj" type="date" title="选择年月日" :min-date="minDate" :max-date="maxDate" @cancel="showJykssjPicker = false" @confirm="onConfirmJykssj"/>
</van-popup>

<van-field required :rules="[{ required: true }]" readonly @click="showJyjssjPicker = true" v-model="form.jyjssj" label="经营结束时间" placeholder="请输入" input-align="right" label-width="auto" />
<van-popup v-model="showJyjssjPicker" round position="bottom">
<van-datetime-picker
v-model="jyjssj"
type="date"
title="选择年月日"
:min-date="minDate"
:max-date="maxDate"
@cancel="showJyjssjPicker = false"
@confirm="onConfirmJyjssj"
/>
<van-datetime-picker v-model="jyjssj" type="date" title="选择年月日" :min-date="minDate" :max-date="maxDate" @cancel="showJyjssjPicker = false" @confirm="onConfirmJyjssj"/>
</van-popup>

<van-field required :rules="[{ required: true }]" v-model="form.cbje" label="承包金额(元)" placeholder="请输入" input-align="right" label-width="auto" />
@@ -99,10 +55,11 @@
<van-field v-model="form.nsy" label="年收益(元)" placeholder="请输入" input-align="right" label-width="auto" />
<van-field v-model="form.bzxx" label="备注信息" placeholder="请输入" input-align="right" label-width="auto" />

<van-field readonly required :rules="[{ required: true }]" @click="showSurveyStatusPicker = true" v-model="form.surveyStatusText" label="调查状态" placeholder="请输入" input-align="right" label-width="auto" />
<!--<van-field readonly required :rules="[{ required: true }]" @click="showSurveyStatusPicker = true" v-model="form.surveyStatusText" label="调查状态" placeholder="请输入" input-align="right" label-width="auto" />
<van-popup v-model="showSurveyStatusPicker" round position="bottom">
<van-picker show-toolbar :columns="dict.type.survey_status" value-key="label" @cancel="showSurveyStatusPicker = false" @confirm="onConfirmSurveyStatus"/>
</van-popup>
</van-popup>-->
<field-select v-model="form.surveyStatusText" label="调查状态" value-key="dictLabel" data-key="dictValue" placeholder="请选择" requiredx remote-url="/system/dict/data/type/survey_status" :on-remote-response="'data'"/>

<van-field readonly label="实物图" placeholder="" input-align="right" label-width="auto" />
<image-upload v-model="form.dkImg"/>
@@ -119,9 +76,12 @@
import { getLandDetail } from "@/api/resource/land"
import { getOperationDetail, updateOperation, addOperation } from "@/api/resource/operation"
import { getInfoByImportCode } from "@/api/system/dept";
import FieldSelect from "@/components/form/FieldSelect.vue";

export default {
dicts: ['zjlx', 'survey_status', 'is_common', 'jydxlx', 'jyfs'],
name: "appEdit",
components: {FieldSelect},
data() {
return {
showJyfsPicker: false,


+ 7
- 0
src/views/resource/land/index.vue Voir le fichier

@@ -217,10 +217,17 @@
<el-descriptions title="经营数据" border :column="2" class="margin-top">
<el-descriptions-item label="经营面积(亩)">{{ form.jymj }}</el-descriptions-item>
<el-descriptions-item label="经营方式">{{ form.jyfs }}</el-descriptions-item>
<el-descriptions-item label="经营对象类型">{{ form.jydxlx }}</el-descriptions-item>
<el-descriptions-item label="经营对象名称">{{ form.jydxmc }}</el-descriptions-item>
<el-descriptions-item label="证件类型">{{ form.jydxzjlx }}</el-descriptions-item>
<el-descriptions-item label="证件号码">{{ form.jydxzjhm }}</el-descriptions-item>
<el-descriptions-item label="是否签订合同">{{ form.sfqdht }}</el-descriptions-item>
<el-descriptions-item label="经营开始时间">{{ form.jykssj }}</el-descriptions-item>
<el-descriptions-item label="经营结束时间">{{ form.jyjssj }}</el-descriptions-item>
<el-descriptions-item label="承包金额(元)">{{ form.cbje }}</el-descriptions-item>
<el-descriptions-item label="兑现金额(元)">{{ form.dxje }}</el-descriptions-item>
<el-descriptions-item label="尚欠金额(元)">{{ form.sqje }}</el-descriptions-item>
<el-descriptions-item label="年收益(元)">{{ form.nsy }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ form.bz }}</el-descriptions-item>
<el-descriptions-item label="调查状态">{{ form.surveyStatus }}</el-descriptions-item>
<el-descriptions-item label="实物图">


+ 7
- 0
src/views/resource/operation/index.vue Voir le fichier

@@ -186,10 +186,17 @@
<el-descriptions title="经营数据" border :column="2" class="margin-top">
<el-descriptions-item label="经营面积(亩)">{{ form.jymj }}</el-descriptions-item>
<el-descriptions-item label="经营方式">{{ form.jyfs }}</el-descriptions-item>
<el-descriptions-item label="经营对象类型">{{ form.jydxlx }}</el-descriptions-item>
<el-descriptions-item label="经营对象名称">{{ form.jydxmc }}</el-descriptions-item>
<el-descriptions-item label="证件类型">{{ form.jydxzjlx }}</el-descriptions-item>
<el-descriptions-item label="证件号码">{{ form.jydxzjhm }}</el-descriptions-item>
<el-descriptions-item label="是否签订合同">{{ form.sfqdht }}</el-descriptions-item>
<el-descriptions-item label="经营开始时间">{{ form.jykssj }}</el-descriptions-item>
<el-descriptions-item label="经营结束时间">{{ form.jyjssj }}</el-descriptions-item>
<el-descriptions-item label="承包金额(元)">{{ form.cbje }}</el-descriptions-item>
<el-descriptions-item label="兑现金额(元)">{{ form.dxje }}</el-descriptions-item>
<el-descriptions-item label="尚欠金额(元)">{{ form.sqje }}</el-descriptions-item>
<el-descriptions-item label="年收益(元)">{{ form.nsy }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ form.bz }}</el-descriptions-item>
<el-descriptions-item label="调查状态">{{ form.surveyStatus }}</el-descriptions-item>
<el-descriptions-item label="实物图">


Chargement…
Annuler
Enregistrer