上传文件至 src/views

This commit is contained in:
2025-05-09 13:29:07 +09:00
parent 7ee521cc65
commit 4bf8637494
4 changed files with 758 additions and 0 deletions

185
src/views/ApprovalList.vue Normal file
View File

@ -0,0 +1,185 @@
<template>
<div class="page-container">
<UserMenu />
<form @submit.prevent="search" class="search-form">
<label>From:</label>
<input type="date" v-model="form.startDate" required />
<label>To:</label>
<input type="date" v-model="form.endDate" required />
<button type="submit">検索</button>
</form>
<table v-if="form.sizaiList?.length > 0" class="outputtable">
<thead>
<tr>
<th>資材ID</th>
<th>資材名</th>
<th>数量</th>
<th>カテゴリー</th>
<th>購入依頼者</th>
<th>購入依頼部門</th>
<th>状態</th>
<th>依頼日</th>
<th>承認</th>
<th>却下</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in form.sizaiList" :key="index">
<td>{{ item.id }}</td>
<td>
<ApprovalDetail :targetId="item.id">{{ item.name }}</ApprovalDetail>
</td>
<td>{{ item.num }}</td>
<td>{{ item.category_name }}</td>
<td>{{ item.request_user_name }}</td>
<td>{{ item.request_dept_name }}</td>
<td>{{ item.status_name }}</td>
<td>{{ item.request_date }}</td>
<td>
<template v-if="item.status == 1 || item.status == 3">
<a href="#" @click.prevent="approval(item.id)">承認</a>
</template>
</td>
<td>
<template v-if="item.status == 1">
<a href="#" @click.prevent="reject(item.id)">却下</a>
</template>
</td>
</tr>
</tbody>
</table>
<div v-else style="text-align: center; margin-top: 20px">
データがありません
</div>
</div>
</template>
<script setup>
import { reactive, onMounted } from "vue";
import axios from "axios";
import { ElMessage } from "element-plus";
import UserMenu from "../components/UserMenu.vue";
import ApprovalDetail from "../components/ApprovalDetail.vue";
import { useRouter } from "vue-router";
const router = useRouter();
const form = reactive({
startDate: "",
endDate: "",
sizaiList: [],
targetId: null,
message: "",
messageflag: true,
});
const fetchList = () => {
axios
.get("/api/approvalList/init")
.then((res) => {
const response = res.data;
if (!response.success) {
ElMessage.error(response.message || "初期化失敗しました");
return;
}
Object.assign(form, response.data);
if (!form.sizaiList) form.sizaiList = [];
})
.catch((err) => {
if ([401, 403].includes(err.response?.status)) {
ElMessage.error("ログイン情報が無効です。再度ログインしてください。");
router.push("/login");
} else {
ElMessage.error("サーバーエラーが発生しました");
}
});
};
onMounted(fetchList);
const search = () => {
axios
.post("/api/approvalList/search", {
startDate: form.startDate,
endDate: form.endDate,
})
.then((res) => {
Object.assign(form, res.data);
if (!form.sizaiList) form.sizaiList = [];
});
};
const approval = (id) => {
if (!confirm("本当に承認しますか?")) return;
axios
.post("/api/approvalList/approval", {
targeId: id,
startDate: form.startDate,
endDate: form.endDate,
})
.then((res) => {
const response = res.data;
if (!response.success) {
ElMessage.error(response.message || "承認失敗しました");
return;
}
Object.assign(form, res.data);
if (!form.sizaiList) form.sizaiList = [];
ElMessage.success(response.message || "承認完了しました");
})
.catch(() => {
ElMessage.error("サーバーエラーが発生しました");
});
};
const reject = (id) => {
if (!confirm("本当に却下しますか?")) return;
axios
.post("/api/approvalList/reject", {
targeId: id,
startDate: form.startDate,
endDate: form.endDate,
})
.then((res) => {
const response = res.data;
if (!response.success) {
ElMessage.error(response.message || "却下失敗しました");
return;
}
Object.assign(form, response.data);
if (!form.sizaiList) form.sizaiList = [];
ElMessage.success(response.message || "却下完了しました");
})
.catch(() => {
ElMessage.error("サーバーエラーが発生しました");
});
};
</script>
<style scoped>
@import "@/assets/common.css";
.page-container {
max-width: 1000px;
margin: 0 auto;
padding: 20px;
box-sizing: border-box;
}
.search-form {
margin-bottom: 20px;
display: flex;
gap: 10px;
align-items: center;
}
th,
td {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>

166
src/views/DeleverAct.vue Normal file
View File

@ -0,0 +1,166 @@
<template>
<div class="page-container">
<UserMenu />
<form @submit.prevent="search" class="search-form">
<select v-model="form.deptId" required>
<option disabled value="">選択してください</option>
<option v-for="dept in state.deptList" :key="dept.id" :value="dept.id">
{{ dept.name }}
</option>
</select>
<button type="submit">検索</button>
</form>
<table v-if="state.sizaiList.length > 0" class="outputtable">
<thead>
<tr>
<th>資材ID</th>
<th>資材名</th>
<th>数量</th>
<th>カテゴリー</th>
<th>購入依頼者</th>
<th>購入依頼部門</th>
<th>状態</th>
<th>依頼日</th>
<th>納品</th>
<th>QRコード</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in state.sizaiList" :key="index">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.num }}</td>
<td>{{ item.category_name }}</td>
<td>{{ item.request_user_name }}</td>
<td>{{ item.request_dept_name }}</td>
<td>{{ item.status_name }}</td>
<td>{{ item.request_date }}</td>
<td>
<template v-if="item.status == 2 || item.status == 4">
<a href="#" @click.prevent="delever(item.id)">納品</a>
</template>
<template v-else>
<span style="color: red">納品</span>
</template>
</td>
<td>
<el-popover placement="top" trigger="hover" width="auto">
<template #reference>
<span style="cursor: pointer; color: blue">QRコード</span>
</template>
<QrCode :id="item.id" />
</el-popover>
</td>
</tr>
</tbody>
</table>
<div v-else style="text-align: center; margin-top: 20px">
データがありません
</div>
</div>
</template>
<script setup>
import { reactive, onMounted } from "vue";
import axios from "axios";
import UserMenu from "../components/UserMenu.vue";
import { useRouter } from "vue-router";
import { ElMessage } from "element-plus";
import QrCode from "../components/QrCode.vue";
const router = useRouter();
const form = reactive({
deptId: "",
});
const state = reactive({
deptList: [],
sizaiList: [],
});
const fetchList = () => {
axios
.get("/api/delever/init")
.then((res) => {
const response = res.data;
if (!response.success) {
ElMessage.error(response.message || "初期化失敗しました");
return;
}
state.deptList = response.data.deptList;
state.sizaiList = response.data.sizaiList || [];
form.deptId =
response.data.deptId ||
(state.deptList.length > 0 ? state.deptList[0].id : "");
})
.catch((err) => {
if ([401, 403].includes(err.response?.status)) {
ElMessage.error("ログイン情報が無効です。再度ログインしてください。");
router.push("/login");
} else {
ElMessage.error("サーバーエラーが発生しました");
}
});
};
onMounted(fetchList);
const search = () => {
axios
.post("/api/delever/search", {
deptId: form.deptId,
})
.then((res) => {
const response = res.data;
if (!response.success) {
ElMessage.error(response.message || "検索失敗しました");
return;
}
state.sizaiList = response.data.sizaiList || [];
});
};
const delever = (id) => {
if (!confirm("納品に操作しますか?")) return;
axios
.post("/api/delever/act", {
id,
deptId: form.deptId,
})
.then((res) => {
const response = res.data;
if (!response.success) {
ElMessage.error(response.message || "納品失敗しました");
return;
}
state.sizaiList = response.data.sizaiList || [];
search();
ElMessage.success(response.message || "納品完了しました");
})
.catch(() => {
ElMessage.error("サーバーエラーが発生しました");
});
};
</script>
<style scoped>
@import "@/assets/common.css";
.page-container {
max-width: 1000px;
margin: 0 auto;
padding: 20px;
box-sizing: border-box;
}
.search-form {
margin-bottom: 20px;
display: flex;
gap: 10px;
align-items: center;
}
</style>

251
src/views/InStore.vue Normal file
View File

@ -0,0 +1,251 @@
<template>
<div class="page-container">
<UserMenu />
<form @submit.prevent="search" class="search-form">
<button @click="scanQR">QRコード読取</button>
<div v-show="isScanning">
<div id="reader" style="width: 300px"></div>
</div>
<input
id="target"
v-model="form.id"
type="number"
placeholder="資材IDを入力"
required
/>
<button type="submit">検索</button>
</form>
<form @submit.prevent="submitForm">
<table class="inputtable">
<tr>
<td>資材ID</td>
<td>{{ form.id }}</td>
</tr>
<tr>
<td>資材名</td>
<td>{{ form.name }}</td>
</tr>
<tr>
<td>数量</td>
<td>{{ form.num }}</td>
</tr>
<tr>
<td>カテゴリー</td>
<td>{{ form.category_name }}</td>
</tr>
<tr>
<td>状態</td>
<td>{{ form.status_name }}</td>
</tr>
<tr>
<td>倉庫</td>
<td v-if="form.status === '5' || form.status === '7'">
<select v-model="form.souko_id" required>
<option disabled value="">選択してください</option>
<option
v-for="sou in state.soukoList"
:key="sou.id"
:value="sou.id"
>
{{ sou.name }}
</option>
</select>
</td>
<td v-else>
{{ form.souko_name || "" }}
</td>
</tr>
<tr>
<td>購入依頼者</td>
<td>{{ form.request_user_name }}</td>
</tr>
<tr>
<td>購入依頼部門</td>
<td>{{ form.request_dept_name }}</td>
</tr>
<tr>
<td>依頼日</td>
<td>{{ form.request_date }}</td>
</tr>
<tr>
<td>発注日</td>
<td>{{ form.order_date }}</td>
</tr>
<tr>
<td>納品日</td>
<td>{{ form.delivery_date }}</td>
</tr>
<tr>
<td>入庫日</td>
<td>{{ form.instore_date }}</td>
</tr>
<tr>
<td>出庫日</td>
<td>{{ form.outstore_date }}</td>
</tr>
<tr>
<td>備考</td>
<td>{{ form.note }}</td>
</tr>
</table>
<div
v-if="form.status === '5' || form.status === '7'"
style="margin-top: 20px"
>
<button type="submit">入庫</button>
</div>
</form>
</div>
</template>
<script setup>
import { reactive, ref, onMounted } from "vue";
import axios from "axios";
import { useRouter } from "vue-router";
import { ElMessage } from "element-plus";
import UserMenu from "../components/UserMenu.vue";
import { Html5Qrcode } from "html5-qrcode";
const router = useRouter();
const form = reactive({
id: "",
name: "",
num: "",
category_name: "",
status_name: "",
status: 0,
souko_id: "",
souko_name: "",
request_user_name: "",
request_dept_name: "",
request_date: "",
order_date: "",
delivery_date: "",
instore_date: "",
outstore_date: "",
note: "",
deptId: "",
});
const state = reactive({
soukoList: [],
});
const isScanning = ref(false);
const scanQR = () => {
isScanning.value = true;
const html5QrCode = new Html5Qrcode("reader");
html5QrCode
.start(
{ facingMode: "environment" },
{
fps: 10,
qrbox: 250,
},
(decodedText) => {
form.id = decodedText;
isScanning.value = false;
html5QrCode
.stop()
.then(() => {
/* 停止成功時の処理 */
})
.catch(() => {
/* 停止失敗時の処理 */
});
search();
},
(errorMessage) => {
console.warn("読み取りエラー: ", errorMessage);
}
)
.catch((err) => {
ElMessage.error("QRコード読み取りに失敗しました");
isScanning.value = false;
});
};
const fetchList = async () => {
try {
const res = await axios.get("/api/inStore/init");
const response = res.data;
if (!response.success) {
ElMessage.error(response.message || "初期化に失敗しました");
router.push("/login");
}
} catch (err) {
ElMessage.error("サーバーエラーが発生しました");
router.push("/login");
}
};
const search = async () => {
if (!form.id || form.id === "") {
ElMessage.warning("資材IDを入力してください");
return;
}
try {
const res = await axios.post("/api/inStore/search", { id: form.id });
const response = res.data;
if (!response.success) {
ElMessage.error(response.message || "検索失敗しました");
return;
}
const data = response.data;
if (!data) {
ElMessage.error("資材データが見つかりませんでした");
return;
}
Object.assign(form, data.sizai);
state.soukoList = data.soukoList || [];
} catch (err) {
ElMessage.error("検索中にサーバーエラーが発生しました");
}
};
const submitForm = async () => {
if (!confirm("入庫に操作しますか?")) return;
axios
.post("/api/inStore/act", { sizai: { ...form } })
.then((res) => {
const response = res.data;
if (!response.success) {
ElMessage.error(response.message || "入庫失敗しました");
return;
}
Object.assign(form, response.data.sizai);
ElMessage.success(response.message || "入庫完了しました");
})
.catch(() => {
ElMessage.error("サーバーエラーが発生しました");
});
};
onMounted(fetchList);
</script>
<style scoped>
@import "@/assets/common.css";
.page-container {
max-width: 1000px;
margin: 0 auto;
padding: 20px;
box-sizing: border-box;
}
.search-form {
margin-bottom: 20px;
display: flex;
gap: 10px;
align-items: center;
}
</style>

156
src/views/OrderAct.vue Normal file
View File

@ -0,0 +1,156 @@
<template>
<div class="page-container">
<UserMenu />
<form @submit.prevent="search" class="search-form">
<select v-model="form.deptId" required>
<option disabled value="">選択してください</option>
<option v-for="dept in state.deptList" :key="dept.id" :value="dept.id">
{{ dept.name }}
</option>
</select>
<button type="submit">検索</button>
</form>
<table v-if="state.sizaiList.length > 0" class="outputtable">
<thead>
<tr>
<th>資材ID</th>
<th>資材名</th>
<th>数量</th>
<th>カテゴリー</th>
<th>購入依頼者</th>
<th>購入依頼部門</th>
<th>状態</th>
<th>依頼日</th>
<th>発注</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in state.sizaiList" :key="index">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.num }}</td>
<td>{{ item.category_name }}</td>
<td>{{ item.request_user_name }}</td>
<td>{{ item.request_dept_name }}</td>
<td>{{ item.status_name }}</td>
<td>{{ item.request_date }}</td>
<td>
<template v-if="item.status == 2">
<a href="#" @click.prevent="order(item.id)">発注</a>
</template>
<template v-else>
<span style="color: red">発注済み</span>
</template>
</td>
</tr>
</tbody>
</table>
<div v-else style="text-align: center; margin-top: 20px">
データがありません
</div>
</div>
</template>
<script setup>
import { reactive, onMounted } from "vue";
import axios from "axios";
import UserMenu from "../components/UserMenu.vue";
import { useRouter } from "vue-router";
import { ElMessage } from "element-plus";
const router = useRouter();
const form = reactive({
deptId: "",
});
const state = reactive({
deptList: [],
sizaiList: [],
});
const fetchList = () => {
axios
.get("/api/order/init")
.then((res) => {
const response = res.data;
if (!response.success) {
ElMessage.error(response.message || "初期化失敗しました");
return;
}
state.deptList = response.data.deptList;
state.sizaiList = response.data.sizaiList || [];
form.deptId =
response.data.deptId ||
(state.deptList.length > 0 ? state.deptList[0].id : "");
})
.catch((err) => {
if ([401, 403].includes(err.response?.status)) {
ElMessage.error("ログイン情報が無効です。再度ログインしてください。");
router.push("/login");
} else {
ElMessage.error("サーバーエラーが発生しました");
}
});
};
onMounted(fetchList);
const search = () => {
axios
.post("/api/order/search", {
deptId: form.deptId,
})
.then((res) => {
const response = res.data;
if (!response.success) {
ElMessage.error(response.message || "検索失敗しました");
return;
}
state.sizaiList = response.data.sizaiList || [];
});
};
const order = (id) => {
if (!confirm("本当に注文しますか?")) return;
axios
.post("/api/order/act", {
id,
deptId: form.deptId,
})
.then((res) => {
const response = res.data;
if (!response.success) {
ElMessage.error(response.message || "注文失敗しました");
return;
}
state.sizaiList = response.data.sizaiList || [];
search();
ElMessage.success(response.message || "注文完了しました");
})
.catch(() => {
ElMessage.error("サーバーエラーが発生しました");
});
};
</script>
<style scoped>
@import "@/assets/common.css";
.page-container {
max-width: 1000px;
margin: 0 auto;
padding: 20px;
box-sizing: border-box;
}
.search-form {
margin-bottom: 20px;
display: flex;
gap: 10px;
align-items: center;
}
</style>