瀏覽代碼

综合填报

rongxin_prod
zhao 2 年之前
父節點
當前提交
c7ced6eae0
共有 9 個文件被更改,包括 1658 次插入7 次删除
  1. +2
    -0
      .gitignore
  2. +181
    -0
      src/api/sunVillage_info/entity/report.js
  3. +57
    -7
      src/components/form/FieldDatePicker.vue
  4. +18
    -0
      src/router/index.js
  5. +512
    -0
      src/utils/expression.js
  6. +11
    -0
      src/utils/index.js
  7. +4
    -0
      src/utils/utils.js
  8. +278
    -0
      src/views/sunVillage_info/entityReport/reportList.vue
  9. +595
    -0
      src/views/sunVillage_info/entityReport/reportView.vue

+ 2
- 0
.gitignore 查看文件

@@ -12,3 +12,5 @@ yarn-error.log*
*.ntvs*
*.njsproj
*.sln

dist.*

+ 181
- 0
src/api/sunVillage_info/entity/report.js 查看文件

@@ -0,0 +1,181 @@
import request from '@/utils/request'

// 查询统计报列表
export function listReporttitle(query) {
return request({
url: '/entity/reporttitle/list',
method: 'get',
params: query
})
}

// 导出统计报
export function exportReporttitle(query) {
return request({
url: '/entity/reporttitle/export',
method: 'get',
params: query
})
}

// 查询统计报详细
export function getReporttitle(id) {
return request({
url: '/entity/reporttitle/get/' + id,
method: 'get'
})
}

// 新增统计报
export function addReporttitle(data) {
return request({
url: '/entity/reporttitle/add',
method: 'post',
data: data
})
}

// 修改统计报
export function updateReporttitle(data) {
return request({
url: '/entity/reporttitle/edit',
method: 'post',
data: data
})
}

// 删除统计报
export function delReporttitle(id) {
return request({
url: '/entity/reporttitle/remove/' + id,
method: 'get'
})
}

// 启用统计报
export function enableReporttitle(id) {
return request({
url: '/entity/reporttitle/enable/' + id,
method: 'post'
})
}

// 禁用统计报
export function disableReporttitle(id) {
return request({
url: '/entity/reporttitle/disable/' + id,
method: 'post'
})
}

// 获取模板
export function getReportTemplate(id) {
return request({
url: '/entity/reporttitle/template/' + id,
method: 'get'
})
}

// 获取横向模板
export function getReportHorizontalTemplate(id) {
return request({
url: '/entity/reporttitle/horizontalTemplate/' + id,
method: 'get'
})
}

// 查询统计填报列表
export function listReport(query) {
return request({
url: '/entity/report/list',
method: 'get',
params: query
})
}

// 导出统计填报
export function exportReport(query) {
return request({
url: '/entity/report/export',
method: 'get',
params: query
})
}

// 查询统计填报详细
export function getReport(id) {
return request({
url: '/entity/report/get/' + id,
method: 'get'
})
}

// 新增统计填报
export function addReport(data) {
return request({
url: '/entity/report/add',
method: 'post',
data: data
})
}

// 修改统计填报
export function updateReport(data) {
return request({
url: '/entity/report/edit',
method: 'post',
data: data
})
}

// 删除统计填报
export function delReport(id) {
return request({
url: '/entity/report/remove/' + id,
method: 'get'
})
}

// 导出统计填报
export function reportExport(id) {
return request({
url: '/entity/report/reportExport/' + id,
method: 'get',
})
}

// 竖向统计
export function summaryStatistics(query) {
return request({
url: '/entity/report/summaryStatistics',
method: 'get',
params: query
})
}

// 导出竖向统计
export function summaryStatisticsExport(query) {
return request({
url: '/entity/report/summaryStatisticsExport',
method: 'get',
params: query
})
}

// 横向统计
export function horizontalSummaryStatistics(query) {
return request({
url: '/entity/report/horizontalSummaryStatistics',
method: 'get',
params: query
})
}

// 导出横向统计
export function horizontalSummaryStatisticsExport(query) {
return request({
url: '/entity/report/horizontalSummaryStatisticsExport',
method: 'get',
params: query
})
}

+ 57
- 7
src/components/form/FieldDatePicker.vue 查看文件

@@ -14,18 +14,33 @@
:rules="rules"
:required="required"
:label-width="labelWidth || 'auto'"
:input-align="inputAlign || 'left'"
>
<!-- <template #button>
<van-icon name="notes-o" size="20"/>
</template>-->
</van-field>
<van-popup v-model="popupVisible" position="bottom">

<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"
:title="label || ''"
@confirm="onConfirm"
@cancel="onCancel"
@change="onChanged"
@@ -37,14 +52,16 @@
<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',
'type', // 类型, 仅支持 datetime date time year-month month-day datehour
'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]
],
watch: {
value: function (newVal, oldVal) {
@@ -75,7 +92,7 @@ export default {
openPopup() {
if(!this.readonly)
{
console.log(this.internalValue);
//console.log(this.internalValue);
this.popupVisible = true;
this.$nextTick(() => {
try
@@ -83,8 +100,9 @@ export default {
if(1)
{
let values = (this.visibleValue || this.getValue(new Date)).split(/\D+/); //TODO: 按非数字符号粗略分割解析初始值, 仅对于类似yyyy-MM-dd
console.log(values);
this.$refs.picker.getPicker().setValues(values);
//console.log(values);
let picker = this.$refs.picker.getPicker ? this.$refs.picker.getPicker() : this.$refs.picker;
picker.setValues(values);
}
else {
//TODO: 打开时保存初始值, 取消或点击遮罩未确定的时候恢复该初始值到v-model
@@ -132,7 +150,39 @@ export default {
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>



+ 18
- 0
src/router/index.js 查看文件

@@ -3444,6 +3444,24 @@ export const constantRoutes = [
},
component: (resolve) => require(['@/views/sunVillage_info/list_register_detail'], resolve)
},
{ // 综合填报
path: '/sunVillage_info/entityReportList',
name: 'entityReportList',
meta: {
title: '综合填报',
hidden: true,
},
component: (resolve) => require(['@/views/sunVillage_info/entityReport/reportList'], resolve)
},
{ // 综合填报
path: '/sunVillage_info/entityReportView',
name: 'entityReportView',
meta: {
title: '综合填报',
hidden: true,
},
component: (resolve) => require(['@/views/sunVillage_info/entityReport/reportView'], resolve)
},
{ // 统计填报
path: '/sunVillage_info/statistical_report',
name: 'sunVillageInfoStatisticalReport',


+ 512
- 0
src/utils/expression.js 查看文件

@@ -0,0 +1,512 @@

export const Expression = function(_str, _flag = 0, _placeholderValueMap = {})
{
this.pos = 0; // 当前解析表达式字符串的位置
this.str = _str; // 表达式
this.errno = Expression.NO_ERROR; // 当前错误码
this.placeholderValueMap = _placeholderValueMap; // 占位符值字典
this.flag = _flag | Expression.PARSE_FLAG_ERROR_HANDLE_SCHEME_THROW_EXCEPTION; // 行为标记
this.placeholders = [];
}

Expression.NO_ERROR = 0;
Expression.ERROR = 1;
Expression.NULL_STRING = 2;
Expression.BY_ZERO = 3;
Expression.MISSING_DIGIT = 4;
Expression.MISSING_RIGHT_PARENT = 5;
Expression.MISSING_OPERATOR = 6;
Expression.INVALID_CHARACTER = 7;
Expression.MISSING_PLACEHOLDER = 8;
Expression.INVALID_DIGIT = 9;
Expression.INVALID_PLACEHOLDER = 10;
Expression.MISSING_RIGHT_PLACEHOLDER_END = 11;
Expression.INVALID_PLACEHOLDER_FUNCTION = 12;
Expression.MISSING_COMPARE_OPERATOR = 13;
Expression.INVALID_COMPARE_OPERATOR = 14;
Expression.INCOMPLETE = 15;
Expression.ErrorStr = [
"",
"错误",
"空字符串",
"除0",
"缺失数字",
"缺失右括号",
"缺失运算符",
"无效字符",
"缺失占位符",
"无效数字",
"无效占位符",
"缺失占位符结尾标识",
"无效占位符内置函数",
"缺失比较运算符",
"无效比较运算符",
"表达式不完整",
];

Expression.PARSE_FLAG_NONE = 0;
Expression.PARSE_FLAG_ERROR_HANDLE_SCHEME_RETURN_ZERO = 1; // 解析到错误则当前部分返回0
Expression.PARSE_FLAG_ERROR_HANDLE_SCHEME_THROW_EXCEPTION = 1 << 1; // 解析到错误则抛出异常
Expression.PARSE_FLAG_ALL_NUMBER_AS_PLACEHOLDER = 1 << 3; // 所有数字都作为占位符
Expression.PARSE_FLAG_IGNORE_ERROR_MISSING_PLACEHOLDER = 1 << 4; // 忽略占位符缺失
Expression.PARSE_FLAG_IGNORE_ERROR_BY_ZERO = 1 << 5; // 忽略除0

// 是否读取到字符串结尾
Expression.prototype.__EOF = function()
{
return !this.str || this.pos >= this.str.length;
};

// 字符串转为数字
Expression.prototype.__StrTo = function(numStr)
{
return Number(numStr)
};

// 开始解析, 重置状态
Expression.prototype.__Ready = function()
{
this.pos = 0;
this.errno = Expression.NO_ERROR;
this.placeholders = [];
let err = this.__CheckStr();
return (err === Expression.NO_ERROR);
};

// 解析 值 括号 占位符 的优先级最高的表达式
Expression.prototype.__EvalV = function()
{
if(this.__EOF())
{
return this.__FatalError(Expression.INCOMPLETE);
}
this.__SkipBlank();
let nStr = this.str.substring(this.pos);
let p = 0;
let nag = false;
let result = 0;
if(nStr.charAt(p) === '-')
{
nag = true;
this.pos++;
p++;
}
p += this.__SkipBlank();
if(nStr.charAt(p) === '(') // 括号表达式
{
p++;
this.pos++;
result = this.__EvalP();
if(this.str.charAt(this.pos) !== ')')
{
return this.__FatalError(Expression.MISSING_RIGHT_PARENT);
}
this.pos++;
}
else if(nStr.charAt(p) === '{') // 占位符
{
p++;
this.pos++;
p += this.__SkipBlank();
let d = '';
let size = 0;
let ch = nStr.charAt(p);
while("`~@#%^&*()-+=,/?:;\"'|\\[{]}".indexOf(ch) === -1) // 中文支持
{
size++;
d += ch;
p++;
this.pos++;
if(p >= nStr.length)
{
return this.__FatalError(Expression.MISSING_RIGHT_PLACEHOLDER_END);
}
ch = nStr.charAt(p);
}
p += this.__SkipBlank();
if(this.str.charAt(this.pos) !== '}')
{
return this.__FatalError(Expression.MISSING_RIGHT_PLACEHOLDER_END);
}
this.pos++;
if(size > 0)
{
result = this.__ParsePlaceholder(d);
}
else
{
return this.__NormalError(Expression.MISSING_PLACEHOLDER);
}
}
else // 纯数字
{
let d = '';
let size = 0;
let ch = nStr.charAt(p);
while((ch >= '0' && ch <= '9') || ch === '.')
{
size++;
d += ch;
p++;
this.pos++;
if(p >= nStr.length)
break;
ch = nStr.charAt(p);
}
if(size > 0)
{
let m = d.indexOf(".");
if(m !== -1)
{
let n = d.lastIndexOf(".");
if(n !== -1 && m !== n)
{
return this.__FatalError(Expression.INVALID_DIGIT);
}
if(m === 0 || m === d.length - 1)
d = d.substr(0, m) + d.substr(m + 1);
}
if(this.flag & Expression.PARSE_FLAG_ALL_NUMBER_AS_PLACEHOLDER)
result = this.__ParsePlaceholder(d);
else
result = this.__StrTo(d);
}
else
{
return this.__FatalError(Expression.MISSING_DIGIT);
}
}
if(nag)
result = -result;
return result;
};

// 解析* /的优先级相对较高的表达式
Expression.prototype.__EvalM = function()
{
if(this.__EOF())
{
return this.__FatalError(Expression.INCOMPLETE);
}
let first = this.__EvalV();
let result = first;
this.__SkipBlank();
let nStr = this.str.substring(this.pos);
while(nStr.length > 0)
{
let ch = nStr.charAt(0);
if(ch !== '*' && ch !== '/')
return result;
else
{
this.pos++;
let second = this.__EvalV();
if(ch === '*')
result = result *second;
else
{
if(second === 0)
{
return this.__NormalError(Expression.BY_ZERO);
}
result = result / second;
}
}
nStr = this.str.substring(this.pos);
}
return result;
};

// 解析+ -的优先级最低的表达式
Expression.prototype.__EvalP = function()
{
if(this.__EOF())
{
return this.__FatalError(Expression.INCOMPLETE);
}
this.__SkipBlank();
let first = this.__EvalM();
let result = first;
let nStr = this.str.substring(this.pos);
while(nStr.length > 0)
{
let ch = nStr.charAt(0);
if(ch !== '+' && ch !== '-')
return result;
else
{
this.pos++;
let second = this.__EvalM();
if(ch === '+')
result = result + second;
else
result = result - second;
}
nStr = this.str.substring(this.pos);
}
return result;
};

// 解析比较运算符
Expression.prototype.__EvalCmp = function()
{
if(this.__EOF())
{
return this.__FatalError(Expression.MISSING_COMPARE_OPERATOR);
}
this.__SkipBlank();
let result = '';
let nStr = this.str.substring(this.pos);
while(nStr.length > 0)
{
let ch = nStr.charAt(0);
if(ch !== '=' && ch !== '!' && ch !== '>' && ch !== '<')
break;
else
{
if(result.length === 0)
{
result += ch;
this.pos++;
}
else // === 1
{
if(result !== "=") // 如果第一个字符不是=, 第二个字符必定是=
{
if(ch !== '=')
return this.__FatalError(Expression.INVALID_COMPARE_OPERATOR);
}
else // 如果第一个字符是=, 第二个字符可以是=
{
if(ch === '=')
result += ch;
else
{
break;
}
}
result += ch;
this.pos++;
}
}
if(result.length >= 2)
break;
nStr = this.str.substring(this.pos);
}

if(result === "=")
result = "==";
return result;
};

// 开始计算
Expression.prototype.Calc = function()
{
if(!this.__Ready())
return this.__OnError(0);
return this.__EvalP();
};

// 判断表达式断言
Expression.prototype.Predicate = function()
{
if(!this.__Ready())
return this.__OnError(false);
let a = this.__EvalP();
if(this.HasError())
return this.__OnError(false);
let op = this.__EvalCmp();
if(this.HasError())
return this.__OnError(false);
let b = this.__EvalP();
if(this.HasError())
return this.__OnError(false);
//console.log(a + op + b);
return eval(a + op + b);
};

Expression.prototype.FLAG = function(flags)
{
for(let i of arguments)
{
if((this.flag & i) === i)
return true;
}
return false;
}

// 普通错误, 仅设置可允许忽略的错误时调用, 错误被忽略时不设置错误码
Expression.prototype.__NormalError = function(err)
{
switch(err)
{
case Expression.BY_ZERO:
if(this.FLAG(Expression.PARSE_FLAG_IGNORE_ERROR_BY_ZERO))
return 0;
break;
case Expression.MISSING_PLACEHOLDER:
if(this.FLAG(Expression.PARSE_FLAG_IGNORE_ERROR_MISSING_PLACEHOLDER))
return 0;
break;
case Expression.INVALID_DIGIT:
if(this.FLAG(Expression.PARSE_FLAG_IGNORE_ERROR_INVALID_DIGIT))
return 0;
break;
}
return this.__FatalError(err);
};

// 全局错误处理
Expression.prototype.__OnError = function(ifError)
{
if(this.FLAG(Expression.PARSE_FLAG_ERROR_HANDLE_SCHEME_THROW_EXCEPTION)) // 抛异常
{
throw new Error(this.Error());
}
else // 返回0
{
return ifError;
}
};

// 计算是否有错误
Expression.prototype.HasError = function()
{
return this.errno !== Expression.NO_ERROR;
};

// 返回计算的错误, 并清除错误
Expression.prototype.GetError = function()
{
let e = this.errno;
this.errno = Expression.NO_ERROR;
return e;
}

// 获取当前错误的字符串
Expression.prototype.Error = function()
{
return Expression.ErrorStr[this.errno];
}

// 致命错误
Expression.prototype.__FatalError = function(err)
{
this.errno = err;
throw new Error(this.Error());
};

Expression.prototype.ParsedPlaceholders = function()
{
return this.placeholders;
}

// 解析占位符
Expression.prototype.__ParsePlaceholder = function(name)
{
this.placeholders.push(name);
if(!this.placeholderValueMap)
{
return this.__NormalError(Expression.MISSING_PLACEHOLDER);
}
if(name.startsWith("$")) // 特殊环境变量
return this.__ParseNumber(this.placeholderValueMap[name]);

let ptr = this.placeholderValueMap;
let d = null;
let notFetch = false;
let i = 0;
do
{
let index = name.indexOf(".", i);
let s = index === -1 ? name.substring(i) : name.substring(i, index);
i += s.length + 1;
s = s.trim();
if(s.startsWith("$")) // 函数管线
{
if(!notFetch) // 此时当前值应该是数字, 不再继续向下取Object/Map
{
d = this.__ParseNumber(ptr); // 当前值转换为数字
notFetch = true; // 此时当前值应该是数字, 不再继续向下取Object/Map
}
switch(s.substring(1).toLowerCase())
{
case "abs":
d = Math.abs(d);
break;
case "neg":
d = -d;
break;
case "lt0":
if(d >= 0)
return 0;
break;
case "gt0":
if(d <= 0)
return 0;
break;
default:
return this.__FatalError(Expression.INVALID_PLACEHOLDER_FUNCTION);
}
}
else
{
if(notFetch/*null != d*/) // TODO: 被管线函数处理过, 占位符表达式书写不应该出现该情况, 管线函数应都在表达式尾部, 并且不在表达式起始
return d;
ptr = ptr[s];
if(null === ptr || undefined === ptr)
{
return this.__NormalError(Expression.MISSING_PLACEHOLDER);
}
}
} while(i < name.length);
if(null == d)
return this.__ParseNumber(ptr);
else
return d;
};

// 检查表达式字符串
Expression.prototype.__CheckStr = function()
{
if(!this.str)
{
return Expression.NULL_STRING;
}
return Expression.NO_ERROR;
};

// 跳过空白符
Expression.prototype.__SkipBlank = function()
{
let i = 0;
for(; (this.pos + i) < this.str.length; i++)
{
if(!/\s/.test(this.str.charAt(this.pos + i)))
break;
}
this.pos += i;
return i;
};

// 对象转数字
Expression.prototype.__ParseNumber = function(val)
{
if(null === val)
return this.__NormalError(Expression.INVALID_DIGIT);
if(val instanceof Number)
return val;
else
{
try
{
return this.__StrTo(val.toString());
}
catch(e)
{
console.error(e);
return this.__NormalError(Expression.INVALID_DIGIT);
}
}
};


+ 11
- 0
src/utils/index.js 查看文件

@@ -1206,3 +1206,14 @@ export function manual_page(list, page_no = 1, page_size = 10)
let start = (page_no - 1) * page_size;
return list.slice(start, start + page_size);
}

export function array_toMap(arr, byFunc, overriding)
{
let res = {};
arr.forEach((x) => {
let a = byFunc(x);
if(!res.hasOwnProperty(a) || overriding)
res[a] = x;
});
return res;
}

+ 4
- 0
src/utils/utils.js 查看文件

@@ -158,3 +158,7 @@ export function isBankCard (str_cardNo) {
return false;
}
}

export function is_not_number(val) {
return (val === null || val === undefined || val === '');
}

+ 278
- 0
src/views/sunVillage_info/entityReport/reportList.vue 查看文件

@@ -0,0 +1,278 @@
<template>
<div class="app-container">
<div class="header_main-placeholder">
<div class="header_main">
综合填报
<div class="return_btn" @click="$router.back()"></div>
<div class="add_btn" @click="add"></div>
</div>
</div>

<van-pull-refresh v-model="refreshing" @refresh="getList()">
<van-list
class="list_main"
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="getList('+1')"
>

<van-swipe-cell class="item" v-for="(item,index) in list" :key="index">
<div class="item_box" @click="view(item)">
<div class="head_block">
<i class="icon"></i>
<div class="title">{{item.reportName}}</div>
</div>

<div class="order_block">
<div class="flex_block">
<i class="icon icon_1"></i>
<div class="text">{{item.operatorDate}}</div>
</div>
<div class="flex_block" v-if="item.operatorName">
<i class="icon icon_2"></i>
<div class="text">{{item.operatorName}}</div>
</div>
<div class="flex_block" v-if="item.operatorDepartment">
<i class="icon icon_2"></i>
<div class="text">{{item.operatorDepartment}}</div>
</div>
</div>
</div>
<template #right>
<van-row class="full-height toolbar">
<van-col class="full-height">
<van-button square text="修改" type="info" :to="{name:'entityReportView', query: {reportId:item.id, intent: 'edit'}}" class="full-height" />
</van-col>
<van-col class="full-height">
<van-button square text="删除" type="danger" @click="remove(item,index)" class="full-height" />
</van-col>
</van-row>
</template>
</van-swipe-cell>
</van-list>
</van-pull-refresh>
</div>
</template>

<script>
import {delReport, listReport} from "@/api/sunVillage_info/entity/report.js";
export default {
name: "ReportList",
data() {
return {
list:[],
loading: false,
finished: false,
refreshing: false,
total: 0,
queryParams:{
pageNum:1,
pageSize:10,
orderByColumn:'createTime',
isAsc:'desc'
}
};
},
created() {
this.getList();
},
methods: {
add() {
this.$router.push({
name: 'entityReportView',
query: {
intent: 'add',
}
});
},
view(row){
this.$router.push({
name: 'entityReportView',
query: {
intent: 'view',
reportId: row.id,
}
});
},
getList(target){
let type = typeof (target);
//console.log(type, target);
if(target && this.finished)
return;
if (target === 0) {
this.refreshing = true;
this.finished = true;
this.total = 0;
this.queryParams.pageNum = 1;
this.list = [];
}
else if (type === 'number')
this.queryParams.pageNum = target;
else if (type === 'string') {
this.queryParams.pageNum = eval(this.queryParams.pageNum + target)
}
else
{
this.refreshing = true;
this.finished = true;
this.total = 0;
this.queryParams.pageNum = 1;
this.list = []
}
listReport(this.queryParams).then(response => {
if (response.rows.length === 0) {
this.finished = true;
return;
}
this.list = response.rows;
this.total += response.rows.length;
this.finished = this.total >= response.total;
}).finally(() => {
this.loading = false;
this.refreshing = false;
});
},
remove(row, index){
this.$dialog.confirm({
message: '您确认删除综合填报?',
})
.then(() => {
delReport(row.id).then(res => {
this.$toast.success('删除成功');
this.list.splice(index,1);
});
})
.catch(() => {
});
},
refresh() {
this.getList(); return;
this.list = [];
this.queryParams.pageNum = 1;
this.refreshing = true;
this.finished = false;
},
},
}
</script>

<style scoped lang="scss">
.app-container {
//padding: 0.2rem 3%;
width: 100vw;
height: 100vh;
}
.full-height {
height: 100%;
}
.header_main-placeholder {
height: 116px;
}
.header_main {
height: 116px;
background: url('../../../assets/images/sunVillage_info/list_head.png') no-repeat;
background-size: 100% 100%;
position: fixed;
top: 0;
left: 0;
width: 100%;
font-size: 36px;
line-height: 116px;
text-align: center;
color: #fff;
z-index: 999;

.return_btn {
width: 24px;
height: 43.2px;
background: url('../../../assets/images/sunVillage_info/list_icon_5.png') center center no-repeat;
background-size: 20px 36px;
position: absolute;
left: 38px;
top: 36px;
}

.add_btn {
width: 56.4px;
height: 40.8px;
background: url('../../../assets/images/sunVillage_info/list_icon_9.png') center center no-repeat;
background-size: 47px 34px;
position: absolute;
right: 38px;
top: 36px;
}
}

.list_main{
padding:26px 22px 0;
.item{
height: 162px;
border-radius: 30px;
background: #fff;
box-shadow: 4px 6px 5px rgba(63, 68, 75, 0.1);
margin-bottom: 20px;
.item_box{
padding:25px 32px;
}
.head_block{
height: 62px;
display: flex;
align-items: center;
width: 100%;
.icon{
width: 34px;
height: 30px;
background: url('../../../assets/images/sunVillage_info/fixedAssets_icon_4.png') no-repeat;
background-size: 100% 100%;
display: block;
margin-right: 12px;
}
.title{
flex:1;
font-size: 32px;
color: #252525;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-right: 20px;

}
}
.order_block{
display: flex;
height: 52px;
padding-top: 12px;
font-size: 24px;
color: #858585;
align-items: center;
padding-bottom: 10px;
.flex_block{
display: flex;
align-items: center;
justify-content: center;
margin-right: 28px;
height: 42px;
.icon{
width: 25px;
height: 25px;
margin-top: 3px;
margin-right: 8px;
&.icon_1{
background: url('../../../assets/images/sunVillage_info/fixedAssets_icon_3.png') no-repeat;
background-size: 100% 100%;
}
&.icon_2{
background: url('../../../assets/images/sunVillage_info/fixedAssets_icon_5.png') no-repeat;
background-size: 100% 100%;
}
}
}
}
}
}

.toolbar {
margin-left: 2px;
}
</style>

+ 595
- 0
src/views/sunVillage_info/entityReport/reportView.vue 查看文件

@@ -0,0 +1,595 @@
<template>
<div class="app-container">
<div class="header_main-placeholder">
<div class="header_main">
综合填报
<div class="return_btn" @click="back"></div>
<div class="add_btn" @click="save" v-if="(isAdd || isEdit) && editorData.templateId"></div>
</div>
</div>

<van-form ref="form" :class="{'form_readonly': disableEdit}">
<van-row>
<van-col :span="editorData.templateId ? 16 : 24">
<field-select
class="template-selector"
v-model="editorData.templateId"
label=" 模板"
value-key="reportName"
data-key="id"
placeholder="报表模板"
:rules="[{ required: true }]"
:required="true"
:readonly="disableEdit"
:columns="templateList"
@input="getTemplate"
/>
</van-col>
<van-col span="8" v-if="!!editorData.templateId">
<field-date-picker
class="field_no-label"
v-model="editorData.reportYear"
placeholder="报表年度"
formatter="yyyy"
:readonly="disableEdit"
input-align="center"
type="year"
/>
</van-col>
</van-row>
<van-row v-if="!!editorData.templateId">
<van-col span="8">
<van-field class="field_no-label" :readonly="disableEdit" v-model="editorData.titleLeft" label="" placeholder="左上" input-align="left"/>
</van-col>
<van-col span="8">
<van-field class="field_no-label" :readonly="disableEdit" v-model="editorData.titleCenter" label="" placeholder="中上" input-align="center"/>
</van-col>
<van-col span="8">
<van-field class="field_no-label" :readonly="disableEdit" v-model="editorData.titleRight" label="" placeholder="右上" input-align="right"/>
</van-col>
</van-row>

<div class="main-table" v-if="!!editorData.templateId">
<table>
<thead>
<tr>
<td v-for="(header) in removePlaceholder(editorData.headers)" :colspan="header.colspan" :style="{
'background-color': calcColor(header.type),
'color': calcTextColor(header.type),
}">
{{header.headerName}}
</td>
</tr>
</thead>

<tbody>
<tr v-for="(row, rindex) in editorData.rows">
<td v-for="(col) in removePlaceholder(row)" :colspan="col.colspan" :rowspan="col.rowspan" :style="{
'text-align': calcAlign(editorData.headers[col.colIndex].type),
'background-color': calcColor(editorData.headers[col.colIndex].type),
}">
<div class="full-height" v-if="editorData.headers[col.colIndex].type === '2'" :class="{'validate-error': col.error, 'validate-error-box': col.error,}">
<input class="input-field align-right full-height" v-model="col.val" :readonly="disableEdit" type="number"></input>
</div>
<div class="full-height" v-else-if="editorData.headers[col.colIndex].type === '4'">
<input class="input-field align-center full-height" v-model="col.name" :readonly="disableEdit"></input>
</div>
<div v-else :style="{'text-align': calcAlign(editorData.headers[col.colIndex].type)}">{{col.name}}</div>
</td>
</tr>
</tbody>
</table>
</div>

<template v-if="!!editorData.templateId">
<div>
<van-field :readonly="disableEdit" v-model="editorData.reportRemark" label="备注" placeholder="报表备注"/>
</div>
<div>
<van-field readonly :value="editorData.rule" label="规则" placeholder="报表效验公式">
<template #extra>
<van-button :disabled="!editorData.rule" style="height: 100%;" type="primary" size="small" @click="validate(true)">效 验</van-button>
</template>
</van-field>
</div>

<van-row>
<van-col span="8">
<van-field class="field_no-label" :readonly="disableEdit" v-model="editorData.operatorDepartment" label="" placeholder="填报单位" input-align="left"/>
</van-col>
<van-col span="8">
<van-field class="field_no-label" :readonly="disableEdit" v-model="editorData.operatorName" label="" placeholder="填报人" input-align="center"/>
</van-col>
<van-col span="8">
<field-date-picker
class="field_no-label"
v-model="editorData.operatorDate"
placeholder="填报日期"
formatter="yyyy-MM-dd"
:readonly="disableEdit"
input-align="right"
/>
</van-col>
</van-row>
</template>
</van-form>
</div>
</template>

<script>
import FieldSelect from "@/components/form/FieldSelect";
import {
addReport, delReport,
getReport,
getReportTemplate,
listReporttitle,
updateReport
} from "@/api/sunVillage_info/entity/report";
import {array_grouping, array_toMap, date_format} from "@/utils";
import {Expression} from "@/utils/expression";
import {is_not_number} from "@/utils/utils";
import FieldDatePicker from "@/components/form/FieldDatePicker";
import {Notify} from "vant";
export default {
name: "ReportView",
components: {FieldDatePicker, FieldSelect},
data() {
return {
editorData: {
id: null,
templateId: null,
reportRemark: null,
titleLeft: null,
titleCenter: null,
titleRight: null,
reportStatus: "0",
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
reportName: '',
operatorName: '',
operatorDate: '',
operatorDepartment: '',
rule: null,
reportYear: date_format('%Y'),
headers: [],
rows: [],
cells: [],
rules: [],
},
templateList: [],
loading: false,
disableEdit: false,
intent: 'add',
reportId: null,
};
},
created() {
this.getTemplateList();
this.parseQuery();
},
mounted(){
this.init();
},
methods: {
getTemplateList() {
listReporttitle({reportStatus: '0'}).then((resp) => {
this.templateList = resp.rows;
});
},
getTemplate() {
if(!this.editorData.templateId && !this.editorData.id)
return;
this.loading = true;
if(this.editorData.id) // 修改
{
getReport(this.editorData.id).then((resp) => {
let reportData = resp.data;
getReportTemplate(reportData.templateId).then((resp) => {
let templateData = resp.data;
this.setTableData(templateData, reportData);
}).finally(() => {
this.loading = false;
});
}).catch(() => {
this.loading = false;
});
}
else
{
getReportTemplate(this.editorData.templateId).then((resp) => {
let templateData = resp.data;
this.setTableData(templateData);
}).finally(() => {
this.loading = false;
});
}
},
setTableData(templateData, reportData) {
let data;
if(!reportData)
{
data = templateData;
data.rows.forEach((x) => {
x.forEach((y) => {
y.error = false;
});
});
}
else
{
let cells = reportData.cells;
data = reportData;
data.headers = templateData.headers;
data.rows = templateData.rows;
data.cells = templateData.cells;
data.rules = templateData.rules;
data.rule = templateData.rule;

let group = array_grouping(cells, (x) => x.rowIndex);
Object.keys(group).forEach((x) => group[x] = array_toMap(group[x], (x) => x.colIndex));
data.rows.forEach((cols, rowIndex) => {
cols.forEach((x) => {
if(group[rowIndex] && group[rowIndex][x.colIndex])
{
if(templateData.headers[x.colIndex].type === '4')
x.name = group[rowIndex][x.colIndex].name;
x.val = group[rowIndex][x.colIndex].val;
}
})
});
}
this.editorData = data;
if(this.editorData.id)
this.validate();
},
cellIsPlaceholder(x) {
return x.colspan <= 0 || (x.hasOwnProperty('rowspan') && x.rowspan <= 0);
},
removePlaceholder(cells) {
return cells.filter((x) => !this.cellIsPlaceholder(x));
},
calcAlign(type) {
switch(type)
{
case '2':
return 'right';
case '3':
case '4':
return 'center';
case '1':
return 'left';
}
},
calcColor(type) {
switch(type)
{
case '2':
return 'unset';
case '4':
return 'unset';
case '3':
return '#d7e8f3';
case '1':
return '#aad8f6';
}
},
calcTextColor(type) {
switch(type)
{
case '2':
case '4':
return '#2facfe';
case '3':
case '1':
return '#858585';
}
},
save() {
let validateResult = this.validate();
if(validateResult)
this.requestSave();
else
{
this.$dialog.confirm({
message: '报表存在不通过的效验, 是否继续提交?',
})
.then(() => {
return this.requestSave();
})
.catch(() => {
});
}
},
requestSave() {
this.$refs.form.validate().then(() => {
this.preHandle();
this.loading = true;
let func = this.editorData.id ? updateReport : addReport;
func(this.editorData).then((resp) => {
this.notify("保存成功!", 'success');
this.back();
}).finally(() => {
this.loading = false;
});
}).catch(() => {
this.notify("请填写完整表单", 'danger');
this.$refs.form.scrollToField();
});
},
preHandle() {
this.editorData.cells = [];
this.editorData.rows.forEach((x) => this.editorData.cells.push(...x));
},
reset() {
this.$refs.form.resetValidation();
this.editorData = {
id: null,
deptId: null,
deptName: null,
templateId: null,
reportName: null,
reportYear: null,
reportRemark: null,
titleLeft: null,
titleCenter: null,
titleRight: null,
rule: null,
operatorName: null,
operatorDate: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
headers: [],
rows: [],
cells: [],
rules: [],
};
},
validate(showMsg) {
if(!this.editorData.rules || !this.editorData.rules.length)
return true;
let errors = [];
for(let i in this.editorData.headers)
{
let header = this.editorData.headers[i];
if(header.type !== '2')
continue;
let map = {};
for(let m in this.editorData.rows)
{
let cell = this.editorData.rows[m][i];
map['' + (Number(m) + 1)] = is_not_number(cell.val) ? 0 : Number(cell.val);
this.$set(this.editorData.rows[Number(m)][Number(i)], 'error', false);
}
for(let m in this.editorData.rules)
{
let rule = this.editorData.rules[m];
let exp = new Expression(rule, Expression.PARSE_FLAG_ALL_NUMBER_AS_PLACEHOLDER | Expression.PARSE_FLAG_ERROR_HANDLE_SCHEME_THROW_EXCEPTION, map);
try
{
let res = exp.Predicate();
//console.log(rule, res);
if(!res)
{
errors.push(`第${Number(i) + 1}列效验错误: ${rule}`);
}
let placeholders = exp.ParsedPlaceholders();
for(let n in placeholders)
{
if(!res)
this.$set(this.editorData.rows[Number(placeholders[n]) - 1][Number(i)], 'error', true);
}
}
catch(e)
{
console.log(e);
errors.push(e);
}
}
}
if(showMsg)
{
this.$dialog.alert({
title: errors.length ? '效验错误' : '效验成功',
message: errors.join('<br/>'),
allowHtml: true,
});
}
return errors.length === 0;
},
parseQuery() {
let query = this.$route.query;
this.reportId = query.reportId;
this.intent = query.intent;
if(!this.reportId)
{
this.intent = 'add';
return;
}
if(this.intent === 'add')
{
this.reportId = null;
}
},
init() {
this.editorData.id = this.reportId;
this.getTemplate();
this.disableEdit = this.intent === 'view';
},
back() {
this.$router.back();
},
notify(message, type) {
Notify.clear();
Notify({ type: type || 'primary', message: message });
},
},
computed: {
isAdd() {
return this.intent === 'add';
},
isEdit() {
return this.intent === 'edit';
},
isView() {
return this.intent === 'view';
},
}
}
</script>

<style scoped lang="scss">
.app-container{
background: #e9e9e9;
min-height: 100vh;
width: 100vw;
.header_main-placeholder {
height: 116px;
}

.header_main {
height: 116px;
background: url('../../../assets/images/sunVillage_info/list_head.png') no-repeat;
background-size: 100% 100%;
position: fixed;
top: 0;
left: 0;
width: 100%;
font-size: 36px;
line-height: 116px;
text-align: center;
color: #fff;
z-index: 999;

.return_btn {
width: 24px;
height: 43.2px;
background: url('../../../assets/images/sunVillage_info/list_icon_5.png') center center no-repeat;
background-size: 20px 36px;
position: absolute;
left: 38px;
top: 36px;
}

.add_btn {
width: 56.4px;
height: 40.8px;
background: url('../../../assets/images/sunVillage_info/list_icon_9.png') center center no-repeat;
background-size: 47px 34px;
position: absolute;
right: 38px;
top: 36px;
}
}

.main-table {
overflow-x: auto;
overflow-y: auto;
position: relative;
background-color: #ffffff;
padding: 0.15rem 0.15rem;
border-radius: 0.15rem;
margin: 0.1rem 0.1rem;

table {
width: max-content;
border-collapse: collapse;
border: 0.01rem solid #1989fa;
table-layout: fixed;
}
thead td {
text-align: center;
border: 0.01rem solid #1989fa;
height: 1rem;
font-size: 0.32rem;
padding: 0 0.4rem;
margin: 0;
font-weight: bold;
max-width: 1.2rem;
}
tbody td {
font-size: 0.3rem;
border: 0.01rem solid #1989fa;
height: 1rem;
white-space: break-spaces;
word-wrap: break-word;
overflow-wrap: break-word;
padding: 0;
margin: 0;
max-width: 1.5rem;
position: relative;
}

.input-field {
width: 100%;
background-color: unset;
border: 0;
}

.validate-error {
color: #F56C6C;
}
.validate-error-box {
color: #F56C6C;
border: 0.02rem solid #F56C6C;
}
}
.align-right {
text-align: right;
}
.align-center {
text-align: center;
}
.full-height {
height: 100%;
}

/deep/ .van-field__label {
background-color: #2facfe;
margin: 0;
color: #fff;
border-top-left-radius: 0.15rem;
border-bottom-left-radius: 0.15rem;
padding: 0 0.2rem;
display: flex;
align-items: center;
}

/deep/ .van-field__body {
background-color: #ffffff;
border-top-right-radius: 0.15rem;
border-bottom-right-radius: 0.15rem;
padding: 0 0.1rem;
}

/deep/ .van-field__body {
height: 100%;
}

/deep/ .van-field {
background-color: unset;
padding: 0.1rem 0.15rem;
height: 1rem;
}

.field_no-label /deep/ .van-field__body {
border-top-left-radius: 0.15rem;
border-bottom-left-radius: 0.15rem;
}

.template-selector /deep/ span {
padding-left: 0.8rem;
background: #2facfe url('../../../assets/images/sunVillage_info/list_icon_11.png') left center no-repeat;
background-size: 0.45rem;
}

.form_readonly /deep/ .van-icon-arrow-down {
display: none;
}
}


</style>

Loading…
取消
儲存