|
|
@@ -3,77 +3,78 @@
|
|
|
<div class="app-container">
|
|
|
<div class="form-container">
|
|
|
<div class="section-container">
|
|
|
- <div class="form-section">対象 </div>
|
|
|
- <el-form-item class="radio-group-vertical">
|
|
|
- <div class="radio-container">
|
|
|
- <el-radio
|
|
|
- label="immediate"
|
|
|
- v-model="queryParams.releaseType"
|
|
|
- class="vertical-radio"
|
|
|
- >月指定</el-radio>
|
|
|
- <div class="scheduled-row">
|
|
|
- <!-- 期間指定时显示的日期选择(同行) -->
|
|
|
- <div class="date-group" >
|
|
|
- <!-- 日期选择器代码保持不变 -->
|
|
|
- <el-select v-model="queryParams.monthYear" placeholder="" class="date-select" :disabled="queryParams.releaseType === 'scheduled'">
|
|
|
- <el-option v-for="year in years" :key="year" :label="year" :value="year"></el-option>
|
|
|
- </el-select>
|
|
|
- <span class="date-label">年</span>
|
|
|
- <el-select
|
|
|
- v-model="queryParams.startMonth"
|
|
|
- placeholder=""
|
|
|
- class="date-select-small"
|
|
|
- :disabled="queryParams.releaseType === 'scheduled'"
|
|
|
- >
|
|
|
- <el-option
|
|
|
- v-for="month in months"
|
|
|
- :key="month"
|
|
|
- :label="month"
|
|
|
- :value="month"
|
|
|
- ></el-option>
|
|
|
- </el-select>
|
|
|
- <span class="date-label">月</span>
|
|
|
- <el-form-item>
|
|
|
- <el-button @click="resetForm" class="append-button">集計条件リセット</el-button>
|
|
|
- </el-form-item>
|
|
|
+ <div class="form-section">対象</div>
|
|
|
+ <el-form-item class="radio-group-vertical">
|
|
|
+ <div class="radio-container">
|
|
|
+ <el-radio
|
|
|
+ :label="TARGET_PERIOD_TYPE.MONTHLY"
|
|
|
+ v-model="queryParams.targetPeriodType"
|
|
|
+ class="vertical-radio"
|
|
|
+ >月指定
|
|
|
+ </el-radio>
|
|
|
+ <div class="annual-row">
|
|
|
+ <div class="date-group">
|
|
|
+ <el-select v-model="queryParams.monthYear" placeholder="" class="date-select"
|
|
|
+ :disabled="queryParams.targetPeriodType !== TARGET_PERIOD_TYPE.MONTHLY">
|
|
|
+ <el-option v-for="year in years" :key="year" :label="year" :value="year"></el-option>
|
|
|
+ </el-select>
|
|
|
+ <span class="date-label">年</span>
|
|
|
+ <el-select
|
|
|
+ v-model="queryParams.startMonth"
|
|
|
+ placeholder=""
|
|
|
+ class="date-select-small"
|
|
|
+ :disabled="queryParams.targetPeriodType !== TARGET_PERIOD_TYPE.MONTHLY"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="month in months"
|
|
|
+ :key="month"
|
|
|
+ :label="month"
|
|
|
+ :value="month"
|
|
|
+ ></el-option>
|
|
|
+ </el-select>
|
|
|
+ <span class="date-label">月</span>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button @click="resetForm" class="append-button">集計条件リセット</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <el-radio
|
|
|
- label="scheduled"
|
|
|
- v-model="queryParams.releaseType"
|
|
|
- class="scheduled-radio"
|
|
|
- >年度指定</el-radio>
|
|
|
- <div class="scheduled-row">
|
|
|
- <!-- 期間指定时显示的日期选择(同行) -->
|
|
|
- <div class="date-group" >
|
|
|
- <!-- 日期选择器代码保持不变 -->
|
|
|
- <el-select v-model="queryParams.startYear" placeholder="" class="date-select" :disabled="queryParams.releaseType === 'immediate'">
|
|
|
- <el-option v-for="year in years" :key="year" :label="year" :value="year"></el-option>
|
|
|
- </el-select>
|
|
|
- <span class="date-label">年度</span>
|
|
|
+ <el-radio
|
|
|
+ :label="TARGET_PERIOD_TYPE.ANNUAL"
|
|
|
+ v-model="queryParams.targetPeriodType"
|
|
|
+ class="annual-radio"
|
|
|
+ >年度指定
|
|
|
+ </el-radio>
|
|
|
+ <div class="annual-row">
|
|
|
+ <div class="date-group">
|
|
|
+ <!-- 日期选择器代码保持不变 -->
|
|
|
+ <el-select v-model="queryParams.startYear" placeholder="" class="date-select"
|
|
|
+ :disabled="queryParams.targetPeriodType !== TARGET_PERIOD_TYPE.ANNUAL">
|
|
|
+ <el-option v-for="year in years" :key="year" :label="year" :value="year"></el-option>
|
|
|
+ </el-select>
|
|
|
+ <span class="date-label">年度</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </el-form-item>
|
|
|
+ </el-form-item>
|
|
|
</div>
|
|
|
<el-form-item label="集計種別" style="margin-left: 50px;margin-top: -15px">
|
|
|
- <el-radio-group v-model="queryParams.aggregationType" class="custom-radio-group">
|
|
|
- <el-radio label="FC_CHECKBOX">FC別集計</el-radio>
|
|
|
- <el-radio label="TYPE_CHECKBOX">エリア別集計</el-radio>
|
|
|
- <el-radio label="STORE_CHECKBOX">店舗別集計</el-radio>
|
|
|
+ <el-radio-group v-model="queryParams.aggregationType" class="custom-radio-group">
|
|
|
+ <el-radio :label="AGGREGATION_TYPE.FC">FC別集計</el-radio>
|
|
|
+ <el-radio :label="AGGREGATION_TYPE.AREA">エリア別集計</el-radio>
|
|
|
+ <el-radio :label="AGGREGATION_TYPE.STORE">店舗別集計</el-radio>
|
|
|
</el-radio-group>
|
|
|
</el-form-item>
|
|
|
<div class="divider"></div>
|
|
|
<PublicRange
|
|
|
v-model="queryParams"
|
|
|
:region-tree="regionTree"
|
|
|
- :yamada-fc-brand="yamadaFcBrand "
|
|
|
+ :yamada-fc-brand="yamadaFcBrand"
|
|
|
:yamada-business-type="yamadaBusinessType"
|
|
|
@check-change="handleCheckChange"
|
|
|
:show-business-type="false"
|
|
|
/>
|
|
|
<div class="btn-section" style="padding-left: 78px; margin-top: 25px;">
|
|
|
- <button class="operate-btn" @click="Confirm" v-hasPermi="['fcbi:sales:sum']">集計</button>
|
|
|
+ <button class="operate-btn" @click="handleConfirm" v-hasPermi="['fcbi:sales:sum']">集計</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -81,16 +82,23 @@
|
|
|
|
|
|
<script name="surveySumSettings" setup>
|
|
|
import { getRegionTree } from "@/api/fcbi/survey.js";
|
|
|
-import {reactive, ref, onMounted, getCurrentInstance, watch, toRefs} from 'vue';
|
|
|
+import { reactive, ref, onMounted, getCurrentInstance, watch, toRefs } from 'vue';
|
|
|
import PublicRange from '../../../components/PublicRange.vue';
|
|
|
-import { useSurveyStore, useSurveySalesStore } from '@/store/surveyStore';
|
|
|
+import { useSurveyStore, F } from '@/store/surveyStore';
|
|
|
import { useRouter } from 'vue-router';
|
|
|
+import { AGGREGATION_TYPE, TARGET_PERIOD_TYPE } from '@/constants';
|
|
|
|
|
|
const { proxy } = getCurrentInstance();
|
|
|
const surveyStore = useSurveyStore();
|
|
|
const surveySalesStore = useSurveySalesStore();
|
|
|
const router = useRouter();
|
|
|
|
|
|
+// 导出常量以便在模板中使用
|
|
|
+defineExpose({
|
|
|
+ AGGREGATION_TYPE,
|
|
|
+ TARGET_PERIOD_TYPE
|
|
|
+});
|
|
|
+
|
|
|
/**
|
|
|
* データ辞書から品牌と業務タイプのデータを取得します
|
|
|
*/
|
|
|
@@ -103,6 +111,9 @@ const { yamada_business_type: yamadaBusinessType } = proxy.useDict('yamada_busin
|
|
|
const regionTree = ref([]);
|
|
|
const selectedRegions = ref([]);
|
|
|
const error = ref('');
|
|
|
+const currentYear = new Date().getFullYear();
|
|
|
+const years = Array.from({ length: 11 }, (_, i) => currentYear + i);
|
|
|
+const months = Array.from({ length: 12 }, (_, i) => i + 1);
|
|
|
|
|
|
/**
|
|
|
* フォームの入力データを保持するオブジェクトです
|
|
|
@@ -112,8 +123,8 @@ const data = reactive({
|
|
|
queryParams: {
|
|
|
brandCode: [],
|
|
|
businessTypeCode: [],
|
|
|
- releaseType: 'immediate',
|
|
|
- aggregationType: 'FC_CHECKBOX',
|
|
|
+ targetPeriodType: TARGET_PERIOD_TYPE.MONTHLY,
|
|
|
+ aggregationType: AGGREGATION_TYPE.FC,
|
|
|
monthYear: null,
|
|
|
startMonth: null,
|
|
|
startYear: null,
|
|
|
@@ -122,9 +133,6 @@ const data = reactive({
|
|
|
});
|
|
|
const { queryParams } = toRefs(data);
|
|
|
|
|
|
-const currentYear = new Date().getFullYear();
|
|
|
-const years = Array.from({ length: 11 }, (_, i) => currentYear + i);
|
|
|
-const months = Array.from({ length: 12 }, (_, i) => i + 1);
|
|
|
/**
|
|
|
* 地域ツリーのデータが更新されたときに、選択された地域を更新します
|
|
|
*/
|
|
|
@@ -135,9 +143,9 @@ watch(regionTree, () => {
|
|
|
}, { deep: true });
|
|
|
|
|
|
watch(
|
|
|
- () => queryParams.value.releaseType,
|
|
|
+ () => queryParams.value.targetPeriodType,
|
|
|
(newVal) => {
|
|
|
- if (newVal === 'immediate') {
|
|
|
+ if (newVal === TARGET_PERIOD_TYPE.MONTHLY) {
|
|
|
queryParams.value.startYear = null;
|
|
|
} else {
|
|
|
queryParams.value.monthYear = null;
|
|
|
@@ -151,17 +159,24 @@ watch(
|
|
|
* コンポーネントのマウント後に地域ツリーデータを初期化します
|
|
|
*/
|
|
|
onMounted(async () => {
|
|
|
- const response = await getRegionTree();
|
|
|
- if (response?.success) {
|
|
|
- const regions = response.data.regions || [];
|
|
|
- regionTree.value = regions;
|
|
|
- surveyStore.setRegionTree(regions)
|
|
|
- if (regionTree.value.length > 0) {
|
|
|
- updateSelectedRegions(regionTree.value);
|
|
|
+ try {
|
|
|
+ const response = await getRegionTree();
|
|
|
+ if (response?.success) {
|
|
|
+ const regions = response.data.regions || [];
|
|
|
+ regionTree.value = regions;
|
|
|
+ surveyStore.setRegionTree(regions)
|
|
|
+ if (regionTree.value.length > 0) {
|
|
|
+ updateSelectedRegions(regionTree.value);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ error.value = response?.message || '地域データの取得に失敗しました';
|
|
|
+ proxy.$message.error(error.value);
|
|
|
+ console.error('地域データの取得に失敗しました:', response);
|
|
|
}
|
|
|
- } else {
|
|
|
- error.value = response?.message || '地域データの取得に失敗しました';
|
|
|
- console.error('地域データの取得に失敗しました:', response);
|
|
|
+ } catch (err) {
|
|
|
+ error.value = '地域データの取得中にエラーが発生しました';
|
|
|
+ proxy.$message.error(error.value);
|
|
|
+ console.error('地域データの取得中にエラーが発生しました:', err);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
@@ -172,15 +187,15 @@ const handleCheckChange = (regionId, isChecked) => {
|
|
|
const region = findRegionById(regionTree.value, regionId);
|
|
|
if (region) {
|
|
|
if (isChecked) {
|
|
|
- if (!selectedRegions.value.some(r => r.region_code === region.regionCode)) {
|
|
|
+ if (!selectedRegions.value.some(r => r.regionCode === region.regionCode)) {
|
|
|
selectedRegions.value.push({
|
|
|
- region_code: region.regionCode
|
|
|
+ regionCode: region.regionCode
|
|
|
});
|
|
|
}
|
|
|
} else {
|
|
|
- selectedRegions.value = selectedRegions.value.filter(r => r.region_code !== region.regionCode);
|
|
|
+ selectedRegions.value = selectedRegions.value.filter(r => r.regionCode !== region.regionCode);
|
|
|
}
|
|
|
- queryParams.value.regions = selectedRegions.value;
|
|
|
+ queryParams.value.regions = [...selectedRegions.value];
|
|
|
}
|
|
|
};
|
|
|
|
|
|
@@ -188,6 +203,8 @@ const handleCheckChange = (regionId, isChecked) => {
|
|
|
* 指定されたIDを持つ地域ノードをツリーから再帰的に検索します
|
|
|
*/
|
|
|
const findRegionById = (nodes, id) => {
|
|
|
+ if (!nodes || !nodes.length) return null;
|
|
|
+
|
|
|
for (const node of nodes) {
|
|
|
if (node.id === id) {
|
|
|
return node;
|
|
|
@@ -206,10 +223,11 @@ const findRegionById = (nodes, id) => {
|
|
|
* 選択されたすべての地域を再帰的に更新し、サブノードのみを収集します
|
|
|
*/
|
|
|
const updateSelectedRegions = (nodes) => {
|
|
|
+ if (!nodes || !nodes.length) return;
|
|
|
selectedRegions.value = [];
|
|
|
// 最上位ノードは親ノードとしてマークされ、再帰的に子ノードを処理します
|
|
|
collectSelectedRegions(nodes, true);
|
|
|
- queryParams.value.regions = selectedRegions.value;
|
|
|
+ queryParams.value.regions = [...selectedRegions.value];
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
@@ -226,7 +244,7 @@ const collectSelectedRegions = (nodes, isParent = false) => {
|
|
|
}
|
|
|
if (node.checked) {
|
|
|
selectedRegions.value.push({
|
|
|
- region_code: node.regionCode
|
|
|
+ regionCode: node.regionCode
|
|
|
});
|
|
|
}
|
|
|
if (node.children && node.children.length > 0) {
|
|
|
@@ -235,40 +253,52 @@ const collectSelectedRegions = (nodes, isParent = false) => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
-const Confirm = () => {
|
|
|
-
|
|
|
- let isValid = true;
|
|
|
+/**
|
|
|
+ * 検索条件を検証する関数です
|
|
|
+ */
|
|
|
+const validateForm = () => {
|
|
|
+ const errors = [];
|
|
|
|
|
|
- if (queryParams.value.releaseType === 'immediate') {
|
|
|
+ if (queryParams.value.targetPeriodType === TARGET_PERIOD_TYPE.MONTHLY) {
|
|
|
if (!queryParams.value.monthYear) {
|
|
|
- isValid = false;
|
|
|
- proxy.$message.warning('月指定の年を選択してください');
|
|
|
+ errors.push('「対象 月指定」の年を選択してください');
|
|
|
}
|
|
|
if (!queryParams.value.startMonth) {
|
|
|
- isValid = false;
|
|
|
- proxy.$message.warning('月指定の月を選択してください');
|
|
|
+ errors.push('「対象 月指定」の月を選択してください');
|
|
|
}
|
|
|
- }
|
|
|
- else if (queryParams.value.releaseType === 'scheduled') {
|
|
|
+ } else if (queryParams.value.targetPeriodType === TARGET_PERIOD_TYPE.ANNUAL) {
|
|
|
if (!queryParams.value.startYear) {
|
|
|
- isValid = false;
|
|
|
- proxy.$message.warning('年度指定の年度を選択してください');
|
|
|
+ errors.push('「対象 年度指定」の年度を選択してください');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (!isValid) {
|
|
|
+ return errors;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 確認ボタンをクリックしたときの処理関数です
|
|
|
+ * @constructor
|
|
|
+ */
|
|
|
+const handleConfirm = () => {
|
|
|
+
|
|
|
+ const errors = validateForm();
|
|
|
+
|
|
|
+ if (errors.length > 0) {
|
|
|
+ errors.forEach(error => {
|
|
|
+ proxy.$message.warning(error);
|
|
|
+ });
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
let salesFlag = 0;
|
|
|
- const isMonth = queryParams.value.releaseType === 'immediate';
|
|
|
+ const isMonth = queryParams.value.targetPeriodType === TARGET_PERIOD_TYPE.MONTHLY;
|
|
|
|
|
|
switch (queryParams.value.aggregationType) {
|
|
|
- case 'FC_CHECKBOX':
|
|
|
+ case AGGREGATION_TYPE.FC:
|
|
|
const hasArea = queryParams.value.regions && queryParams.value.regions.length > 0;
|
|
|
salesFlag = isMonth ? (hasArea ? 1 : 2) : (hasArea ? 3 : 4);
|
|
|
break;
|
|
|
- case 'STORE_CHECKBOX':
|
|
|
+ case AGGREGATION_TYPE.STORE:
|
|
|
salesFlag = isMonth ? 5 : 6;
|
|
|
break;
|
|
|
default:
|
|
|
@@ -276,30 +306,32 @@ const Confirm = () => {
|
|
|
}
|
|
|
|
|
|
const transferData = {
|
|
|
- releaseType: queryParams.value.releaseType,
|
|
|
+ targetPeriodType: queryParams.value.targetPeriodType,
|
|
|
monthYear: isMonth ? queryParams.value.monthYear : null,
|
|
|
startMonth: isMonth ? queryParams.value.startMonth : null,
|
|
|
startYear: !isMonth ? queryParams.value.startYear : null,
|
|
|
brandCodes: queryParams.value.brandCode,
|
|
|
- regionCodes: queryParams.value.regions.map(region => region.region_code),
|
|
|
+ regionCodes: queryParams.value.regions.map(region => region.regionCode),
|
|
|
aggregationType: queryParams.value.aggregationType,
|
|
|
- salesFlag
|
|
|
+ salesFlag: salesFlag
|
|
|
};
|
|
|
|
|
|
surveySalesStore.setSalesData(transferData);
|
|
|
router.push({ name: 'salesSumResult' });
|
|
|
};
|
|
|
|
|
|
+/**
|
|
|
+ * キャンセルボタンをクリックしたときの処理関数です
|
|
|
+ */
|
|
|
const resetForm = () => {
|
|
|
- queryParams.value.releaseType = 'immediate';
|
|
|
- queryParams.value.aggregationType = 'FC_CHECKBOX';
|
|
|
+ queryParams.value.targetPeriodType = TARGET_PERIOD_TYPE.MONTHLY;
|
|
|
+ queryParams.value.aggregationType = AGGREGATION_TYPE.FC;
|
|
|
queryParams.value.monthYear = null;
|
|
|
queryParams.value.startMonth = null;
|
|
|
queryParams.value.startYear = null;
|
|
|
queryParams.value.brandCode = [];
|
|
|
-
|
|
|
- selectedRegions.value = [];
|
|
|
queryParams.value.regions = [];
|
|
|
+ selectedRegions.value = [];
|
|
|
if (regionTree.value.length > 0) {
|
|
|
resetRegionTreeCheck(regionTree.value);
|
|
|
}
|
|
|
@@ -351,14 +383,14 @@ const resetRegionTreeCheck = (nodes) => {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
}
|
|
|
-.scheduled-row {
|
|
|
+.annual-row {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
margin-left: 88px;
|
|
|
margin-top: -45px;
|
|
|
}
|
|
|
@media (max-width:48em) {
|
|
|
- .scheduled-row {
|
|
|
+ .annual-row {
|
|
|
margin-left: 13%;
|
|
|
width: 80%;
|
|
|
}
|