Files
17168ERP/web/admin/accounting/news_reg.aspx
2025-08-29 01:27:25 +08:00

707 lines
38 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<%@ Page Title="後端管理" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="news_reg.aspx.cs" Inherits="admin_accounting_new_reg" ValidateRequest="false" %>
<%@ Register Src="~/admin/_uc/alert.ascx" TagPrefix="uc1" TagName="alert" %>
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" runat="Server">
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="footer_script" runat="Server">
<script>
let VueApp = new Vue({
el: '#app',
vuetify: new Vuetify(vuetify_options),
data() {
return {
this_id: '<%= Request["num"] %>',
options: {},
optionsDetail: { multiSort: false },
search_dialog: {
controls: {
search1: {
id: 'search1',
title: '收支項目',
text_prop: 'kind',
value_prop: 'num',
keys: [
{ id: 'kind', title: '項目名稱', value: '' },
],
api_url: HTTP_HOST + 'api/accounting/GetTitleKindList',
columns: [
{ id: 'kind', title: '項目名稱', value: '' },
],
selected: {},
select(t) {
console.log("select search1", t);
}
}, search2: {
id: 'search2',
title: '收支帳戶',
text_prop: 'kind',
value_prop: 'num',
keys: [
{ id: 'kind', title: '帳戶名稱', value: '' },
],
api_url: HTTP_HOST + 'api/accounting/GetAccountKindList',
columns: [
{ id: 'kind', title: '帳戶名稱', value: ''},
],
selected: {},
select(t) {
console.log("select search2", t);
}
},
search3: {
id: 'search3',
title: '相關活動',
text_prop: 'subject',
value_prop: 'num',
keys: [
{ id: 'subject', title: '活動名稱', value: '' },
{ id: 'kindTxt', title: '活動分類' },
],
api_url: HTTP_HOST + 'api/activity/GetList',
columns: [
{ id: 'subject', title: '活動名稱' },
{ id: 'kindTxt', title: '活動分類' },
],
selected: {},
select(t) {
console.log("select search3", t);
}
},
search4: {
id: 'search4',
title: '人員',
text_prop: 'u_name',
value_prop: 'num',
keys: [
{ id: 'm_number', title: '編號', value: '' },
{ id: 'u_name', title: '姓名', value: '' },
{ id: 'sex', title: '性別', value: '' },
],
api_url: HTTP_HOST + 'api/member/GetList',
columns: [
{ id: 'm_number', title: '編號' },
{ id: 'u_name', title: '姓名' },
{ id: 'sex', title: '性別' },
],
selected: {},
select(t) {
console.log("select search4", t);
}
},
},
show: false,
current: {},
list: [],
count: 0,
page:1,
loading: false,
footer: {
showFirstLastPage: true,
disableItemsPerPage: true,
itemsPerPageAllText: '',
itemsPerPageText:'',
},
},
snackbar: {
show: false,
text: "",
},
total: '<%= _t %>',
//檔案上傳
filePath: '<%= ResolveUrl( Model.accounting.Dir) %>/',
filerules: [
value => !value || value.size < 2000000 || '檔案限制 2 MB 以內',
value => !!value || '檔案必填',
],
searchDetail: '',
headersDetail: [
{ text: '檔案名稱', value: 'pic1', sortable: false },
{ text: '', value: 'actions', sortable: false, width: "200px" },
],
desserts: [],
desserts_count: 0,
editedIndex: -1,
editedItem: {
id: 0,
num: 0,
accounting_num: 0,
pic1: '',
pic1_name: '',
pic1push: [],
},
defaultItem: {
id: 0,
num: 0,
accounting_num: 0,
pic1: '',
pic1_name: '',
pic1push: [],
},
}
},
mounted() {
this.search_dialog.current = this.search_dialog.controls.search1
//console.log("mounted");
},
watch: {
options: {
handler() {
this.search_get()
console.log("watch2", this.search_dialog, this.search_dialog.page);
},
deep: true,
},
optionsDetail: {
handler() {
this.initialize();
},
deep: true,
},
},
methods: {
search_show(curr) {
//console.log("btn_click:", curr, curr.api_url);
this.search_dialog.current = curr;
this.search_clear()
//this.search_get()//清除完自動會重抓, 故取消
this.search_dialog.show = true;
},
search_clear() {
if (!this.search_dialog.current.keys) return;
this.search_dialog.current.keys.forEach((t, i) => { t.value = '' })
this.search_get()
},
search_get() {
if (!this.search_dialog.current.keys) return;
let api_url = this.search_dialog.current.api_url;
let keys = this.search_dialog.current.keys;
//const { page, itemsPerPage } = this.options
//const { sortBy, sortDesc, page, itemsPerPage } = this.options
this.search_dialog.page = this.options.page??1
let params = { page: this.search_dialog.page, pageSize: 10 };//url params
var search = {};//post body
keys.forEach((t, i) => {
search[t.id] = t.value;
});
console.log("search_get", api_url, search, params, this.options);
this.search_dialog.loading = true
axios.post(api_url, search, { params: params })
.then(response => {
this.search_dialog.list = response.data.list
this.search_dialog.count = response.data.count
this.search_dialog.loading = false
})
.catch(error => {
console.log(error)
this.search_dialog.list = []
this.search_dialog.count = 0
this.search_dialog.loading = false
this.snackbar.text = "錯誤:" + error
this.snackbar.show=true
})
},
search_headers() {
if (!this.search_dialog.current.columns) return;
r = [];
this.search_dialog.current.columns.forEach((t, i) => {
r.push({
text: t.title,
align: 'start',
sortable: false,
value: t.id,
})
})
return r
},
search_select(row) {
let curr = this.search_dialog.current;
let target = $(`[data-search-control=${curr.id}]`);
curr.selected = row;
target.children("input.search-text").val(curr.selected[curr.text_prop])//text
target.children("input:hidden").val(curr.selected[curr.value_prop])//value
if (curr.select instanceof Function) {
curr.select(row);
}
this.search_dialog.show = false;
},
initialize() {
if (this.this_id != '') {
const { sortBy, sortDesc, page, itemsPerPage } = this.optionsDetail
const params = {
sortBy: sortBy[0], sortDesc: sortDesc[0],
page: page, pageSize: itemsPerPage,
};
var searchItemDetail = {
accounting_num: this.this_id,
}
axios
.post(HTTP_HOST + 'api/accounting/GetAccFiles', searchItemDetail, { params: params })
.then(response => {
this.desserts = response.data.list
this.desserts_count = response.data.count
})
.catch(
error => console.log(error)
)
}
},
cancel() {
this.spliceNullData();
this.close();
},
spliceNullData() {
//if new data ,then splice it
if (this.editedItem.num == 0) {
for (var i = 0; i < this.desserts.map(x => x.id).length; i++) {
if (this.desserts[i].id == this.editedItem.id) {
this.desserts.splice(i, 1); break;
}
}
}
},
close() {
setTimeout(() => {
this.editedItem = $.extend(true, {}, this.defaultItem);
this.editedIndex = -1;
}, 300)
},
addNew() {
this.spliceNullData();
//addObj.id = this.desserts.length + 1;
var keysArr = [];
for (var i = 0; i < this.desserts.map(x => x.id).length; i++) {
//console.log(this.desserts[i].id)
keysArr.push(parseInt(this.desserts[i].id));
}
var _c = Math.max.apply(null, keysArr);
const addObj = $.extend(true, {}, this.defaultItem);
addObj.id = (isFinite(_c) ? _c : 0) + 1;
this.desserts.unshift(addObj);
this.editItem(addObj);
},
editItem(item) {
this.editedIndex = this.desserts.indexOf(item);
this.editedItem = $.extend(true, {}, item);
}, save() {
if (this.editedIndex > -1) {
if (this.this_id != '') {
if (this.editedItem.pic1push != null) {
var reader = new FileReader();
reader.onload = function (e) {
if (e.total <= 2000000) {
//上傳檔案
const formData = new FormData();
formData.append('file-to-upload', VueApp.editedItem.pic1push)
axios
.post(HTTP_HOST + 'api/accounting/uploadFiles', formData, {
Headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => {
if (response.data != "") {
//寫入
var accounting_files = {
accounting_num: VueApp.this_id,
pic1: response.data,
pic1_name: VueApp.editedItem.pic1push.name,
}
axios
.post(HTTP_HOST + 'api/accounting/SaveFileData', accounting_files)
.then(response => {
VueApp.editedItem.num = response.data;
VueApp.editedItem.pic1 = accounting_files.pic1;
VueApp.editedItem.pic1_name = accounting_files.pic1_name;
Object.assign(VueApp.desserts[VueApp.editedIndex], VueApp.editedItem)
VueApp.close()
})
.catch(
error => console.log(error)
)
}
})
.catch(
error => {
console.log(error)
VueApp.snackbar.text = "錯誤:" + error.response.data.message
VueApp.snackbar.show = true
}
)
} else {
VueApp.snackbar.text = "檔案限制 2 MB 以內";
VueApp.snackbar.show = true
}
}
reader.readAsDataURL(this.editedItem.pic1push);
}
else {
this.snackbar.text = "請選擇檔案";
this.snackbar.show = true
}
} else {
this.snackbar.text = "庫存資料錯誤";
this.snackbar.show = true
}
}
},
deleteItem(item) {
if (confirm('確定要刪除此筆資料嗎?')) {
const index = this.desserts.indexOf(item);
if (item.num > 0) {
if (index != -1) {
axios
.delete(HTTP_HOST + 'api/accounting/DeleteFilesItem/' + item.num)
.then(response => {
console.log("del", item);
this.desserts.splice(index, 1)
this.desserts_count = this.desserts_count - 1;
})
.catch(error => console.log(error))
}
} else {
this.desserts.splice(index, 1)
}
}
},
isPhoto(name) {
const n = name.split('.')[1];
const type = new Array("jpg", "jpeg", "gif", "png", "bmp");
return type.indexOf(n) > -1 ? true : false
},
},
computed: {
}, filters: {
currency: function (value) {
return value == null || value === "" ? "" :
('$' + parseFloat(value).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,").replace(".00", ""));
},
}
})
$('#<%= price.ClientID %>').on("change", function () {
getTotalPrice();
})
$('#<%= tax.ClientID %>').on("change", function () {
getTotalPrice();
})
function getTotalPrice() {
const _pp = ($('#<%= price.ClientID %>').val() != null && $('#<%= price.ClientID %>').val() != "") ? parseFloat($('#<%= price.ClientID %>').val()) :0 ;
const _tt = ($('#<%= tax.ClientID %>').val() != null && $('#<%= tax.ClientID %>').val() != "") ? parseFloat($('#<%= tax.ClientID %>').val()) : 0;
let _tp = _pp + _tt;
_tp = ('$' + parseFloat(_tp).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,").replace(".00", ""));
$('#totalPrice').text(_tp);
}
</script>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="page_nav" runat="Server">
<div class="scroll-nav nav nav-tabs mb-2 mb-sm-0 d-none d-sm-flex">
</div>
<div class="">
<asp:Button ID="add" runat="server" Text="送出" OnClick="add_Click" CssClass="btn btn-primary" />
<asp:Button ID="edit" runat="server" Text="修改備註" Visible="false" OnClick="edit_Click" CssClass="btn btn-primary" />
<asp:Button ID="goback" runat="server" Text="回列表" Visible="false" CausesValidation="false" OnClick="goback_Click" CssClass="btn btn-outline-secondary" />
</div>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<uc1:alert runat="server" ID="L_msg" Text="" />
<div id="content" class="container-md">
<div class="card shadow-sm my-3">
<div class="card-header py-0">
<nav class="navbar py-0">
<div class="nav nav-tabs">
<button class="nav-link active" id="sec2-tab1" data-bs-toggle="tab" data-bs-target="#sec2-page1"
type="button" role="tab" aria-controls="home" aria-selected="true">
收支管理</button>
<button class="nav-link" id="sec2-tab2" data-bs-toggle="tab" data-bs-target="#sec2-page2"
type="button" role="tab" aria-controls="profile" aria-selected="false">
檔案上傳</button>
</div>
</nav>
</div>
<asp:Panel ID="cardBodyPanel" runat="server" CssClass="card-body">
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active " id="sec2-page1" role="tabpanel" aria-labelledby="sec2-tab1">
<div>
<div class="form-text text-muted">以下 * 欄位為必填欄位</div>
</div>
<div class="row mb-1 label-sm-right " :class="{readonly : this_id !='' }">
<label class="col-sm-2 col-lg-1 col-form-label">單據日期 *</label>
<div class="col-sm-10 col-lg-3">
<asp:TextBox ID="uptime" runat="server" CssClass="form-control " TextMode="Date" autocomplete="off" data-date-format="yyyy-mm-dd"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator6" ControlToValidate="uptime" runat="server" ErrorMessage="必填!" Display="Dynamic" SetFocusOnError="true"></asp:RequiredFieldValidator>
</div>
<label class="col-sm-2 col-lg-1 col-form-label">收支類別 *</label>
<div class="col-sm-10 col-lg-3">
<asp:DropDownList ID="category" CssClass="form-select" runat="server" data-int="Y">
<asp:ListItem Value="" Text="請選擇"></asp:ListItem>
</asp:DropDownList>
<asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server" ControlToValidate="category"
ErrorMessage="必填!" Display="Dynamic" SetFocusOnError="true"></asp:RequiredFieldValidator>
</div>
<label class="col-sm-2 col-lg-1 col-form-label">收支帳戶 *</label>
<div class="col-sm-10 col-lg-3">
<div class="input-group mb-3" data-search-control="search2" @click="search_show(search_dialog.controls.search2)">
<input class="form-control search-text" type="text" readonly
id="kind2_txt" runat="server" placeholder="收支帳戶" value="">
<asp:HiddenField ID="kind2" runat="server" Value="" />
<button class="btn btn-outline-secondary" type="button">
<i class="mdi mdi-view-list-outline"></i>
</button>
</div>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" ControlToValidate="kind2_txt" runat="server" ErrorMessage="必填!" Display="Dynamic" SetFocusOnError="true"></asp:RequiredFieldValidator>
</div>
</div>
<div class="row mb-1 label-sm-right " :class="{readonly : this_id !='' }">
<label class="col-sm-2 col-lg-1 col-form-label">收支項目 *</label>
<div class="col-sm-10 col-lg-3">
<div class="input-group mb-3" data-search-control="search1" @click="search_show(search_dialog.controls.search1)">
<input class="form-control search-text" type="text" readonly
id="kind_txt" runat="server" placeholder="收支項目" value="">
<asp:HiddenField ID="kind" runat="server" Value="" />
<button class="btn btn-outline-secondary" type="button">
<i class="mdi mdi-view-list-outline"></i>
</button>
</div>
<asp:RequiredFieldValidator ID="RequiredFieldValidator7" ControlToValidate="kind_txt" runat="server" ErrorMessage="必填!" Display="Dynamic" SetFocusOnError="true"></asp:RequiredFieldValidator>
</div>
<label class="col-sm-2 col-lg-1 col-form-label">相關活動</label>
<div class="col-sm-10 col-lg-3">
<div class="input-group mb-3" data-search-control="search3" @click="search_show(search_dialog.controls.search3)">
<input class="form-control search-text" type="text" readonly
id="activity_num_txt" runat="server" placeholder="相關活動" value="">
<asp:HiddenField ID="activity_num" runat="server" Value="" />
<button class="btn btn-outline-secondary" type="button">
<i class="mdi mdi-view-list-outline"></i>
</button>
</div>
</div>
</div>
<div class="row mb-1 label-sm-right " :class="{readonly : this_id !='' }">
<label class="col-sm-2 col-lg-1 col-form-label">未稅金額 *</label>
<div class="col-sm-10 col-lg-3">
<asp:TextBox ID="price" MaxLength="7" runat="server" CssClass="form-control" placeholder="請輸入未稅金額"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator4" ControlToValidate="price" runat="server" ErrorMessage="必填!" Display="Dynamic" SetFocusOnError="true"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ControlToValidate="price" Display="Dynamic" SetFocusOnError="true" ErrorMessage="只能輸入數字" ValidationGroup="Required" ID="RegularExpressionValidator3" runat="server" ValidationExpression="^(\d+)?$" />
</div>
<label class="col-sm-2 col-lg-1 col-form-label">稅額 *</label>
<div class="col-sm-10 col-lg-3">
<asp:TextBox ID="tax" MaxLength="7" runat="server" CssClass="form-control" placeholder="請輸入稅額"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator8" ControlToValidate="tax" runat="server" ErrorMessage="必填!" Display="Dynamic" SetFocusOnError="true"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ControlToValidate="tax" Display="Dynamic" SetFocusOnError="true" ErrorMessage="只能輸入數字" ValidationGroup="Required" ID="RegularExpressionValidator1" runat="server" ValidationExpression="^(\d+)?$" />
</div>
<label class="col-sm-2 col-lg-1 col-form-label">總額</label>
<div class="col-sm-10 col-lg-3 pt-2">
<span id="totalPrice">{{total | currency}}</span>
</div>
</div>
<div class="row mb-1 label-sm-right " :class="{readonly : this_id !='' }">
<label class="col-sm-2 col-lg-1 col-form-label">內部負責人 *</label>
<div class="col-sm-10 col-lg-3">
<div class="input-group mb-3" data-search-control="search4" @click="search_show(search_dialog.controls.search4)">
<input class="form-control search-text" type="text" readonly
id="mem_num_txt" runat="server" placeholder="人員" value="" >
<asp:HiddenField ID="mem_num" runat="server" Value="" />
<button class="btn btn-outline-secondary" type="button" >
<i class="mdi mdi-view-list-outline"></i>
</button>
</div>
<asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ControlToValidate="mem_num_txt"
ErrorMessage="必填!" Display="Dynamic" SetFocusOnError="true"></asp:RequiredFieldValidator>
</div>
<label class="col-sm-2 col-lg-1 col-form-label">外部負責人</label>
<div class="col-sm-10 col-lg-3">
<asp:TextBox ID="debtor" MaxLength="20" runat="server" CssClass="form-control" placeholder="請輸入外部負責人"></asp:TextBox>
</div>
</div>
<hr />
<div class="row mb-1">
<label class="col-form-label">摘要</label>
<div class="">
<asp:TextBox ID="excerpt" runat="server" Rows="5" TextMode="MultiLine" CssClass="form-control" placeholder="請輸入摘要(可入傳票)"></asp:TextBox>
</div>
</div>
<hr />
<div class="row mb-1">
<label class="col-form-label">備註</label>
<div class="">
<asp:TextBox ID="demo" runat="server" Rows="5" TextMode="MultiLine" CssClass="form-control" placeholder="請輸入備註"></asp:TextBox>
</div>
</div>
<div class="row mb-1">
<asp:Panel ID="timePanel1" runat="server" CssClass="col-12 text-right text-primary" Visible="false">建檔時間:<asp:Literal ID="reg_time" runat="server"></asp:Literal></asp:Panel>
</div>
</div>
<div class="tab-pane fade giftItems label-sm-right" id="sec2-page2" role="tabpanel" aria-labelledby="sec2-tab2">
<v-card class="mx-auto mt-10" outlined v-if="this_id!=''">
<v-data-table
hide-default-header
:headers="headersDetail"
:items="desserts"
<%-- :search="searchDetail"--%>
:options.sync="optionsDetail" class="elevation-1" fixed-header height="550px"
<%-- :server-items-length="desserts_count"--%>
>
<v-divider inset></v-divider>
<template v-slot:top>
<v-toolbar flat color="white">
<div class="d-flex w-100">
<%--<v-text-field v-model="searchDetail" append-icon="mdi-magnify" label="查詢" dense outlined single-line hide-details></v-text-field>--%>
<v-btn
color="primary"
class="ml-2 white--text"
@click="addNew">
<v-icon dark>mdi-plus</v-icon>新增
</v-btn>
</div>
</v-toolbar>
<div class="form-text text-muted ml-5">檔案限制 2 MB 以內僅接受jpg、png、pdf格式</div>
</template>
<template v-slot:item.pic1="{ item }" :cols="12" >
<div class="input-group mb-3" v-if="item.id === editedItem.id">
<v-file-input v-model="editedItem.pic1push"
required :rules="filerules" accept="image/png, image/jpeg, application/pdf"
show-size label="請選擇檔案"
truncate-length="25">
</v-file-input>
</div>
<template v-else>
<template v-if="isPhoto(item.pic1)">
<a :href="filePath+item.pic1" target="_blank" >
<v-img
max-height="138"
max-width="250"
:lazy-src="filePath+item.pic1"
:src="filePath+item.pic1"
:alt="item.pic1_name"
></v-img>
</a>
</template>
<template v-else>
<v-btn
outlined color="primary" class="ma-2" elevation="3" download
:href="filePath+item.pic1"
>
{{item.pic1_name}}
<v-icon right dark >mdi-cloud-download</v-icon>
</v-btn>
</template>
</template>
</template>
<template v-slot:item.actions="{ item }">
<div v-if="item.id === editedItem.id">
<v-icon color="red" class="mr-3" @click="cancel">
mdi-window-close
</v-icon>
<v-icon color="green" @click="save">
mdi-content-save
</v-icon>
</div>
<div v-else>
<v-icon color="red" @click="deleteItem(item)">
mdi-delete
</v-icon>
</div>
</template>
</v-data-table>
</v-card>
<div class="mx-auto" v-else >
<p class="lead">請先儲存收支管理後再新增檔案上傳</p>
</div>
</div>
</div>
</asp:Panel>
</div>
<v-dialog v-model="search_dialog.show" max-width="500px">
<v-card>
<v-card-title class="justify-space-between grey lighten-2">
查詢:{{search_dialog.current.title}}
<v-btn icon @click="search_dialog.show=false"><v-icon>mdi-close</v-icon></v-btn>
</v-card-title>
<v-card-text >
<v-row>
<v-col v-for="item in search_dialog.current.keys"
:cols="search_dialog.current.keys.length>1?6:12" >
<v-text-field v-model="item.value" :label="item.title"></v-text-field>
</v-col>
<v-col cols="12" class="text-end">
<v-btn color="primary" elevation="0" @click="search_get()">查詢</v-btn>
<v-btn elevation="0" @click="search_clear()">清除條件</v-btn>
</v-col>
</v-row>
<v-data-table
:headers="search_headers()"
:items="search_dialog.list"
:footer-props="search_dialog.footer"
:items-per-page="10"
:server-items-length="search_dialog.count"
:page.sync="search_dialog.page"
:options.sync="options"
@click:row="search_select"
></v-data-table>
</v-card-text>
<v-card-actions>
</v-card-actions>
</v-card>
</v-dialog>
<v-snackbar
v-model="snackbar.show"
timeout="2000"
>
{{ snackbar.text }}
<template v-slot:action="{ attrs }">
<v-btn
text
v-bind="attrs"
@click="snackbar.show = false"
>
關閉
</v-btn>
</template>
</v-snackbar>
</div>
</asp:Content>