信息填报

master
lion 1 year ago
parent be9171d907
commit 25fa8562c2

@ -0,0 +1,64 @@
import request from "@/utils/request";
export function index (params,isLoading=true) {
return request({
method: "get",
url: "/api/admin/department-category/index",
params,
isLoading
})
}
export function store (data,isLoading=true) {
return request({
method: "post",
url: "/api/admin/department-category/store",
data,
isLoading
})
}
export function show (params,isLoading=true) {
return request({
method: "get",
url: "/api/admin/department-category/show",
params,
isLoading
})
}
export function save (data,isLoading=true) {
return request({
method: "post",
url: "/api/admin/department-category/save",
data,
isLoading
})
}
export function destroy (data,isLoading=true) {
return request({
method: "post",
url: "/api/admin/department-category/delete",
data,
isLoading
})
}
export function categoryYears(params,isLoading=true) {
return request({
method: "get",
url: "/api/admin/get-years",
params,
isLoading
})
}
export function categoryTypes(params,isLoading=true) {
return request({
method: "get",
url: "/api/admin/get-department-category-types",
params,
isLoading
})
}

@ -0,0 +1,37 @@
import request from "@/utils/request";
export function index (params,isLoading=true) {
return request({
method: "get",
url: "/api/admin/category-rule/list",
params,
isLoading
})
}
export function store (data,isLoading=true) {
return request({
method: "post",
url: "/api/admin/category-rule/store",
data,
isLoading
})
}
export function save (data,isLoading=true) {
return request({
method: "post",
url: "/api/admin/category-rule/save",
data,
isLoading
})
}
export function destroy (data,isLoading=true) {
return request({
method: "post",
url: "/api/admin/category-rule/delete",
data,
isLoading
})
}

@ -0,0 +1,46 @@
import request from "@/utils/request";
export function index (params,isLoading=true) {
return request({
method: "get",
url: "/api/admin/department-category-type/index",
params,
isLoading
})
}
export function store (data,isLoading=true) {
return request({
method: "post",
url: "/api/admin/department-category-type/store",
data,
isLoading
})
}
export function show (params,isLoading=true) {
return request({
method: "get",
url: "/api/admin/department-category-type/show",
params,
isLoading
})
}
export function save (data,isLoading=true) {
return request({
method: "post",
url: "/api/admin/department-category-type/save",
data,
isLoading
})
}
export function destroy (data,isLoading=true) {
return request({
method: "post",
url: "/api/admin/department-category-type/delete",
data,
isLoading
})
}

@ -0,0 +1,47 @@
import request from "@/utils/request";
export function index (params,isLoading=true) {
return request({
method: "get",
url: "/api/admin/department-record/get-by-category",
params,
isLoading
})
}
export function recordStore (data,isLoading=true) {
return request({
method: "post",
url: "/api/admin/department-record/store",
data,
isLoading
})
}
export function show (params,isLoading=true) {
return request({
method: "get",
url: "/api/admin/department-record/show",
params,
isLoading
})
}
export function save (data,isLoading=true) {
return request({
method: "post",
url: "/api/admin/department-record/save",
data,
isLoading
})
}
export function destroy (data,isLoading=true) {
return request({
method: "post",
url: "/api/admin/department-record/delete",
data,
isLoading
})
}

@ -79,6 +79,11 @@ export const constantRoutes = [{
component: () => import('@/views/full/indexfull.vue'),
hidden: true
},
{
path: '/departmentH5',
component: () => import('@/views/departmentH5/form/index.vue'),
hidden: true
},
{
path: '/fill',
component: Layout,

@ -0,0 +1,100 @@
<template>
<div>
<el-drawer
size="600px"
title="设置清单类型"
:visible.sync="drawer"
direction="rtl">
<div style="padding: 10px 20px;">
<el-descriptions direction="vertical" :column="2" :labelStyle="{ 'font-weight': 600 }">
<el-descriptions-item label="已选清单" :span="2">
<div v-for="(item, index) in selections">
<Tag closable color="primary" @on-close="selections.splice(index, 1)">
{{ item.title }}
</Tag>
</div>
</el-descriptions-item>
<el-descriptions-item label="人员选择" :span="2">
<Transfer
:data="persons"
:target-keys="selectedPersons"
filterable
:filter-method="filterMethod"
@on-change="arr => selectedPersons = arr"></Transfer>
</el-descriptions-item>
<el-descriptions-item label="开始填报月份">
<DatePicker type="month" v-model="startMonth" placeholder="请选择开始填报月份"></DatePicker>
</el-descriptions-item>
<el-descriptions-item label="结束填报月份">
<DatePicker type="month" v-model="endMonth" placeholder="请选择结束填报月份"></DatePicker>
</el-descriptions-item>
</el-descriptions>
<Button type="primary" shape="circle" style="width: 40%;margin-top: 20px;" @click="submit"></Button>
</div>
</el-drawer>
</div>
</template>
<script>
import { index, assignCategoryType } from "@/api/person";
export default {
data() {
return {
drawer: false,
selections: [],
persons: [],
selectedPersons: [],
startMonth: '',
endMonth: ''
}
},
methods: {
async getPersons () {
this.persons = (await index({ page: 1, page_size: 9999 },false)).data.map(i => ({
key: i.id,
label: i.name
}))
},
filterMethod (data, query) {
return data.label.indexOf(query) > -1;
},
setSelections (arr) {
if (arr instanceof Array) {
this.selections = arr
}
},
show () {
this.drawer = true;
},
hide () {
this.drawer = false;
},
submit () {
assignCategoryType({
person_id: this.selectedPersons.toString(),
category_id: this.selections.map(i => i.id).toString(),
start_year_month: this.$moment(this.startMonth).format("YYYY-MM"),
end_year_month: this.$moment(this.endMonth).format("YYYY-MM"),
}).then(res => {
this.hide()
})
}
},
computed: {},
created() {
this.getPersons()
}
}
</script>
<style scoped lang="scss">
::v-deep .ivu-tag {
height: auto;
line-height: 1.5;
padding: 4px 8px;
}
::v-deep .ivu-tag .ivu-icon-ios-close {
top: 0;
}
</style>

@ -0,0 +1,390 @@
<script>
import { index as typeIndex } from "@/api/departmentCategoryType";
import { index as formIndex } from "@/api/system/customForm";
import { save, show, store, index, destroy } from "@/api/departmentCategory";
import { CreateDialog } from "@/utils/createDialog"
import { deepCopy } from "@/utils";
export default {
props: {
options: [Array,Object]
},
render(h) {
let dialog = new CreateDialog(this,[
],{
width: "45%"
})
return dialog.render()
},
data() {
return {
columns: 1,
row: {},
formInfo: [
{
name: '清单名称',
field: 'title',
edit_input: 'text',
form_show: true,
// _props: {
// type: "textarea",
// autoSize: {
// minRows: 2
// }
// }
},
// {
// name: '',
// field: 'require',
// edit_input: 'text',
// form_show: true,
// _props: {
// type: "textarea",
// autoSize: {
// minRows: 4
// }
// }
// },
{
name: '父栏目',
field: 'pid',
_default: 0,
edit_input: 'el-cascader',
form_show: true,
_props: {
disabled:true,
options: this.options,
props: { checkStrictly: true, value: "id", label: "title", disabled: "_disabled" },
},
_events: {
change: (e) => {
this.form.pid = e.at(-1);
}
}
},
{
name: "年份",
field: "year",
edit_input: "el-date-picker",
// edit_input: "text",
form_show: true,
_props: {
'disabled':true,
type: "year",
"value-format": "yyyy"
}
},
{
name: "清单类型",
field: "type_id",
edit_input: "radio",
form_show: true,
_props:{
'disabled':true
},
_params: []
},
// {
// name: "",
// field: "measure_duration",
// edit_input: "radio",
// form_show: true,
// _params: [
// {
// value: "monthly",
// label: ""
// },
// {
// value: "quarterly",
// label: ""
// },
// {
// value: "yearly",
// label: ""
// },
// ]
// },
// {
// name: "",
// field: "measure_type",
// edit_input: "radio",
// form_show: true,
// _params: [
// {
// value: "check",
// label: ""
// },
// {
// value: "reply",
// label: ""
// }
// ]
// },
// {
// name: "",
// field: "measure_reply_quantity",
// edit_input: "el-input-number",
// form_show: true,
// _props: {
// precision: 0,
// controls: false
// }
// },
{
name: '排序值',
field: 'myindex',
edit_input: 'el-input-number',
form_show: true,
_props: {
controls: false
}
}
],
id: "",
type: "add",
dialogVisible: false,
form: {},
originalForm: {},
rules: {
title: [
{ required: true,message: "请填写清单名称" }
],
// type_id: [
// { required: true,message: "" }
// ],
// measure_reply_quantity: [
// {
// validator:(rule,value,cb) => {
// if (this.form['measure_type'] === 'reply') {
// value > 0 ? cb() : cb(new Error('0'))
// } else {
// cb()
// }
// }
// }
// ]
},
file: {},
};
},
methods: {
setRow (row) {
this.row = row
},
init() {
for (let key in this.form) {
if (this.formInfo.find(i => i.field === key)?._default) {
this.form[key] = this.formInfo.find(i => i.field === key)._default
}
else if (this.form[key] instanceof Array) {
this.form[key] = [];
} else {
this.form[key] = "";
}
}
this.$refs["elForm"].clearValidate();
},
setForm(key = [], value = []) {
if (key instanceof Array) {
key.forEach((key, index) => {
this.form[key] = value[index] ?? "";
});
}
if (typeof key === "string") {
this.form[key] = value;
}
if (!key) {
this.init();
}
},
show() {
this.dialogVisible = true;
},
hidden() {
this.dialogVisible = false;
},
setType(type = "add") {
let types = ["add", "editor", "show"];
if (types.includes(type)) {
this.type = type;
} else {
console.warn("Unknown type: " + type);
}
},
setId(id) {
if (typeof id == "number") {
this.id = id;
} else {
console.error("error typeof id: " + typeof id);
}
},
async getDetail() {
const res = await show({ id: this.id });
this.$integrateData(this.form, res);
this.formInfo.forEach((i) => {
if (i && (i.edit_input === "file" || i.edit_input === "files")) {
res[i._relations.link_with_name]
? (this.file[i.field] =
res[i._relations.link_with_name] instanceof Array
? res[i._relations.link_with_name].map((i) => {
return {
name: i?.name,
url: i?.url,
response: i,
};
})
: [
{
name: res[i._relations.link_with_name]?.name,
url: res[i._relations.link_with_name]?.url,
response: res[i._relations.link_with_name],
},
])
: (this.file[i.field] = []);
}
this.form = Object.assign({}, this.form);
this.originalForm = deepCopy(res);
});
},
submit() {
if (this.type === "add") {
if (this.form.hasOwnProperty("id")) {
delete this.form.id;
}
store(this.form).then(res => {
this.$Message.success({
content: `${this.type === "add" ? "新增" : "编辑"}成功`,
});
this.$emit("refresh");
this.hidden();
})
}
if (this.type === "editor") {
Object.defineProperty(this.form, "id", {
value: this.id,
enumerable: true,
configurable: true,
writable: true,
});
save(this.form).then(res => {
this.$Message.success({
content: `${this.type === "add" ? "新增" : "编辑"}成功`,
});
this.$emit("refresh");
this.hidden();
})
}
},
},
computed: {
title () {
if (this.type === 'add') return '新增'
if (this.type === 'editor') return '编辑'
if (this.type === 'show') return '查看'
}
},
watch: {
"form.year":{
handler:function (newVal) {
this.form.year = newVal.toString()
}
},
options(val){
this.$set(this.formInfo.find(i => i.field === 'pid')._props,'options',val)
},
formInfo: {
handler: function (newVal) {
this.form = {};
this.file = {};
newVal.forEach((i) => {
if (i.field) {
this.form[i.field] = (i._default || i._default === 0)? i._default : '';
if (
i.validation instanceof Array &&
i.validation.length > 0 &&
!!i.validation.find((i) => i === "required")
) {
}
if (i.edit_input === "files") {
this.form[i.field] = [];
}
if (i.edit_input === "files" || i.edit_input === "file") {
this.file[i.field] = [];
}
if (i.edit_input === "checkbox") {
this.form[i.field] = [];
}
if (i._relations) {
this.form[i._relations?.link_with_name] = [];
}
}
});
this.columns = newVal.length > 11 ? '2' : '1'
},
immediate: true,
},
dialogVisible(val) {
if (val) {
document.documentElement.style.setProperty(
"--column-num",
this.columns
);
if (this.type === "editor" || this.type === "show") {
this.$nextTick(() => this.getDetail());
}
} else {
this.id = "";
this.type = "";
this.init();
this.$refs["elForm"].clearValidate();
delete this.form.id;
for (let key in this.file) {
this.file[key] = [];
}
}
},
},
created() {
typeIndex({ page: 1,page_size: 999 }).then(res => {
this.formInfo.find(i => i.field === 'type_id')._params = res.data
})
formIndex({ page: 1,page_size: 999 }).then(res => {
this.formInfo.find(i => i.field === 'form_id')._params = res.data
})
}
};
</script>
<style>
:root {
--column-num: 2;
}
</style>
<style scoped lang="scss">
.uploaded-a {
color: red;
text-decoration: none;
transition: all 0.2s;
}
.uploaded-a:hover {
color: red;
text-decoration: underline;
}
.form-body {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(var(--column-num), 1fr);
}
::v-deep .el-input-number.is-without-controls .el-input__inner {
text-align: left;
}
</style>

@ -0,0 +1,221 @@
<template>
<div>
<xy-dialog ref="dialog" :width="60" :is-show.sync="isShow" :type="'form'" :title="title" :form="form">
<template v-slot:table>
<xy-table
ref="xyTable"
:table-item="table"
:list="categoryRuleList"
:isPage='false'
>
<template v-slot:btns>
<el-table-column align='center' label="操作" width="120" header-align="center">
<template slot="header" slot-scope="scope">
<el-button
size="mini" @click="addRules">新增</el-button>
</template>
<template slot-scope="scope" style="display: flex;">
<Button v-if="!scope.row.isEdit" style="margin-right:5px" size="small" type="primary" @click="submitRules(scope.row)"></Button>
<Button v-else style="margin-right:5px" size="small" type="primary" @click="scope.row.isEdit=false"></Button>
<el-popover width="180"
:ref="`${scope.row.id}-${scope.$index}`"
trigger="hover">
<template>
<div>
<p style="padding-bottom: 10px;">确定要删除吗</p>
<div style="text-align: right;margin: 0;">
<el-button size="mini"
type="text"
@click="$refs[`${scope.row.id}-${scope.$index}`].doClose()"
>取消</el-button>
<el-button type="primary"
size="mini"
@click="delRules(scope.row,scope.$index)">确定</el-button>
</div>
</div>
</template>
<template #reference>
<Button
style="margin-right:6px;"
type="error"
size="small">
删除
</Button>
</template>
</el-popover>
</template>
</el-table-column>
</template>
</xy-table>
</template>
<template v-slot:footerContent>
<Button @click="isShow=false,$emit('refresh')"></Button>
</template>
</xy-dialog>
</div>
</template>
<script>
import {
Message
} from 'element-ui'
import { index,store,save,destroy} from "@/api/category/rule.js"
export default {
components: {
},
data() {
return {
isShow: false,
visible:false,
type: 'add',
title:'规则设置',
category_id:'',
id:'',
categoryRuleList:[],
form: {
table:''
},
table:[{
label: "开始日期",
prop: "start_at",
customFn: row => {
return(<el-date-picker v-model={row.start_at}
type="date"
disabled={row.isEdit}
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
placeholder="选择日期">
</el-date-picker>)
}
},{
label: "结束日期",
prop: "end_at",
customFn: row => {
return(<el-date-picker v-model={row.end_at}
type="date"
format="yyyy-MM-dd"
disabled={row.isEdit}
value-format="yyyy-MM-dd"
placeholder="选择日期">
</el-date-picker>)
}
},{
label: "填报数量",
prop: "quantity",
width:80,
customFn: row => {
return(<el-input type='text' disabled={row.isEdit} v-model={row.quantity}></el-input>)
}
},{
label: "备注",
prop: "remark",
customFn: row => {
return(<el-input type='textarea' disabled={row.isEdit} v-model={row.remark}></el-input>)
}
},{
label: "排序",
prop: "myindex",
width:80,
customFn: row => {
return(<el-input type='text' disabled={row.isEdit} v-model={row.myindex}></el-input>)
}
}
],
rules: {
categoryRuleList: [{
required: true,
message: '请选择填报清单'
}]
}
}
},
created() {
},
methods: {
async getCategoryRule(){
const res = await index({
category_id:this.category_id
})
res.map(item=>{
item.isEdit = true
})
this.categoryRuleList = res
console.log("this.categoryRuleList",this.categoryRuleList)
},
addRules(){
this.categoryRuleList.push({
category_id:this.category_id,
isEdit:false,
start_at:'',
end_at:'',
quantity:1,
remark:'',
myindex:0
})
},
delRules(row,index){
if(row.id){
destroy({
id:row.id
}).then(res=>{
this.$Message.success({
content: `删除成功`,
});
this.categoryRuleList.splice(index,1)
})
}else{
this.categoryRuleList.splice(index,1)
}
},
submitRules(row){
console.log("row",row)
if(this.isNull(row.start_at)||this.isNull(row.end_at)){
Message({
type:'warning',
message:'请填写全部信息'
})
return
}
if(row.id){
save(row).then(res => {
this.$Message.success({
content: `保存成功`,
});
this.getCategoryRule()
})
}else{
store(row).then(res => {
this.$Message.success({
content: `保存成功`,
});
this.getCategoryRule()
})
}
},
isNull(p){
return p == '' || p == undefined || p == null || p == 'undefined' || p == 'null';
},
},
watch: {
isShow(newVal) {
if(newVal){
this.getCategoryRule()
}else{
this.title='规则设置'
this.category_id=''
}
},
}
}
</script>
<style scoped lang="scss">
::v-deep .table{
flex-basis: 100%;
}
</style>

@ -0,0 +1,320 @@
<template>
<div>
<div>
<div ref="lxHeader">
<LxHeader style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<div slot="content"></div>
<slot>
<header-content :auths="auths_auth_mixin">
<template #search>
<div>
<div style="margin-bottom:15px;margin-top:15px;">
<span style="margin-right:15px;display: inline-block;width:45px;vertical-align: top;">年度 </span>
<el-radio-group style="width:90%" v-model="select.year" @change="changeYear">
<el-radio style="margin-right:5px;margin-bottom:5px;margin-left:0" v-for="item in yearList" border
:label="item">{{item}}</el-radio>
</el-radio-group>
</div>
<div>
<span style="margin-right:15px;display: inline-block;width:45px;vertical-align: top;">类型 </span>
<el-radio-group style="width:90%" @change="changeCategoryType" v-model="select.category_type_id">
<el-radio style="margin-right:5px;margin-bottom:5px;margin-left:0" v-for="item in categoryTypeList" border
:label="item.id">{{item.title}}</el-radio>
</el-radio-group>
</div>
<!-- <el-date-picker size="small" style="width: 110px;" placeholder="请选择日期" value-format="yyyy" v-model="select.year" type="year"></el-date-picker> -->
<!-- <Button
style="margin-left: 10px;"
type="primary"
@click="getList"
>查询</Button> -->
</div>
</template>
<!-- <template #create>
<Button type="primary" @click="$refs['create'].setType('add'),$refs['create'].show()"></Button>
</template>
<template #setting>
<Button type="primary" :ghost="isStartSelect" @click="isStartSelect = !isStartSelect">设置清单类型</Button>
</template> -->
</header-content>
</slot>
</LxHeader>
</div>
</div>
<div>
<div style="margin-bottom:15px;">
<el-button v-if="select.category_type_id" @click="$refs['create'].setType('add'),
$refs['create'].setForm('type_id', select.category_type_id),
$refs['create'].setForm('year', select.year.toString()),
$refs['create'].show()" plain>新建{{select.year}}{{select.categoryTypeName}}清单</el-button>
</div>
<xy-table ref="xyTable" :is-page="false" :list="list" res-prop="" :indent="20" :row-key="row => row._index"
:table-item="table" :auths="auths_auth_mixin" :req-opt="select" :destroy-action="destroy" @editor="row => {
$refs['create'].setId(row.id);
$refs['create'].setType('editor');
$refs['create'].show();
}" @destroyed="getList">
<template v-slot:btns>
<el-table-column align='center' fixed="right" label="操作" width="220" header-align="center">
<template slot="header" slot-scope="scope">
<el-button
size="mini" @click="">整体克隆</el-button>
</template>
<template slot-scope="scope">
<div style="display: flex;">
<Button v-if="scope.row._type !== 'type'" size="small" type="primary" @click="$refs['create'].setId(scope.row.id),
$refs['create'].setType('editor'),
$refs['create'].show();">编辑</Button>
<el-popover width="180" v-if="scope.row._type !== 'type'" :ref="`${scope.row.id}-${scope.$index}`" trigger="hover">
<template>
<div>
<p style="padding-bottom: 10px;">确定要删除吗</p>
<div style="text-align: right;margin: 0;">
<el-button size="mini" type="text" @click="$refs[`${scope.row.id}-${scope.$index}`].doClose()"></el-button>
<el-button type="primary" size="mini"
@click="$refs['xyTable'].deleteClick(scope.row, 'delete')">确定</el-button>
</div>
</div>
</template>
<template #reference>
<div style="margin-right: 6px;height: 100%;width: 100%;">
<Button type="error" size="small" @click="$refs[`${scope.row.id}-${scope.$index}`].doShow()">
删除
</Button>
</div>
</template>
</el-popover>
<Button size="small" type="primary" @click="createChild(scope.row)"></Button>
</div>
</template>
</el-table-column>
</template>
</xy-table>
</div>
<create ref="create" :options="list" @refresh="getList"></create>
<categorySetting ref="categorySetting"></categorySetting>
</div>
</template>
<script>
import {
index,
destroy,
categoryYears,
categoryTypes
} from "@/api/departmentCategory"
import {
authMixin
} from "@/mixin/authMixin";
import headerContent from "@/components/LxHeader/XyContent.vue";
import LxHeader from "@/components/LxHeader/index.vue";
import create from "./component/create.vue";
import categorySetting from "./component/categorySetting.vue";
export default {
mixins: [authMixin],
components: {
categorySetting,
headerContent,
LxHeader,
create
},
data() {
return {
provideOptions: [],
yearList: [],
categoryTypeList:[],
select: {
year: '',
category_type_id:'',
categoryTypeName:''
},
isStartSelect: false,
list: [],
table: [
// {
// type: "selection",
// width: 48,
// selectable: row => {
// return row._type === 'type' ? false : this.isStartSelect;
// }
// },
{
type: "",
label: "",
prop: "index",
fixed:'left',
width:100,
customFn: row => {
return row._type === 'type' ? row._text : row._index;
}
},
{
prop: "title",
label: '清单',
align: "left",
// fixed:'left',
// width:600,
customFn: row => {
return row._type === 'type' ? ( <span> <i style = "padding: 0 8px;color: rgb(239, 216, 117);"
class = "el-icon-folder-opened"> </i><span style="text-wrap:wrap">{row.title}</span> </span>) : ( <span> < i style = "padding: 0 8px;"
class = "el-icon-document" > </i><span style="text-wrap:wrap">{row.title}</span > </span>)
}
},
// {
// prop: "myindex",
// label: "",
// width:80
// },
]
}
},
async created() {
await this.getPastYears()
// this.yearList = this.getPastYears(5)
await this.getCategoryType()
await this.getList()
// this.select.year = this.$moment().format('YYYY')
},
methods: {
index,
destroy,
async getCategoryType(){
await categoryTypes().then(res=>{
this.categoryTypeList = res
this.select.category_type_id = res.length>0?res[0].id:''
this.select.categoryTypeName = res.length>0?res[0].title:''
})
},
changeYear(e){
if(e){
this.getList()
}
},
changeCategoryType(e){
if(e){
this.categoryTypeList.map(item=>{
if(item.id===e){
this.select.categoryTypeName = item.title
}
})
this.getList()
}
},
toChineseNum(number) {
const chineseNum = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
const chineseUnit = ["", "十", "百", "千", "万", "亿"];
let numStr = number.toString();
let len = numStr.length;
let str = "";
for (let i = 0; i < len; i++) {
str += chineseNum[parseInt(numStr[i])] + chineseUnit[len - 1 - i];
}
str = str.replace(/零[十百千]/g, "零");
str = str.replace(/零+/g, "零");
str = str.replace(/^零+/, "");
str = str.replace(/零+$/, "");
if (str[str.length - 1] === "零") {
str = str.slice(0, -1);
}
return str
},
formatList(data = [], pid) {
data.forEach((item, index) => {
if (item.hasOwnProperty('categories_tree')) {
item._id = item.id
delete item.id;
item._disabled = true
item._type = 'type'
item.children = item.categories_tree
item._text = this.toChineseNum(index + 1)
} else {
item._type = 'doc'
item._index = pid ? `${pid}-${index+1}` : (index + 1)
// item._index = pid ? (index+1) : (index + 1)
}
if (item.children instanceof Array && item.children.length > 0) {
this.formatList(item.children, item._index ? item._index : false)
}
})
},
async getPastYears(years) {
await categoryYears().then(res=>{
this.yearList = res.years
this.select.year = res.selected_year
})
},
async getList() {
let res = await index({
year:this.select.year,
category_type_id:this.select.category_type_id
});
this.formatList(res);
this.list = res;
},
createChild(row) {
let category_type_id = this.select.category_type_id
if(row.type_id){
category_type_id = row.type_id
}
if (row._type === 'type') {
this.$refs['create'].setForm('type_id', category_type_id);
this.$refs['create'].setForm('pid', 0);
this.$refs['create'].setForm('year', this.select.year.toString());
this.$refs['create'].setType('add');
this.$refs['create'].show();
} else {
this.$refs['create'].setForm('type_id', category_type_id);
this.$refs['create'].setForm('pid', row.id);
this.$refs['create'].setForm('year', this.select.year.toString());
this.$refs['create'].setType('add');
this.$refs['create'].show();
}
},
},
computed: {},
watch: {
isStartSelect(newVal) {
const selections = this.$refs['xyTable'].getSelection()
if (!newVal && selections.length > 0) {
this.$refs['categorySetting'].setSelections(selections)
this.$refs['categorySetting'].show()
}
}
}
}
</script>
<style scoped lang="scss">
a {
color: $primaryColor;
text-decoration: none;
transition: all 0.2s;
}
a:hover {
color: $primaryColor;
text-decoration: underline;
}
::v-deep .el-table .cell.el-tooltip{
white-space: wrap!important;
text-wrap:wrap
}
</style>

@ -0,0 +1,237 @@
<script>
import { save, show, store, index, destroy } from "@/api/departmentCategoryType";
import { CreateDialog } from "@/utils/createDialog"
import { deepCopy } from "@/utils";
export default {
props: {
tableName: String,
},
render(h) {
let dialog = new CreateDialog(this,[
],{
width: "480px"
})
return dialog.render()
},
data() {
return {
columns: 1,
row: {},
formInfo: [
{
name: '清单类型名称',
field: 'title',
edit_input: 'text',
form_show: true
},
{
name: '排序值',
field: 'myindex',
edit_input: 'el-input-number',
form_show: true,
_props: {
controls: false
}
}
],
id: "",
type: "add",
dialogVisible: false,
form: {},
originalForm: {},
rules: {
title: [
{ required: true,message: "请填写清单名称" }
]
},
file: {},
};
},
methods: {
setRow (row) {
this.row = row
},
init() {
for (let key in this.form) {
if (this.form[key] instanceof Array) {
this.form[key] = [];
} else {
this.form[key] = "";
}
}
this.$refs["elForm"].clearValidate();
},
show() {
this.dialogVisible = true;
},
hidden() {
this.dialogVisible = false;
},
setType(type = "add") {
let types = ["add", "editor", "show"];
if (types.includes(type)) {
this.type = type;
} else {
console.warn("Unknown type: " + type + "type:add or editor or show");
}
},
setId(id) {
if (typeof id == "number") {
this.id = id;
} else {
console.error("error typeof id: " + typeof id);
}
},
async getDetail() {
const res = await show({ id: this.id });
this.$integrateData(this.form, res);
this.formInfo.forEach((i) => {
if (i && (i.edit_input === "file" || i.edit_input === "files")) {
res[i._relations.link_with_name]
? (this.file[i.field] =
res[i._relations.link_with_name] instanceof Array
? res[i._relations.link_with_name].map((i) => {
return {
name: i?.name,
url: i?.url,
response: i,
};
})
: [
{
name: res[i._relations.link_with_name]?.name,
url: res[i._relations.link_with_name]?.url,
response: res[i._relations.link_with_name],
},
])
: (this.file[i.field] = []);
}
this.form = Object.assign({}, this.form);
this.originalForm = deepCopy(res);
});
},
submit() {
if (this.type === "add") {
if (this.form.hasOwnProperty("id")) {
delete this.form.id;
}
store(this.form).then(res => {
this.$Message.success({
content: `${this.type === "add" ? "新增" : "编辑"}成功`,
});
this.$emit("refresh");
this.hidden();
})
}
if (this.type === "editor") {
Object.defineProperty(this.form, "id", {
value: this.id,
enumerable: true,
configurable: true,
writable: true,
});
save(this.form).then(res => {
this.$Message.success({
content: `${this.type === "add" ? "新增" : "编辑"}成功`,
});
this.$emit("refresh");
this.hidden();
})
}
},
},
computed: {
title () {
if (this.type === 'add') return '新增'
if (this.type === 'editor') return '编辑'
if (this.type === 'show') return '查看'
}
},
watch: {
formInfo: {
handler: function (newVal) {
this.form = {};
this.file = {};
newVal.forEach((i) => {
if (i.field) {
this.form[i.field] = "";
if (
i.validation instanceof Array &&
i.validation.length > 0 &&
!!i.validation.find((i) => i === "required")
) {
}
if (i.edit_input === "files") {
this.form[i.field] = [];
}
if (i.edit_input === "files" || i.edit_input === "file") {
this.file[i.field] = [];
}
if (i.edit_input === "checkbox") {
this.form[i.field] = [];
}
if (i._relations) {
this.form[i._relations?.link_with_name] = [];
}
}
});
this.columns = newVal.length > 11 ? '2' : '1'
},
immediate: true,
},
dialogVisible(val) {
if (val) {
document.documentElement.style.setProperty(
"--column-num",
this.columns
);
if (this.type === "editor" || this.type === "show") {
this.$nextTick(() => this.getDetail());
}
} else {
this.id = "";
this.type = "";
this.init();
this.$refs["elForm"].clearValidate();
delete this.form.id;
for (let key in this.file) {
this.file[key] = [];
}
}
},
},
};
</script>
<style>
:root {
--column-num: 2;
}
</style>
<style scoped lang="scss">
.uploaded-a {
color: red;
text-decoration: none;
transition: all 0.2s;
}
.uploaded-a:hover {
color: red;
text-decoration: underline;
}
.form-body {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(var(--column-num), 1fr);
}
::v-deep .el-input-number.is-without-controls .el-input__inner {
text-align: left;
}
</style>

@ -0,0 +1,88 @@
<template>
<div>
<div>
<div ref="lxHeader">
<LxHeader
style="margin-bottom: 10px; border: 0px; margin-top: 15px"
>
<div slot="content"></div>
<slot>
<header-content :auths="auths_auth_mixin">
<template #search>
<div style="display: flex">
<Button
type="primary"
@click="$refs['xyTable'].getTableData(true)"
>查询</Button
>
</div>
</template>
<template #create>
<Button
type="primary"
@click="$refs['create'].setType('add'),$refs['create'].show()"
>新增</Button
>
</template>
</header-content>
</slot>
</LxHeader>
</div>
</div>
<xy-table ref="xyTable"
:table-item="table"
:auths="auths_auth_mixin"
:action="index"
:destroy-action="destroy"
@editor="row => {
$refs['create'].setId(row.id);
$refs['create'].setType('editor');
$refs['create'].show();
}"></xy-table>
<create ref="create" @refresh="$refs['xyTable'].getTableData()"></create>
</div>
</template>
<script>
import { index,destroy } from "@/api/departmentCategoryType"
import { authMixin } from "@/mixin/authMixin";
import headerContent from "@/components/LxHeader/XyContent.vue";
import LxHeader from "@/components/LxHeader/index.vue";
import create from "./component/create.vue"
export default {
mixins: [authMixin],
components: {
headerContent,
LxHeader,
create
},
data() {
return {
table: [
{
type: "index",
width: 46,
label: "序号"
},
{
prop: "title",
label: "清单类型名称"
},
{
prop: "myindex",
label: "排序"
}
]
}
},
methods: {
index,destroy,
},
computed: {},
}
</script>
<style scoped lang="scss">
</style>

@ -0,0 +1,164 @@
<template>
<div>
<div>
<div ref="lxHeader">
<LxHeader style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<div slot="content"></div>
<slot>
<header-content :auths="auths_auth_mixin">
<template #search>
</template>
</header-content>
</slot>
</LxHeader>
</div>
<div>
<div>
<div style="margin-bottom:15px;margin-top:15px;">
<span style="margin-bottom:15px;display: inline-block;width:45px;vertical-align: top;">年度 </span>
<el-radio-group style="width:90%" v-model="select.year" @change="changeYear">
<el-radio style="margin-right:5px;margin-bottom:15px;margin-left:0" v-for="item in yearList" border
:label="item">{{item}}</el-radio>
</el-radio-group>
</div>
<div style="margin-bottom:15px;margin-top:15px;">
<span style="margin-bottom:15px;display: inline-block;width:45px;vertical-align: top;">部门 </span>
<el-select v-model="select.department_id" @change="changeDep" placeholder="请选择">
<el-option v-for="item in depList" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</div>
<div style="margin-bottom:15px;margin-top:15px;">
<span style="margin-bottom:15px;display: inline-block;width:45px;vertical-align: top;">类型 </span>
<el-radio-group style="width:90%" @change="changeCategoryType" v-model="select.category_type_id">
<el-radio style="margin-right:5px;margin-bottom:5px;margin-left:0" v-for="item in categoryTypeList" border
:label="item.id">{{item.title}}</el-radio>
</el-radio-group>
</div>
<!-- <el-date-picker size="small" style="width: 110px;" placeholder="请选择日期" value-format="yyyy" v-model="select.year" type="year"></el-date-picker> -->
<Button style="margin-left: 10px;width:300px" type="primary" @click="goForm"></Button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {
categoryYears,
categoryTypes
} from "@/api/departmentCategory"
import {
listdept
} from "../../api/system/department.js";
import {
authMixin
} from "@/mixin/authMixin";
import headerContent from "@/components/LxHeader/XyContent.vue";
import LxHeader from "@/components/LxHeader/index.vue";
export default {
mixins: [authMixin],
components: {
headerContent,
LxHeader,
},
data() {
return {
yearList: [],
categoryTypeList: [],
depList: [],
select: {
year: '',
department_id: '',
department_name:'',
category_type_id: '',
categoryTypeName: ''
},
}
},
created() {
this.getPastYears()
this.getCategoryType()
this.getDep()
},
methods: {
async getDep() {
var that = this;
listdept().then(response => {
that.depList = response;
}).catch(error => {
//reject(error)
})
},
async getCategoryType() {
await categoryTypes().then(res => {
this.categoryTypeList = res
this.select.category_type_id = res.length > 0 ? res[0].id : ''
this.select.categoryTypeName = res.length > 0 ? res[0].title : ''
})
},
changeDep(e){
this.depList.map(item=>{
if(item.id===e){
this.select.department_id = item.id
this.select.department_name = item.name
}
})
},
changeYear(e) {},
changeCategoryType(e) {
this.categoryTypeList.map(item=>{
if(item.id===e){
this.select.category_type_id = item.id
this.select.categoryTypeName = item.title
}
})
},
async getPastYears(years) {
await categoryYears().then(res => {
this.yearList = res.years
this.select.year = res.selected_year
})
},
goForm(){
if(!this.select.department_id){
this.$message({
type:'warning',
message:'请选择部门'
})
return
}
this.$router.push({
path:'/departmentH5',
query:this.select
})
}
},
computed: {},
watch: {}
}
</script>
<style scoped lang="scss">
a {
color: $primaryColor;
text-decoration: none;
transition: all 0.2s;
}
a:hover {
color: $primaryColor;
text-decoration: underline;
}
::v-deep .el-table .cell.el-tooltip {
white-space: wrap !important;
text-wrap: wrap
}
</style>

@ -0,0 +1,485 @@
<template>
<div class="card">
<div style="padding: 15px">
<el-radio-group v-model="select.year">
<el-radio v-for="item in years" :label="item" border>{{ item }}</el-radio>
</el-radio-group>
</div>
<div class="info">
<p class="info__title">
<!-- {{ title }} -->
{{queryObj.department_name}}|{{queryObj.categoryTypeName}}|{{queryObj.year}}年填报总览
</p>
</div>
<xy-table
ref="xyTable"
:height="300"
:isHandlerKey="false"
:is-page="false"
:list="categories"
res-prop=""
:indent="20"
:row-key="(row) => row._index"
:table-item="table"
:auths="[]"
:row-style="({ row }) => {
return {
'height': '44px'
}
}"
>
</xy-table>
<el-drawer
title="填报清单"
:visible.sync="isShowDrawer"
position="rtl"
size="750px"
:wrapper-closable="false"
>
<div style="padding: 20px 40px">
<el-form
class="form"
ref="elForm"
:model="form"
:rules="rules"
label-width="80px"
size="small"
>
<el-form-item label="标题" prop="title">
<el-input v-model="form.title" placeholder="请填写标题"></el-input>
</el-form-item>
<el-form-item label="月份" prop="month">
<el-date-picker
@change="changeMonth"
v-model="form.month"
value-format="yyyy-MM"
format="yyyy-MM"
type="month"
placeholder="选择月">
</el-date-picker>
</el-form-item>
<el-form-item label="内容" required prop="content">
<el-input
type="textarea"
:autosize="{ minRows: 15 }"
v-model="form.content"
></el-input>
</el-form-item>
<el-form-item label="附件" prop="files">
<el-upload
class="upload-demo"
:action="action"
multiple
:limit="10"
:headers="{
'Authorization': 'Bearer ' + getToken(true)
}"
:before-upload="beforeUpload"
:on-success="uploadSuccess"
:file-list="fileList"
>
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">{{ type === 'add' ? '' : '' }}</el-button>
<el-button @click="isShowDrawer = false">取消</el-button>
</el-form-item>
</el-form>
</div>
</el-drawer>
<detail ref="show"
@edit="editShow"
@destroyed="() => {
getCategories()
}"></detail>
<!-- getStatics() -->
</div>
</template>
<script>
import detail from "@/views/departmentH5/form/show.vue";
import {
categoryYears,
categoryTypes,
index as category
} from "@/api/departmentCategory"
import {
show,
recordStore,
save
} from "@/api/departmentRecord"
import { getToken } from "@/utils/auth";
export default {
components: {
detail
},
// inject: [ 'statics', 'getStatics'],
data() {
return {
isShowDrawer: false,
formInfo: [],
customForm: {
customFormId: 11,
tableName: "asd",
},
fileList: [],
action: `${process.env.VUE_APP_BASE_API}/api/person/upload-file`,
select: {
year: this.$moment().format("YYYY"),
category_type_id:''
},
years: [],
categories: [],
table: [
{
type: "",
label: "",
prop: "index",
customFn: row => {
return row._type === 'type' ? row._text : row._index;
}
},
{
prop: "title",
label: "清单类型名称",
minWidth: 300,
renderHeader: col => {
return (
<div>{ this.queryObj ? `${this.queryObj.department_name}|${this.queryObj.categoryTypeName}|${this.queryObj.year}年填报清单` : '清单类型名称' }</div>
)
},
align: "left",
customFn: (row) => {
return row._type === "type" ? (
<span>
<i
style="padding: 0 8px;color: rgb(239, 216, 117);"
class="el-icon-folder-opened"
></i>
<span>{row.title}</span>
</span>
) : (
<span>
<i style="padding: 0 8px;" class="el-icon-document"></i>
<span>{row.title}</span>
</span>
);
},
},
{
fixed: "right",
prop: "records_count",
label: "填报情况",
showOverflowTooltip: false,
width: 150,
customFn: (row) => {
return row._is_end ? (
<div>
<Button type="primary" size="small" ghost on={{
['click']:_ => {
this.$refs['show'].setId(row.id)
this.$refs['show'].show()
}
}}>
查看
<Icon type="ios-search"></Icon>
</Button>
<Button type="primary" size="small"
on={{
['click']: e=>{
this.type = "add"
this.isShowDrawer = true;
this.form.category_id = row.id
this.form.department_id = this.queryObj.department_id
}
}}>
填报
<Icon type="ios-arrow-down"></Icon>
</Button>
</div>
) : '';
},
},
{
fixed: "right",
label: "填报数量",
width: 116,
prop:''
},
],
type: "add",
pickRule: [],
queryObj:{},
form: {
category_id: "",
department_id:'',
title: "",
month:'',
content: "",
files: "",
},
rules: {
content: [{ required: true, message: "请填写内容" }]
},
};
},
mounted(){
let query = this.$route.query
console.log("query",this.$route)
this.queryObj = query
this.form.department_id = this.queryObj.department_id
this.select.category_type_id = this.queryObj.category_type_id
},
methods: {
getToken,
changeMonth(e){
console.log(e)
},
beforeUpload(file) {
if (file.size / 1000 > 20 * 1024) {
this.$message({
type: "warning",
message: "上传大小超过20Mb",
});
return false;
}
},
uploadSuccess (response, file, fileList) {
this.fileList = fileList
},
async getDetail (id) {
const res = await show({
id
})
this.$integrateData(this.form, res)
this.form.id = id
this.fileList = res?.files?.map(i => ({
name: i.original_name,
url: i.url,
response: i
})) || []
},
async editShow (id) {
this.type = 'edit'
await this.getDetail(id)
this.isShowDrawer = true
},
toChineseNum(number) {
const chineseNum = [
"零",
"一",
"二",
"三",
"四",
"五",
"六",
"七",
"八",
"九",
];
const chineseUnit = ["", "十", "百", "千", "万", "亿"];
let numStr = number.toString();
let len = numStr.length;
let str = "";
for (let i = 0; i < len; i++) {
str += chineseNum[parseInt(numStr[i])] + chineseUnit[len - 1 - i];
}
str = str.replace(/零[十百千]/g, "零");
str = str.replace(/零+/g, "零");
str = str.replace(/^零+/, "");
str = str.replace(/零+$/, "");
if (str[str.length - 1] === "零") {
str = str.slice(0, -1);
}
return str;
},
formatList(data = [], pid) {
data.forEach((item, index) => {
if (item.hasOwnProperty('categories_tree')) {
item._id = item.id
delete item.id;
item._disabled = true
item._type = 'type'
item.children = item.categories_tree
item._text = this.toChineseNum(index + 1)
} else {
item._type = 'doc'
item._index = pid ? `${pid}-${index+1}` : (index + 1)
// item._index = pid ? (index+1) : (index + 1)
}
if (item.children instanceof Array && item.children.length > 0) {
this.formatList(item.children, item._index ? item._index : false)
} else {
item._is_end = 1
}
})
},
async getCategories() {
console.log("this.select",this.select)
const res = await category(this.select, false);
this.formatList(res);
this.categories = res;
},
async getYears () {
const res = await categoryYears();
this.select.year = res.selected_year;
this.years = res.years;
},
onSubmit() {
console.log("this.form",this.form)
// return
this.$refs["elForm"].validate((res) => {
if (res) {
this.form.files = this.fileList.map((i) => i.response.id).toString();
if (this.type === 'add') {
recordStore(this.form).then((res) => {
this.$message({
type: "success",
message: "填报成功",
});
this.isShowDrawer = false;
this.getCategories()
// this.getStatics()
});
} else {
save(this.form).then((res) => {
this.$message({
type: "success",
message: "修改成功",
});
this.isShowDrawer = false;
this.getCategories()
this.$refs['show'].getData()
});
}
}
});
},
},
computed: {
},
watch: {
type (newVal) {
if (newVal === 'add') {
delete this.form.id
}
},
isShowDrawer (newVal) {
if (newVal) {
} else {
this.fileList = [];
this.form = {
category_id: "",
department_id:'',
title: "",
month:'',
content: "",
files: "",
}
this.$refs['elForm'].clearValidate()
}
}
},
created() {
this.getYears();
this.getCategories();
},
};
</script>
<style lang="scss">
.el-cascader-node__label {
max-width: 300px;
}
</style>
<style scoped lang="scss">
.card {
height: 100%;
background-color: #fff;
margin: 40px;
}
.info {
border-top: 1px solid #EBEEF5;
background: #faf0e9;
padding: 10px 15px;
&__title {
font-size: 22px;
font-weight: 600;
padding-bottom: 8px;
}
&__status {
$color: #377e22,#f2a93c,#ea3423;
display: flex;
align-items: center;
font-size: 12px;
@mixin cir {
padding: 8px;
border-radius: 100%;
margin: 0 6px;
}
@for $i from 1 through length($color) {
.cir#{$i} {
@include cir;
background: nth($color, $i);
}
}
}
}
::v-deep .table-tree {
height: 100%;
background: #f0f2f8;
}
::v-deep .el-radio__input.is-checked + .el-radio__label {
color: #c4312b;
}
::v-deep .el-radio__input.is-checked .el-radio__inner {
background-color: #c4312b;
border-color: #c4312b;
}
::v-deep .el-radio__inner {
width: 18px;
height: 18px;
}
::v-deep .el-radio__input.is-checked .el-radio__inner:after {
content: "";
width: 12px;
height: 6px;
margin-top: -1px;
border: 2px solid white;
border-top: transparent;
border-right: transparent;
text-align: center;
display: block;
position: absolute;
top: 50%;
left: 50%;
vertical-align: middle;
transform: translate(-50%, -50%) rotate(-45deg);
border-radius: 0px;
background: none;
}
::v-deep .el-tabs__nav-wrap::after {
background-color: #ebeef5;
}
</style>

@ -0,0 +1,126 @@
<template>
<div>
<el-dialog title="填报" width="860px" :visible.sync="visible">
<xy-table style="width: 820px"
stripe
ref="xyTable"
:req-opt="select"
:is-first-req="false"
:height="500"
:action="getByCategory"
:table-item="table"
:destroy-action="destroy">
</xy-table>
</el-dialog>
</div>
</template>
<script>
import { index as getByCategory, destroy } from "@/api/departmentRecord";
export default {
data() {
return {
auth: ['delete'],
visible: false,
select: {
category_id: ""
},
table: [
{
prop: "title",
label: "标题",
fixed: "left",
width: 180
},
{
prop: "created_at",
label: "填报日期",
width: 160
},
{
prop: "content",
label: "内容",
align: "left",
minWidth: 200
},
{
prop: "operate",
label: "操作",
align: "left",
width: 140,
customFn: row => {
const _this = this
return (
<div>
<Button type="primary"
size="small"
on={{
['click']:_ => {
this.$emit('edit', row.id)
}
}}>编辑</Button>
<Button type="error"
size="small"
on={{
['click']:_ => {
this.$confirm('此操作将永久删除该填报, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
destroy({
id: row.id
}).then(_ => {
this.$message({
type: 'success',
message: '删除成功!'
});
_this.$refs['xyTable'].getTableData()
this.$emit('destroyed')
})
})
}
}}>删除</Button>
</div>
)
}
}
]
}
},
methods: {
getByCategory,destroy,
show () {
this.visible = true;
},
hide () {
this.visible = false;
},
setId (id) {
this.select.category_id = id;
},
getData () {
this.$refs['xyTable'].getTableData()
}
},
computed: {},
watch: {
visible (newVal) {
if (newVal) {
this.$nextTick(_ => {
this.$refs['xyTable'].getTableData(true)
})
} else {
}
}
},
created() {
}
}
</script>
<style scoped lang="scss">
</style>
Loading…
Cancel
Save