|
|
@@ -12,7 +12,7 @@
|
|
|
<div class="monthly-section">
|
|
|
<div class="date-groups-wrapper">
|
|
|
<div class="date-group">
|
|
|
- <el-radio class="common-radio" :label="TARGET_PERIOD_TYPE.MONTHLY" v-model="queryParams.targetPeriodType">
|
|
|
+ <el-radio class="common-radio" :value="TARGET_PERIOD_TYPE.MONTHLY" v-model="queryParams.targetPeriodType">
|
|
|
月指定
|
|
|
</el-radio>
|
|
|
<el-select class="sales-sum-date-select" v-model="queryParams.startYear" placeholder=""
|
|
|
@@ -32,7 +32,7 @@
|
|
|
</div>
|
|
|
<!-- 年度指定行 -->
|
|
|
<div class="radio-item annual-group">
|
|
|
- <el-radio class="common-radio" :label="TARGET_PERIOD_TYPE.ANNUAL" v-model="queryParams.targetPeriodType">
|
|
|
+ <el-radio class="common-radio" :value="TARGET_PERIOD_TYPE.ANNUAL" v-model="queryParams.targetPeriodType">
|
|
|
年度指定
|
|
|
</el-radio>
|
|
|
<div class="annual-row">
|
|
|
@@ -55,9 +55,9 @@
|
|
|
<el-form-item class="content-group"> <!-- 复用content-group,确保内容区域基准一致 -->
|
|
|
<el-radio-group v-model="queryParams.aggregationType" class="radio-group-horizontal">
|
|
|
<!-- 为每个radio添加common-radio类,与“対象”区域的单选框样式统一 -->
|
|
|
- <el-radio class="common-radio" :label="AGGREGATION_TYPE.FC">FC別集計</el-radio>
|
|
|
- <el-radio class="common-radio" :label="AGGREGATION_TYPE.AREA">エリア別集計</el-radio>
|
|
|
- <el-radio class="common-radio" :label="AGGREGATION_TYPE.STORE">店舗別集計</el-radio>
|
|
|
+ <el-radio class="common-radio" :value="AGGREGATION_TYPE.FC">FC別集計</el-radio>
|
|
|
+ <el-radio class="common-radio" :value="AGGREGATION_TYPE.AREA">エリア別集計</el-radio>
|
|
|
+ <el-radio class="common-radio" :value="AGGREGATION_TYPE.STORE">店舗別集計</el-radio>
|
|
|
</el-radio-group>
|
|
|
</el-form-item>
|
|
|
</div>
|
|
|
@@ -82,43 +82,33 @@
|
|
|
</template>
|
|
|
|
|
|
<script name="purchaseSaleSettings" setup>
|
|
|
+// 1. 基础依赖导入
|
|
|
import { reactive, ref, onMounted, getCurrentInstance, watch, toRefs } from 'vue';
|
|
|
import { useRouter } from 'vue-router';
|
|
|
import { getRegionTree } from "@/api/fcbi/survey.js";
|
|
|
import PublicRange from '../../../components/PublicRange.vue';
|
|
|
import { useSurveyStore, useSalesStore } from '@/store/yamadaStore';
|
|
|
+// 定数ファイルから集計タイプ(FC / エリア / 店舗別)と対象期間タイプ(年度 / 月指定)の定数をインポート
|
|
|
import { AGGREGATION_TYPE, TARGET_PERIOD_TYPE } from '@/constants';
|
|
|
|
|
|
-// テンプレートで定数を使用可能にするため、エクスポートします
|
|
|
-defineExpose({ AGGREGATION_TYPE, TARGET_PERIOD_TYPE });
|
|
|
-
|
|
|
-const error = ref('');
|
|
|
+// 2. 组件实例与状态管理
|
|
|
const { proxy } = getCurrentInstance();
|
|
|
const surveyStore = useSurveyStore();
|
|
|
const salesStore = useSalesStore();
|
|
|
const router = useRouter();
|
|
|
|
|
|
-/**
|
|
|
- * データ辞書からブランドと業務タイプのデータを取得します
|
|
|
- */
|
|
|
-const { yamada_fc_brand: yamadaFcBrand } = proxy.useDict('yamada_fc_brand');
|
|
|
-const { yamada_business_type: yamadaBusinessType } = proxy.useDict('yamada_business_type');
|
|
|
-
|
|
|
-/**
|
|
|
- * 地域ツリーデータと選択された地域コードの配列を保持します
|
|
|
- */
|
|
|
-const regionTree = ref([]);
|
|
|
-const selectedRegions = ref([]);
|
|
|
+// 3. 基础数据与状态定义
|
|
|
+const error = ref('');
|
|
|
+const regionTree = ref([]); // 地域ツリーデータ
|
|
|
+const selectedRegions = ref([]); // 選択された地域コードの配列
|
|
|
|
|
|
+// 年月选择器数据
|
|
|
const currentYear = new Date().getFullYear();
|
|
|
const years = Array.from({ length: 11 }, (_, i) => currentYear + i);
|
|
|
const months = Array.from({ length: 12 }, (_, i) => i + 1);
|
|
|
|
|
|
-/**
|
|
|
- * フォームの入力データを保持するオブジェクトです
|
|
|
- */
|
|
|
+// フォームの入力データ
|
|
|
const data = reactive({
|
|
|
- // 検索条件を格納するオブジェクト
|
|
|
queryParams: {
|
|
|
targetPeriodType: TARGET_PERIOD_TYPE.MONTHLY,
|
|
|
aggregationType: AGGREGATION_TYPE.FC,
|
|
|
@@ -132,43 +122,21 @@ const data = reactive({
|
|
|
});
|
|
|
const { queryParams } = toRefs(data);
|
|
|
|
|
|
-/**
|
|
|
- * 地域ツリーのデータが更新されたときに、選択された地域を更新します
|
|
|
- */
|
|
|
-watch(() => regionTree.value, (newVal) => {
|
|
|
- if (newVal?.length) {
|
|
|
- updateSelectedRegions(newVal);
|
|
|
- }
|
|
|
-}, { deep: true });
|
|
|
+// 4. 数据字典获取
|
|
|
+const { yamada_fc_brand: yamadaFcBrand } = proxy.useDict('yamada_fc_brand');
|
|
|
+const { yamada_business_type: yamadaBusinessType } = proxy.useDict('yamada_business_type');
|
|
|
|
|
|
-/**
|
|
|
- * 対象期間タイプが変更されたときに、関連する日付フィールドをリセットします
|
|
|
- * - 月指定の場合は年度指定フィールドをクリア
|
|
|
- * - 年度指定の場合は月指定フィールドをクリア
|
|
|
- */
|
|
|
-watch(
|
|
|
- () => queryParams.value.targetPeriodType,
|
|
|
- (newVal) => {
|
|
|
- if (newVal === TARGET_PERIOD_TYPE.MONTHLY) {
|
|
|
- queryParams.value.annual = null;
|
|
|
- } else {
|
|
|
- queryParams.value.startYear = null;
|
|
|
- queryParams.value.startMonth = null;
|
|
|
- }
|
|
|
- },
|
|
|
- { immediate: true }
|
|
|
-);
|
|
|
+// 5. 暴露模板使用的常量
|
|
|
+defineExpose({ AGGREGATION_TYPE, TARGET_PERIOD_TYPE });
|
|
|
|
|
|
-/**
|
|
|
- * コンポーネントのマウント後に地域ツリーデータを初期化します
|
|
|
- */
|
|
|
+// 6. 初始化与生命周期
|
|
|
onMounted(async () => {
|
|
|
try {
|
|
|
const response = await getRegionTree();
|
|
|
if (response?.success) {
|
|
|
const regions = response.data.regions || [];
|
|
|
regionTree.value = regions;
|
|
|
- surveyStore.setRegionTree(regions)
|
|
|
+ // surveyStore.setRegionTree(regions)
|
|
|
if (regions.length) {
|
|
|
updateSelectedRegions(regions);
|
|
|
}
|
|
|
@@ -184,25 +152,35 @@ onMounted(async () => {
|
|
|
}
|
|
|
});
|
|
|
|
|
|
+// 7. 监听器
|
|
|
/**
|
|
|
- * 地域のチェック状態が変更されたときのハンドラー関数です
|
|
|
- * @param {string|number} regionId - チェック状態が変更された地域のID
|
|
|
- * @param {boolean} isChecked - チェック状態(true:チェックされた、false:チェックが外れた)
|
|
|
+ * 地域ツリーのデータが更新されたときに、選択された地域を更新します
|
|
|
*/
|
|
|
-const handleCheckChange = (regionId, isChecked) => {
|
|
|
- const region = findRegionById(regionTree.value, regionId);
|
|
|
- if (!region) return;
|
|
|
-
|
|
|
- if (isChecked) {
|
|
|
- if (!selectedRegions.value.some(r => r.regionCode === region.regionCode)) {
|
|
|
- selectedRegions.value.push({ regionCode: region.regionCode });
|
|
|
- }
|
|
|
- } else {
|
|
|
- selectedRegions.value = selectedRegions.value.filter(r => r.regionCode !== region.regionCode);
|
|
|
+watch(() => regionTree.value, (newVal) => {
|
|
|
+ if (newVal?.length) {
|
|
|
+ updateSelectedRegions(newVal);
|
|
|
}
|
|
|
- queryParams.value.regions = [...selectedRegions.value];
|
|
|
-};
|
|
|
+}, { deep: true });
|
|
|
+
|
|
|
+/**
|
|
|
+ * 対象期間タイプが変更されたときに、関連する日付フィールドをリセットします
|
|
|
+ * - 月指定の場合は年度指定フィールドをクリア
|
|
|
+ * - 年度指定の場合は月指定フィールドをクリア
|
|
|
+ */
|
|
|
+watch(
|
|
|
+ () => queryParams.value.targetPeriodType,
|
|
|
+ (newVal) => {
|
|
|
+ if (newVal === TARGET_PERIOD_TYPE.MONTHLY) {
|
|
|
+ queryParams.value.annual = null;
|
|
|
+ } else {
|
|
|
+ queryParams.value.startYear = null;
|
|
|
+ queryParams.value.startMonth = null;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { immediate: true }
|
|
|
+);
|
|
|
|
|
|
+// 8. 地域树处理方法(核心工具方法)
|
|
|
/**
|
|
|
* 指定されたIDを持つ地域ノードをツリーから再帰的に検索します
|
|
|
* @param {Array} nodes - 検索対象の地域ノード配列
|
|
|
@@ -265,6 +243,41 @@ const collectSelectedRegions = (nodes, isParent = false) => {
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
+ * 地域ツリーのチェック状態を再帰的にリセットします
|
|
|
+ * すべてのノードのcheckedプロパティをfalseに設定します
|
|
|
+ * @param {Array} nodes - 地域ツリーのノード配列
|
|
|
+ */
|
|
|
+const resetRegionTreeCheck = (nodes) => {
|
|
|
+ nodes.forEach(node => {
|
|
|
+ node.checked = false;
|
|
|
+ if (node.children?.length) {
|
|
|
+ resetRegionTreeCheck(node.children);
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 9. 事件处理方法
|
|
|
+/**
|
|
|
+ * 地域のチェック状態が変更されたときのハンドラー関数です
|
|
|
+ * @param {string|number} regionId - チェック状態が変更された地域のID
|
|
|
+ * @param {boolean} isChecked - チェック状態(true:チェックされた、false:チェックが外れた)
|
|
|
+ */
|
|
|
+const handleCheckChange = (regionId, isChecked) => {
|
|
|
+ const region = findRegionById(regionTree.value, regionId);
|
|
|
+ if (!region) return;
|
|
|
+
|
|
|
+ if (isChecked) {
|
|
|
+ if (!selectedRegions.value.some(r => r.regionCode === region.regionCode)) {
|
|
|
+ selectedRegions.value.push({ regionCode: region.regionCode });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ selectedRegions.value = selectedRegions.value.filter(r => r.regionCode !== region.regionCode);
|
|
|
+ }
|
|
|
+ queryParams.value.regions = [...selectedRegions.value];
|
|
|
+};
|
|
|
+
|
|
|
+// 10. 表单验证与提交
|
|
|
+/**
|
|
|
* 検索条件を検証する関数です
|
|
|
* 必須項目の入力状態を確認し、未入力の場合はエラーメッセージを返します
|
|
|
* @returns {Array} エラーメッセージの配列(検証が通った場合は空配列)
|
|
|
@@ -352,20 +365,6 @@ const resetForm = () => {
|
|
|
resetRegionTreeCheck(regionTree.value);
|
|
|
}
|
|
|
};
|
|
|
-
|
|
|
-/**
|
|
|
- * 地域ツリーのチェック状態を再帰的にリセットします
|
|
|
- * すべてのノードのcheckedプロパティをfalseに設定します
|
|
|
- * @param {Array} nodes - 地域ツリーのノード配列
|
|
|
- */
|
|
|
-const resetRegionTreeCheck = (nodes) => {
|
|
|
- nodes.forEach(node => {
|
|
|
- node.checked = false;
|
|
|
- if (node.children?.length) {
|
|
|
- resetRegionTreeCheck(node.children);
|
|
|
- }
|
|
|
- });
|
|
|
-};
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|