Browse Source

费用报销

ggooalice 2 years ago
parent
commit
835e31372d

+ 3 - 2
fhKeeper/formulahousekeeper/timesheet_h5/src/main.js

@@ -15,14 +15,15 @@ import { Form , Toast , Grid, GridItem , DatetimePicker , Popover,
 Picker , Dialog , NumberKeyboard , Sticky , Skeleton ,
 Panel , Divider , List , pullRefresh , SwipeCell, Checkbox, 
 Search, Slider,Stepper,Tag, Calendar, Row, Col, RadioGroup, Radio, 
-Loading ,DropdownMenu, DropdownItem, Button, ActionSheet, PullRefresh,Tabbar, TabbarItem} from 'vant';
+Loading ,DropdownMenu, DropdownItem, Button, ActionSheet, PullRefresh,Tabbar,
+TabbarItem,Uploader,Collapse, CollapseItem} from 'vant';
 
 Vue.use(Form).use(Toast).use(Grid).use(GridItem).use(DatetimePicker)
 .use(Picker).use(Dialog).use(NumberKeyboard).use(Sticky).use(Skeleton)
 .use(Panel).use(Divider).use(List).use(pullRefresh).use(SwipeCell)
 .use(Checkbox).use(Search).use(Slider).use(Stepper).use(Tag).use(Calendar).use(RadioGroup).use(Radio)
 .use(Row).use(Col).use(Loading).use(DropdownMenu).use(DropdownItem).use(Button).use(ActionSheet)
-.use(PullRefresh).use(Tabbar).use(TabbarItem).use(Popover);
+.use(PullRefresh).use(Tabbar).use(TabbarItem).use(Popover).use(Uploader).use(Collapse).use(CollapseItem);
 
 // rem
 import "amfe-flexible";

+ 15 - 0
fhKeeper/formulahousekeeper/timesheet_h5/src/router/index.js

@@ -74,6 +74,21 @@ const router = new Router({
         },
         component: () => import("@/views/task/index")
     },
+    {
+        path: "/expense",
+        meta: {
+            title: "费用报销"
+        },
+        component: () => import("@/views/expense/index")
+    },
+    {
+        path: "/expenseDetails",
+        name: "expenseDetails",
+        meta: {
+            title: "单据编辑"
+        },
+        component: () => import("@/views/expense/details")
+    },
     {
         path: "/projectInside",
         name: "projectInside",

+ 1 - 1
fhKeeper/formulahousekeeper/timesheet_h5/src/utils/request.js

@@ -12,7 +12,7 @@ const service = axios.create({
 // request拦截器,在请求之前做一些处理
 service.interceptors.request.use(
     config => {
-        if(config.url != "/report/editReport" && config.url != "/project/editProject") {
+        if(config.url != "/report/editReport" && config.url != "/project/editProject" && config.url != "/common/uploadFile") {
             config.data = qs.stringify(config.data);
             config.headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8";
         } else {

+ 509 - 0
fhKeeper/formulahousekeeper/timesheet_h5/src/views/expense/details.vue

@@ -0,0 +1,509 @@
+<template>
+    <div class="edit">
+        <van-nav-bar title="报销凭证详情" left-text="返回" @click-left="back" fixed left-arrow />
+        <van-form class="edit_form" label-width="140">
+            <!-- 报销人 -->
+            <van-field
+                v-model="editForm.ownerId"
+                label="报销人"
+                @click="ownerIdShow = true"
+                readonly
+                clickable
+                required
+            >
+                <template #input>{{ formshowText.name }}</template>
+            </van-field>
+            <van-popup v-model="ownerIdShow" position="bottom" v-if="canEdit && canExamine">
+                <van-picker
+                    value-key="name"
+                    show-toolbar
+                    :columns="userList"
+                    @confirm="ownerIdChange"
+                    @cancel="
+                        ownerIdShow = false;
+                        $forceUpdate();
+                    "
+                />
+            </van-popup>
+            <!-- 填报日期 -->
+            <van-field
+                v-model="editForm.createDate"
+                label="填报日期"
+                @click="createDateShow = true"
+                readonly
+                clickable
+                required
+            ></van-field>
+            <van-popup v-model="createDateShow" position="bottom" v-if="canEdit">
+                <van-datetime-picker
+                    type="date"
+                    title="选择填报日期"
+                    @confirm="createDateChange"
+                    @cancel="
+                        createDateShow = false;
+                        $forceUpdate();
+                    "
+                    :min-date="minDate"
+                    :max-date="maxDate"
+                />
+            </van-popup>
+            <!-- 发票张数 -->
+            <van-field label="发票张数" :readonly="!canEdit">
+                <template #input>
+                    <van-stepper v-model="editForm.ticketNum" :disabled="!canEdit" />
+                </template>
+            </van-field>
+            <!-- 费用类型 -->
+            <van-field
+                v-model="editForm.type"
+                label="费用类型"
+                @click="typeShow = true"
+                readonly
+                clickable
+            >
+                <template #input>{{ typeList[editForm.type] }}</template>
+            </van-field>
+            <van-popup v-model="typeShow" position="bottom" v-if="canEdit">
+                <van-picker
+                    show-toolbar
+                    :columns="typeList"
+                    @confirm="typeChange"
+                    @cancel="
+                        typeShow = false;
+                        $forceUpdate();
+                    "
+                />
+            </van-popup>
+            <!-- 备注 -->
+            <van-field v-model="editForm.remark" label="备注" :readonly="!canEdit" type="textarea"></van-field>
+            <!-- 发票 -->
+            <van-field label="发票" readonly>
+                <template #input
+                    >总费用:{{ totalCost | numtosum }} 元</template
+                >
+            </van-field>
+            <div class="invoice" v-if="invoiceList.length != 0">
+                <div
+                    v-for="(item, index) in invoiceList"
+                    :key="item.id"
+                    style="position: relative"
+                    :class="index == 0 ? '' : 'invoice_item'"
+                >
+                    <van-icon
+                        name="delete-o"
+                        class="deletebtn"
+                        @click="deleteInvoice(index)"
+                        v-if="canEdit"
+                    />
+                    <van-field
+                        label="所属项目:"
+                        v-model="item.projectId"
+                        @click="(in_projectShow = true), (invoiceIndex = index)"
+                        readonly
+                        clickable
+                    >
+                        <template #input>{{
+                            formshowText.inProjectName[index]
+                        }}</template>
+                    </van-field>
+                    <van-field
+                        label="费用日期:"
+                        v-model="item.happenDate"
+                        @click="(in_dateShow = true), (invoiceIndex = index)"
+                        readonly
+                        clickable
+                    ></van-field>
+                    <van-field
+                        label="发票种类:"
+                        v-model="item.invoiceType"
+                        @click="(in_typeShow = true), (invoiceIndex = index)"
+                        readonly
+                        clickable
+                    >
+                        <template #input>{{
+                            inTypeList[item.invoiceType]
+                        }}</template>
+                    </van-field>
+                    <van-field
+                        label="费用类型:"
+                        v-model="item.expenseType"
+                        @click="(in_exTypeShow = true), (invoiceIndex = index)"
+                        readonly
+                        clickable
+                    ></van-field>
+                    <van-field
+                        label="费用金额(含税):"
+                        v-model="item.amount"
+                        type="number"
+                        @input="costCount"
+                        :readonly="!canEdit"
+                    ></van-field>
+                    <van-field
+                        label="发票号:"
+                        v-model="item.invoiceNo"
+                        readonly
+                    ></van-field>
+                    <van-field
+                        label="税率%:"
+                        v-model="item.taxPercent"
+                        :readonly="!canEdit"
+                    ></van-field>
+                    <van-field
+                        label="税额:"
+                        v-model="item.taxValue"
+                        :readonly="!canEdit"
+                    ></van-field>
+                    <van-field label="备注:" v-model="item.remark" :readonly="!canEdit"></van-field>
+                    <van-field
+                        label="报销凭证:"
+                        @click="invoiceIndex = index"
+                        :clickable="!canEdit"
+                    >
+                        <template #input>
+                            <van-uploader
+                                v-model="uploader[index]"
+                                :before-read="beforeRead"
+                                :after-read="afterRead"
+                                @delete="item.pic = null"
+                                :max-count="1"
+                                :disabled="!canEdit"
+                                :deletable="!canEdit"
+                            />
+                        </template>
+                    </van-field>
+                </div>
+            </div>
+            <!-- 发票-popup -->
+            <span>
+                <!-- 所属项目 -->
+                <van-popup v-model="in_projectShow" position="bottom" v-if="canEdit">
+                    <van-picker
+                        value-key="projectName"
+                        show-toolbar
+                        :columns="inProjectList"
+                        @confirm="inProjectChange"
+                        @cancel="
+                            in_projectShow = false;
+                            $forceUpdate();
+                        "
+                    />
+                </van-popup>
+                <!-- 费用日期 -->
+                <van-popup v-model="in_dateShow" position="bottom" v-if="canEdit">
+                    <van-datetime-picker
+                        type="date"
+                        title="选择费用日期"
+                        @confirm="inDateChange"
+                        @cancel="
+                            in_dateShow = false;
+                            $forceUpdate();
+                        "
+                        :min-date="minDate"
+                        :max-date="maxDate"
+                    />
+                </van-popup>
+                <!-- 发票种类 -->
+                <van-popup v-model="in_typeShow" position="bottom" v-if="canEdit">
+                    <van-picker
+                        show-toolbar
+                        :columns="inTypeList"
+                        @confirm="inTypeChange"
+                        @cancel="
+                            in_typeShow = false;
+                            $forceUpdate();
+                        "
+                    />
+                </van-popup>
+                <!-- 费用类型 -->
+                <van-popup v-model="in_exTypeShow" position="bottom" v-if="canEdit">
+                    <van-picker
+                        value-key="typeName"
+                        show-toolbar
+                        :columns="inexTypeList"
+                        @confirm="inexTypeChange"
+                        @cancel="
+                            in_exTypeShow = false;
+                            $forceUpdate();
+                        "
+                    />
+                </van-popup>
+            </span>
+        </van-form>
+        <!-- 提交 -->
+        <div class="form_btn" style="position: fixed; bottom: 0px; width: 100%" v-if="canEdit">
+            <div style="padding-bottom: 10px">
+                <van-button
+                    square
+                    block
+                    type="info"
+                    @click="submitExpense"
+                    style="width: 100%; float: left"
+                    >提交</van-button
+                >
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    data() {
+        return {
+            user: JSON.parse(localStorage.userInfo),
+            canEdit: this.$route.params.canEdit,
+            canExamine: false,
+            minDate: new Date(2020,0,1),
+            maxDate: new Date(2025,11,31),
+            editForm: {
+                ownerId: '',
+                createDate: '',
+                ticketNum: 0,
+                type: 0,
+                remark: ''
+            },
+            invoiceList: [],
+
+            formshowText: {
+                name: '',
+                inProjectName: []
+            },
+            ownerIdShow: false,
+            userList: [],
+            createDateShow: false,
+            typeShow: false,
+            typeList: ['一般','差旅','外包'],
+            totalCost: 0,
+
+            invoiceIndex: 0,
+            in_projectShow: false,
+            inProjectList: [],
+            in_dateShow: false,
+            in_typeShow: false,
+            inTypeList: ['增值税专用发票','增值税普通发票'],
+            in_exTypeShow: false,
+            allexTypeList: [],
+            inexTypeList: [],
+            uploader: [[]],
+        }
+    },
+    filters: {
+        numtosum(value) {
+            if (value == undefined || !value) return '0.00'
+            value = value.toFixed(2)
+            const intPart = Math.trunc(value)
+            const intPartFormat = intPart.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
+            let floatPart = '.00'
+            const valueArray = value.toString().split('.')
+            if (valueArray.length === 2) { // 有小数部分
+            floatPart = valueArray[1].toString() // 取得小数部分
+            return intPartFormat + '.' + floatPart
+            }
+            return intPartFormat + floatPart
+        },
+    },
+    mounted() {
+        console.log(this.$route.params);
+        for(let i in this.user.functionList){
+            if(this.user.functionList[i].name == '费用审核'){
+                this.canExamine = true
+            }
+        }
+        
+        this.getDetail()
+        if(this.canEdit){
+            if(this.canExamine){
+                this.getUserList()
+            }
+            this.getProjectList()
+        }
+    },
+    methods: {
+        back(){
+            history.back();
+        },
+        formatDate(date) {
+            let mon = date.getMonth() + 1
+            return `${date.getFullYear()}-${mon<10?'0'+mon:mon}-${date.getDate()<10?'0'+date.getDate():date.getDate()}`;
+        },
+        costCount(){
+            let costnum = 0
+            for(let i in this.invoiceList){
+                costnum += this.invoiceList[i].amount*1
+            }
+            this.totalCost = costnum
+        },
+
+        ownerIdChange(value,key){
+            this.editForm.ownerId = value.id
+            this.formshowText.name = value.name
+            this.ownerIdShow = false
+        },
+        createDateChange(value,key){
+            this.editForm.createDate = this.formatDate(value)
+            this.createDateShow = false
+        },
+        typeChange(value,key){
+            this.editForm.type = key
+            this.typeShow = false
+            this.inexTypeList = this.allexTypeList.filter(a=>a.mainType == this.editForm.type)
+        },
+        deleteInvoice(index){
+            this.invoiceList.splice(index,1)
+            this.uploader.splice(index,1)
+        },
+        inProjectChange(value,key){
+            this.formshowText.inProjectName[this.invoiceIndex] = value.projectName
+            this.invoiceList[this.invoiceIndex].projectId = value.id
+            this.in_projectShow = false
+        },
+        inDateChange(value,key){
+            this.invoiceList[this.invoiceIndex].happenDate = this.formatDate(value)
+            this.in_dateShow = false
+        },
+        inTypeChange(value,key){
+            this.invoiceList[this.invoiceIndex].invoiceType = key
+            this.in_typeShow = false
+        },
+        inexTypeChange(value,key){
+            this.invoiceList[this.invoiceIndex].expenseType = value.typeName
+            this.in_exTypeShow = false
+        },
+
+        beforeRead(file){
+            if(file.type != 'image/jpeg' && file.type != 'image/png'){
+                this.$toast.fail('请选择jpg或png格式的图片')
+                return false
+            }
+            return true
+        },
+        afterRead(file){
+            let formData = new FormData();
+            formData.append("multipartFile", file.file);
+            this.$axios.post("/common/uploadFile", formData)
+            .then(res => {
+                if(res.code == "ok") {
+                    this.invoiceList[this.invoiceIndex].pic = res.data
+                } else {
+                    this.$toast.fail('上传失败');
+                    this.uploader[this.invoiceIndex] = []
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err);this.uploader[this.invoiceIndex]=[]});
+        },
+
+        submitExpense(){
+            if(!this.editForm.ownerId){
+                this.$toast.fail('请选择报销人')
+                return
+            }
+            if(!this.editForm.createDate){
+                this.$toast.fail('请选择填报日期')
+                return
+            }
+            if(this.invoiceList.length == 0){
+                this.$toast.fail('请添加发票')
+                return
+            }
+            delete this.editForm.invoiceList
+            this.editForm.items = JSON.stringify(this.invoiceList)
+            this.editForm.totalAmount = this.totalCost
+            this.$axios.post("/expense-sheet/add", this.editForm)
+            .then(res => {
+                if(res.code == "ok") {
+                    this.$toast.success('提交成功')
+                    this.back()
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        },
+
+
+        getDetail(){
+            this.$axios.post("/expense-sheet/getDetail", {id: this.$route.params.id})
+            .then(res => {
+                if(res.code == "ok") {
+                    this.editForm = res.data
+                    if(this.canEdit){this.getExTypeList()}
+                    this.formshowText.name = res.data.ownerName
+                    this.totalCost = res.data.totalAmount
+
+                    this.invoiceList = res.data.invoiceList
+                    for(let i in res.data.invoiceList){
+                        this.formshowText.inProjectName.push(res.data.invoiceList[i].projectName)
+                        this.uploader[i] = [{url:'/upload/' + res.data.invoiceList[i].pic}]
+                    }
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        },
+        getUserList(){
+            this.$axios.post("/user/getSimpleActiveUserList", {})
+            .then(res => {
+                if(res.code == "ok") {
+                    this.userList = res.data
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        },
+        getProjectList(){
+            this.$axios.post("/project/getProjectList", {})
+            .then(res => {
+                if(res.code == "ok") {
+                    this.inProjectList = res.data
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        },
+        getExTypeList(){
+            this.$axios.post("/expense-type/getList", {})
+            .then(res => {
+                if(res.code == "ok") {
+                    this.allexTypeList = res.data
+                    this.inexTypeList = this.allexTypeList.filter(a=>a.mainType == this.editForm.type)
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        },
+    },
+};
+</script>
+
+<style lang="less" scoped>
+.edit{
+    margin-top: 46px;
+    overflow: auto;
+    .form_btn{
+        z-index: 1000;
+    }
+    .edit_form{
+        padding-bottom: 46px;
+        .invoice{
+            border: 0.5px solid rgb(135, 195, 255);
+            margin: 0.2rem;
+            .deletebtn{
+                position: absolute;
+                z-index: 1000;
+                font-size: 24px;
+                right: 0.08rem;
+                top: 0.08rem;
+                color: #c03131;
+            }
+            .invoice_item{
+                border-top: 0.5px solid rgb(135, 195, 255);
+            }
+        }
+    }
+}
+</style>
+<style>
+.edit_form .invoice .van-field__label{
+    color: #999;
+}
+.edit_form .invoice .van-field__control{
+    color: #999;
+}
+</style>

+ 674 - 0
fhKeeper/formulahousekeeper/timesheet_h5/src/views/expense/index.vue

@@ -0,0 +1,674 @@
+<template>
+<div>
+    <van-nav-bar title="费用报销" left-text="返回" @click-left="back" fixed left-arrow style="z-index:1000" />
+    <div class="content">
+        <van-tabs v-model="active" @change="activeChange">
+            <van-tab title="费用报销" :name="0"></van-tab>
+            <van-tab title="单据列表" :name="1"></van-tab>
+            <van-tab title="单据审核" :name="2" v-if="canExamine"></van-tab>
+        </van-tabs>
+        <!-- #region 费用报销 -->
+        <div class="edit" v-if="active == 0">
+            <van-form class="edit_form" label-width="140">
+                <!-- 报销人 -->
+                <van-field v-model="editForm.ownerId" label="报销人" @click="ownerIdShow = true" readonly clickable required>
+                    <template #input>{{formshowText.name}}</template>
+                </van-field>
+                <van-popup v-model="ownerIdShow" position="bottom" v-if="canExamine">
+                    <van-picker
+                    value-key="name"
+                    show-toolbar
+                    :columns="userList"
+                    @confirm="ownerIdChange"
+                    @cancel="ownerIdShow = false;$forceUpdate();"/>
+                </van-popup>
+                <!-- 填报日期 -->
+                <van-field v-model="editForm.createDate" label="填报日期" @click="createDateShow = true" readonly clickable required></van-field>
+                <van-popup v-model="createDateShow" position="bottom">
+                    <van-datetime-picker
+                    type="date"
+                    title="选择填报日期"
+                    @confirm="createDateChange"
+                    @cancel="createDateShow = false;$forceUpdate();"
+                    :min-date="minDate"
+                    :max-date="maxDate"/>
+                </van-popup>
+                <!-- 发票张数 -->
+                <van-field label="发票张数">
+                    <template #input>
+                        <van-stepper v-model="editForm.ticketNum"/>
+                    </template>
+                </van-field>
+                <!-- 费用类型 -->
+                <van-field v-model="editForm.type" label="费用类型" @click="typeShow = true" readonly clickable>
+                    <template #input>{{typeList[editForm.type]}}</template>
+                </van-field>
+                <van-popup v-model="typeShow" position="bottom">
+                    <van-picker
+                    show-toolbar
+                    :columns="typeList"
+                    @confirm="typeChange"
+                    @cancel="typeShow = false;$forceUpdate();"/>
+                </van-popup>
+                <!-- 备注 -->
+                <van-field v-model="editForm.remark" label="备注" type="textarea"></van-field>
+                <!-- 发票 -->
+                <van-field label="发票" readonly>
+                    <template #input>总费用:{{totalCost | numtosum}} 元</template>
+                </van-field>
+                <div class="invoice" v-if="invoiceList.length != 0">
+                    <div v-for="item,index in invoiceList" :key="item.id" style="position:relative" :class="index == 0 ? '' : 'invoice_item'">
+                        <!-- <van-button class="deletebtn" size="mini" type="default" @click="deleteInvoice(index)">删除</van-button> -->
+                        <van-icon name="delete-o" class="deletebtn" @click="deleteInvoice(index)" />
+                        <van-field label="所属项目:" v-model="item.projectId" @click="in_projectShow = true,invoiceIndex = index" readonly clickable>
+                            <template #input>{{formshowText.inProjectName[index]}}</template>
+                        </van-field>
+                        <van-field label="费用日期:" v-model="item.happenDate" @click="in_dateShow = true,invoiceIndex = index" readonly clickable></van-field>
+                        <van-field label="发票种类:" v-model="item.invoiceType" @click="in_typeShow = true,invoiceIndex = index" readonly clickable>
+                            <template #input>{{inTypeList[item.invoiceType]}}</template>
+                        </van-field>
+                        <van-field label="费用类型:" v-model="item.expenseType" @click="in_exTypeShow = true,invoiceIndex = index" readonly clickable></van-field>
+                        <van-field label="费用金额(含税):" v-model="item.amount" type="number" @input="costCount"></van-field>
+                        <van-field label="发票号:" v-model="item.invoiceNo"></van-field>
+                        <van-field label="税率%:" v-model="item.taxPercent"></van-field>
+                        <van-field label="税额:" v-model="item.taxValue"></van-field>
+                        <van-field label="备注:" v-model="item.remark" autosize></van-field>
+                        <van-field label="报销凭证:" @click="invoiceIndex = index" clickable>
+                            <template #input>
+                                <van-uploader v-model="uploader[index]" :before-read="beforeRead" :after-read="afterRead" @delete="item.pic = null" :max-count="1" />
+                            </template>
+                        </van-field>
+                    </div>
+                </div>
+                <div class="addinvoice"><van-button size="mini" icon="plus" type="info" plain hairline @click="addInvoice">添加发票</van-button></div>
+                <!-- 发票-popup -->
+                <span>
+                    <!-- 所属项目 -->
+                    <van-popup v-model="in_projectShow" position="bottom">
+                        <van-picker
+                        value-key="projectName"
+                        show-toolbar
+                        :columns="inProjectList"
+                        @confirm="inProjectChange"
+                        @cancel="in_projectShow = false;$forceUpdate();"/>
+                    </van-popup>
+                    <!-- 费用日期 -->
+                    <van-popup v-model="in_dateShow" position="bottom">
+                        <van-datetime-picker
+                        type="date"
+                        title="选择费用日期"
+                        @confirm="inDateChange"
+                        @cancel="in_dateShow = false;$forceUpdate();"
+                        :min-date="minDate"
+                        :max-date="maxDate"/>
+                    </van-popup>
+                    <!-- 发票种类 -->
+                    <van-popup v-model="in_typeShow" position="bottom">
+                        <van-picker
+                        show-toolbar
+                        :columns="inTypeList"
+                        @confirm="inTypeChange"
+                        @cancel="in_typeShow = false;$forceUpdate();"/>
+                    </van-popup>
+                    <!-- 费用类型 -->
+                    <van-popup v-model="in_exTypeShow" position="bottom">
+                        <van-picker
+                        value-key="typeName"
+                        show-toolbar
+                        :columns="inexTypeList"
+                        @confirm="inexTypeChange"
+                        @cancel="in_exTypeShow = false;$forceUpdate();"/>
+                    </van-popup>
+                </span>
+            </van-form>
+            <!-- 提交 -->
+            <div class="form_btn" style="position:fixed; bottom:0px;width:100%;">
+                <div style="padding-bottom:10px;">
+                    <van-button square block type="info" @click="submitExpense" style="width:100%;float:left;">提交</van-button>
+                </div>
+            </div>
+            
+        </div>
+        <!-- #endregion -->
+        <!-- 单据列表 -->
+        <div class="list" v-if="active == 1">
+            <van-collapse v-model="activeName" accordion class="list_collapse">
+                <van-collapse-item v-for="item in billList" :key="item.id" title="标题1" :name="item.id">
+                    <template #title>
+                        <div class="collapse_label_l">票据编号:{{item.code}}</div>
+                        <div class="collapse_label_r">报销人:{{item.ownerName}}</div>
+                        <div class="collapse_label_l">金额: ¥{{item.totalAmount | numtosum}}</div>
+                        <div class="collapse_label_r">状态:<span :class="statusClass[item.status]">{{statusList[item.status]}}</span></div>
+                    </template>
+                    <div class="wrapper">
+                        <div><span>票据编号:</span><span>{{item.code}}</span></div>
+                        <div><span>金额:</span><span>¥{{item.totalAmount | numtosum}}</span></div>
+                        <div><span>报销人:</span><span>{{item.ownerName}}</span></div>
+                        <div><span>填报日期:</span><span>{{item.createDate}}</span></div>
+                        <div><span>发票张数:</span><span>{{item.ticketNum}}</span></div>
+                        <div><span>费用类型:</span><span>{{typeList[item.type]}}</span></div>
+                        <!-- <div><span>状态:</span><span>{{item.status}}</span></div> -->
+                        <div><span>驳回原因:</span><span>{{item.denyReason}}</span></div>
+                        <div><span>备注:</span><span>{{item.remark}}</span></div>
+                    </div>
+                    <div class="operation">
+                        <van-button size="small" type="info" :to="{ name: 'expenseDetails', params: { id: item.id, canEdit: false } }">查看</van-button>
+                        <van-button style="margin-left:10px" size="small" type="info" :to="{ name: 'expenseDetails', params: { id: item.id, canEdit: true } }">编辑</van-button>
+                        <van-button style="margin-left:10px" size="small" type="danger" @click="deleteBill(item.id)">删除</van-button>
+                    </div>
+                </van-collapse-item>
+            </van-collapse>
+        </div>
+        <!-- 单据审核 -->
+        <div class="audit" v-if="active == 2">
+            <van-collapse v-model="auditName" accordion class="list_collapse">
+                <van-collapse-item v-for="item in examineList" :key="item.id" title="标题2" :name="item.id">
+                    <template #title>
+                        <div class="collapse_label_l">票据编号:{{item.code}}</div>
+                        <div class="collapse_label_r">报销人:{{item.ownerName}}</div>
+                        <div class="collapse_label_l">金额: ¥{{item.totalAmount | numtosum}}</div>
+                        <div class="collapse_label_r">状态:<span :class="statusClass[item.status]">{{statusList[item.status]}}</span></div>
+                        <div class="operation">
+                            <van-button size="small" type="info" @click="approve(item.id)">通过</van-button>
+                            <van-button style="margin-left:15px" size="small" type="danger" @click="deny(item.id)">驳回</van-button>
+                        </div>
+                    </template>
+                    <div class="wrapper">
+                        <div><span>票据编号:</span><span>{{item.code}}</span></div>
+                        <div><span>金额:</span><span>¥{{item.totalAmount | numtosum}}</span></div>
+                        <div><span>报销人:</span><span>{{item.ownerName}}</span></div>
+                        <div><span>填报日期:</span><span>{{item.createDate}}</span></div>
+                        <div><span>发票张数:</span><span>{{item.ticketNum}}</span></div>
+                        <div><span>费用类型:</span><span>{{typeList[item.type]}}</span></div>
+                        <!-- <div><span>状态:</span><span>{{item.status}}</span></div> -->
+                        <div><span>驳回原因:</span><span>{{item.denyReason}}</span></div>
+                        <div><span>备注:</span><span>{{item.remark}}</span></div>
+                    </div>
+                    <div class="lookup">
+                        <van-button size="small" type="info" :to="{ name: 'expenseDetails', params: { id: item.id,canEdit: false } }">查看单据信息</van-button>
+                    </div>
+                </van-collapse-item>
+            </van-collapse>
+        </div>
+    </div>
+</div>
+</template>
+
+<script>
+export default {
+    data() {
+        return {
+            active: 0,
+            user: JSON.parse(localStorage.userInfo),
+            userList: [],
+            canExamine: false,
+            minDate: new Date(2020,0,1),
+            maxDate: new Date(2025,11,31),
+
+            formshowText: {
+                name: '',
+                inProjectName: []
+            },
+        // #region 费用报销
+            editForm: {
+                ownerId: '',
+                createDate: '',
+                ticketNum: 0,
+                type: 0,
+                remark: ''
+            },
+            ownerIdShow: false,
+            createDateShow: false,
+            typeShow: false,
+            typeList: ['一般','差旅','外包'],
+
+            invoiceIndex: 0,
+            totalCost: 0,
+            invoiceList: [
+                // {
+                //     projectId: '',
+                //     happenDate: '',
+                //     invoiceType: '',
+                //     expenseType: '',
+                //     amount: '',
+                //     invoiceNo: '',
+                //     taxPercent: '',
+                //     taxValue: '',
+                //     remark: '',
+                //     pic: ''
+                // }
+            ],
+            in_projectShow: false,
+            in_dateShow: false,
+            in_typeShow: false,
+            in_exTypeShow: false,
+
+            inProjectList: [],
+            inTypeList: ['增值税专用发票','增值税普通发票'],
+            allexTypeList: [],
+            inexTypeList: [],
+            uploader: [[]],
+        // #endregion
+
+            // 单据列表
+            activeName: '',
+            billList: [],
+            statusList: ['审核通过','待审核','已驳回','已撤销'],
+            statusClass: ['','waiting','rejected',''],
+
+            // 单据审核
+            auditName: '',
+            examineList: []
+
+        }
+    },
+    filters: {
+        numtosum(value) {
+            if (value == undefined || !value) return '0.00'
+            value = value.toFixed(2)
+            const intPart = Math.trunc(value)
+            const intPartFormat = intPart.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
+            let floatPart = '.00'
+            const valueArray = value.toString().split('.')
+            if (valueArray.length === 2) { // 有小数部分
+            floatPart = valueArray[1].toString() // 取得小数部分
+            return intPartFormat + '.' + floatPart
+            }
+            return intPartFormat + floatPart
+        },
+    },
+    mounted() {
+        for(let i in this.user.functionList){
+            if(this.user.functionList[i].name == '费用审核'){
+                this.canExamine = true
+            }
+        }
+        if(!this.canExamine){
+            this.editForm.ownerId = this.user.id
+            this.formshowText.name = this.user.name
+        }
+        this.getUserList()
+        this.getProjectList()
+        this.getExTypeList()
+    },
+    methods: {
+        back(){
+            history.back();
+        },
+        formatDate(date) {
+            let mon = date.getMonth() + 1
+            return `${date.getFullYear()}-${mon<10?'0'+mon:mon}-${date.getDate()<10?'0'+date.getDate():date.getDate()}`;
+        },
+        activeChange(){
+            if(this.active == 1){
+                this.getBillList()
+            }
+            if(this.active == 2){
+                this.getExamineList()
+            }
+        },
+        costCount(){
+            let costnum = 0
+            for(let i in this.invoiceList){
+                costnum += this.invoiceList[i].amount*1
+            }
+            this.totalCost = costnum
+        },
+
+    // #region 费用报销
+        ownerIdChange(value,key){
+            this.editForm.ownerId = value.id
+            this.formshowText.name = value.name
+            this.ownerIdShow = false
+        },
+        createDateChange(value,key){
+            this.editForm.createDate = this.formatDate(value)
+            this.createDateShow = false
+        },
+        typeChange(value,key){
+            this.editForm.type = key
+            this.typeShow = false
+            this.inexTypeList = this.allexTypeList.filter(a=>a.mainType == this.editForm.type)
+        },
+
+        // 发票
+        inProjectChange(value,key){
+            this.formshowText.inProjectName[this.invoiceIndex] = value.projectName
+            this.invoiceList[this.invoiceIndex].projectId = value.id
+            this.in_projectShow = false
+        },
+        inDateChange(value,key){
+            this.invoiceList[this.invoiceIndex].happenDate = this.formatDate(value)
+            this.in_dateShow = false
+        },
+        inTypeChange(value,key){
+            this.invoiceList[this.invoiceIndex].invoiceType = key
+            this.in_typeShow = false
+        },
+        inexTypeChange(value,key){
+            this.invoiceList[this.invoiceIndex].expenseType = value.typeName
+            this.in_exTypeShow = false
+        },
+
+        addInvoice(){
+            this.invoiceList.push({
+                projectId: '',
+                happenDate: '',
+                invoiceType: '',
+                expenseType: '',
+                amount: '',
+                invoiceNo: '',
+                taxPercent: '',
+                taxValue: '',
+                remark: '',
+                pic: '',
+            })
+            this.uploader.push([])
+        },
+        deleteInvoice(index){
+            this.invoiceList.splice(index,1)
+            this.uploader.splice(index,1)
+        },
+
+        // 上传报销凭证
+        beforeRead(file){
+            if(file.type != 'image/jpeg' && file.type != 'image/png'){
+                this.$toast.fail('请选择jpg或png格式的图片')
+                return false
+            }
+            return true
+        },
+        afterRead(file){
+            console.log('afterRead',file);
+            let formData = new FormData();
+            formData.append("multipartFile", file.file);
+            this.$axios.post("/common/uploadFile", formData)
+            .then(res => {
+                if(res.code == "ok") {
+                    this.invoiceList[this.invoiceIndex].pic = res.data
+                } else {
+                    this.$toast.fail('上传失败');
+                    this.uploader[this.invoiceIndex] = []
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err);this.uploader[this.invoiceIndex]=[]});
+        },
+
+        // 提交
+        submitExpense(){
+            if(!this.editForm.ownerId){
+                this.$toast.fail('请选择报销人')
+                return
+            }
+            if(!this.editForm.createDate){
+                this.$toast.fail('请选择填报日期')
+                return
+            }
+            if(this.invoiceList.length == 0){
+                this.$toast.fail('请添加发票')
+                return
+            }
+            this.editForm.items = JSON.stringify(this.invoiceList)
+            this.editForm.totalAmount = this.totalCost
+            this.$axios.post("/expense-sheet/add", this.editForm)
+            .then(res => {
+                if(res.code == "ok") {
+                    this.$toast.success('填报成功')
+                    this.editForm = {
+                        ownerId: '',
+                        createDate: '',
+                        ticketNum: 0,
+                        type: 0,
+                        remark: ''
+                    }
+                    this.invoiceList = []
+                    this.uploader = []
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        },
+    // #endregion
+
+        // 单据列表
+        deleteBill(pid){
+            this.$axios.post("/expense-sheet/delete", {id: pid})
+            .then(res => {
+                if(res.code == "ok") {
+                    this.$toast.success('删除成功')
+                    this.getBillList()
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        },
+
+        // 单据审核
+        approve(pid){
+            this.$axios.post("/expense-sheet/approve", {id: pid})
+            .then(res => {
+                if(res.code == "ok") {
+                    this.$toast.success('已通过')
+                    this.getExamineList()
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        },
+        deny(pid){
+            this.$axios.post("/expense-sheet/deny", {id: pid,denyReason:''})
+            .then(res => {
+                if(res.code == "ok") {
+                    this.$toast.success('已驳回')
+                    this.getExamineList()
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        },
+
+        getUserList(){
+            this.$axios.post("/user/getSimpleActiveUserList", {})
+            .then(res => {
+                if(res.code == "ok") {
+                    this.userList = res.data
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        },
+        getProjectList(){
+            this.$axios.post("/project/getProjectList", {})
+            .then(res => {
+                if(res.code == "ok") {
+                    this.inProjectList = res.data
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        },
+        getExTypeList(){
+            this.$axios.post("/expense-type/getList", {})
+            .then(res => {
+                if(res.code == "ok") {
+                    this.allexTypeList = res.data
+                    this.inexTypeList = this.allexTypeList.filter(a=>a.mainType == 0)
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        },
+
+        getBillList(){
+            this.$axios.post("/expense-sheet/list", {
+                pageSize: 20,
+                pageIndex: 1,
+                startDate: '',
+                endDate: '',
+                ownerId: '',
+                type: ''
+            }).then(res => {
+                if(res.code == "ok") {
+                    this.billList = res.data.records
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        },
+
+        getExamineList(){
+            this.$axios.post("/expense-sheet/list", {
+                pageSize: 20,
+                pageIndex: 1,
+                startDate: '',
+                endDate: '',
+                ownerId: '',
+                type: '',
+                status: 1
+            }).then(res => {
+                if(res.code == "ok") {
+                    this.examineList = res.data.records
+                } else {
+                    this.$toast.fail('获取失败');
+                }
+            }).catch(err=> {this.$toast.clear();console.log(err)});
+        }
+    },
+}
+</script>
+
+<style lang="less" scoped>
+.content{
+    margin-top: 46px;
+    overflow: auto;
+    .edit{
+        padding-bottom: 46px;
+        .form_btn{
+            z-index: 1000;
+        }
+        .edit_form{
+            .invoice{
+                border: 0.5px solid rgb(135, 195, 255);
+                margin: 0.2rem;
+                .deletebtn{
+                    position: absolute;
+                    z-index: 900;
+                    font-size: 24px;
+                    right: 0.08rem;
+                    top: 0.08rem;
+                    color: #c03131;
+                }
+                .invoice_item{
+                    border-top: 0.5px solid rgb(135, 195, 255);
+                }
+            }
+            .addinvoice{
+                padding: 0 0.3rem 0.3rem;
+                margin-top: 0.2rem;
+                text-align: right;
+            }
+        }
+    }
+    .list{
+        .list_collapse>div{
+            margin: 4px;
+        }
+        .list_collapse{
+            .collapse_label_l{
+                width: 60%;
+                padding: 4px;
+                display: inline-block;
+            }
+            .collapse_label_r{
+                width: 40%;
+                padding: 4px;
+                display: inline-block;
+                .waiting {
+                    color:orange;
+                }
+                .rejected {
+                    color:red;
+                }
+            }
+            .wrapper{
+                div{
+                    margin: 8px 16px;
+                }
+                div span:nth-child(1){
+                    width: 30%;
+                    display: inline-block;
+                }
+                div span:nth-child(2){
+                    width: 70%;
+                    display: inline-block;
+                }
+            }
+            .operation{
+                display: flex;
+                align-items: center;
+                justify-content: flex-end;
+            }
+        }
+        
+    }
+    .audit{
+        .list_collapse>div{
+            margin: 4px;
+        }
+        .list_collapse{
+            
+            .collapse_label_l{
+                width: 60%;
+                padding: 4px;
+                display: inline-block;
+            }
+            .collapse_label_r{
+                width: 40%;
+                padding: 4px;
+                display: inline-block;
+                .waiting {
+                    color:orange;
+                }
+                .rejected {
+                    color:red;
+                }
+            }
+            .operation{
+                margin-top: 5px;
+                padding-top: 5px;
+                border-top: 0.5px solid #ebedf0;
+                display: flex;
+                align-items: center;
+                justify-content: flex-end;
+            }
+            .wrapper{
+                div{
+                    margin: 8px 16px;
+                }
+                div span:nth-child(1){
+                    width: 30%;
+                    display: inline-block;
+                }
+                div span:nth-child(2){
+                    width: 70%;
+                    display: inline-block;
+                }
+            }
+            .lookup{
+                display: flex;
+                align-items: center;
+                justify-content: flex-end;
+            }
+            
+        }
+        
+    }
+}
+</style>
+<style>
+.edit_form .invoice .van-field__label{
+    color: #999;
+}
+.edit_form .invoice .van-field__control{
+    color: #999;
+}
+</style>

+ 7 - 0
fhKeeper/formulahousekeeper/timesheet_h5/src/views/index/index.vue

@@ -93,6 +93,13 @@
                 if(list[i].name == '导入日报审核') {
                     this.routers.push({name: '导入日报审核',url: '/audit',icon: 'label-o'})
                 }
+                if(list[i].name == '费用报销') {
+                    this.routers.push({
+                        name: '费用报销',
+                        url: '/expense',
+                        icon: 'balance-list-o'
+                    });
+                }
             }
             if (this.user.manageDeptId != 0 && this.user.company.packageEngineering == 1) {
                 this.routers.push(

+ 5 - 2
fhKeeper/formulahousekeeper/timesheet_h5/src/views/project/index.vue

@@ -163,8 +163,11 @@
         },
         methods: {
             toProjectInside(item){
-                sessionStorage.setItem('projectId',JSON.stringify(item.id))
-                this.$router.push("/projectInside");
+                if(this.user.company.packageProject == 1){
+                    sessionStorage.setItem('projectId',JSON.stringify(item.id))
+                    this.$router.push("/projectInside");
+                }
+                
             },
             popoverSelect(action){
                 if(this.popoverType == action.type){

+ 8 - 6
fhKeeper/formulahousekeeper/timesheet_h5/src/views/task/editask.vue

@@ -24,8 +24,8 @@
                     title="选择开始时间"
                     @confirm="startDateChange"
                     @cancel="startDateShow = false;$forceUpdate();"
-                    :min-date="new Date(2010,0,1)"
-                    :max-date="taskform.endDate ? new Date(taskform.endDate) : new Date(2030,11,31)"/>
+                    :min-date="minDate"
+                    :max-date="taskform.endDate ? new Date(taskform.endDate) : maxDate"/>
                 </van-popup>
                 <!-- 截止时间 -->
                 <van-field v-model="taskform.endDate" label="截止时间" placeholder="请选择截止时间" @click="endDateShow = true" readonly clickable></van-field>
@@ -35,8 +35,8 @@
                     title="选择截止时间"
                     @confirm="endDateChange"
                     @cancel="endDateShow = false;$forceUpdate();"
-                    :min-date="taskform.startDate ? new Date(taskform.startDate) : new Date(2010,0,1)"
-                    :max-date="new Date(2030,11,31)"/>
+                    :min-date="taskform.startDate ? new Date(taskform.startDate) : minDate"
+                    :max-date="maxDate"/>
                 </van-popup>
                 <!-- 完成时间 -->
                 <van-field v-if="taskform.type == 1" v-model="taskform.finishDate" label="完成时间" placeholder="请选择完成时间" @click="finishDateShow = true" readonly clickable></van-field>
@@ -46,8 +46,8 @@
                     title="选择完成时间"
                     @confirm="finishDateChange"
                     @cancel="finishDateShow = false;$forceUpdate();"
-                    :min-date="new Date(2010,0,1)"
-                    :max-date="new Date(2030,11,31)"/>
+                    :min-date="minDate"
+                    :max-date="maxDate"/>
                 </van-popup>
                 <!-- 执行人 -->
                 <div style="border: 0.5px solid #87c3ff;margin:0.2rem;position:relative" v-for="item,index in taskform.executorList" :key="index">
@@ -114,6 +114,8 @@ export default {
             title: '编辑任务',
             user: JSON.parse(localStorage.userInfo),
             taskId: JSON.parse(sessionStorage.taskId),
+            minDate: new Date(2020,0,1),
+            maxDate: new Date(2025,11,31),
             canEdit: true,
             taskform:{      // 表单
                 taskType: 0,