quyx@nextosd.com 4 月之前
父节点
当前提交
7431a42e73
共有 6 个文件被更改,包括 575 次插入206 次删除
  1. 8 0
      src/api/fcbi/survey.js
  2. 二进制
      src/assets/images/img.png
  3. 14 0
      src/router/index.js
  4. 272 206
      src/views/fcbi/survey/detail.vue
  5. 13 0
      src/views/fcbi/wares/detail.vue
  6. 268 0
      src/views/fcbi/wares/index.vue

+ 8 - 0
src/api/fcbi/survey.js

@@ -9,6 +9,14 @@ export function listSurvey(query) {
   })
 }
 
+export function listSurveyDetail(data) {
+  return request({
+    url: '/system/survey/listDetail',
+    method: 'post',
+    data: data
+  })
+}
+
 // 查询調査アンケート主(時間制御と状態管理を含む)详细
 export function getSurvey(id) {
   return request({

二进制
src/assets/images/img.png


+ 14 - 0
src/router/index.js

@@ -280,6 +280,20 @@ export const constantRoutes = [
             }
         ]
     },
+    {
+        path: '/waresAdmin',
+        component: Layout,
+        hidden: true,
+        redirect: 'noredirect',
+        children: [
+            {
+                path: 'waresDetail',
+                component: () => import('@/views/fcbi/wares/detail'),
+                name: 'waresDetail',
+                meta: {title: '商品詳細', icon: 'user'}
+            }
+        ]
+    },
 ]
 
 // ダイナミックルート、ユーザー権限に基づいて動的に読み込みます

+ 272 - 206
src/views/fcbi/survey/detail.vue

@@ -8,34 +8,35 @@
                label-width="140px"
                label-position="top">
         <el-form-item label="タイトル"  style="margin-left: 30px;margin-top: -35px;">
-          <el-input v-model="queryParams.title"  class="table-input" :maxlength="100" ></el-input>
+          <el-input v-model="queryParams.title"  class="table-input" :maxlength="100"  disabled></el-input>
         </el-form-item>
-        <el-form-item label="説明文" style="margin-left: 30px;margin-top: -15px;">
+        <el-form-item label="説明文" style="margin-left: 30px;margin-top: -15px;" >
           <el-input
               v-model="queryParams.description"
               class="table-input"
               :maxlength="255"
               type="textarea"
               :rows="2"
+              disabled
           ></el-input>
         </el-form-item>
         <div style=" padding-left: 29px;margin-top: -15px;">公開範囲</div>
         <el-form-item label="FC" prop="brandCode" style="margin-left: 60px; display: flex; align-items: center; margin-top: 10px;">
           <div class="el-form-item__label" style="flex-shrink: 0; margin-right: 20px;"></div>
           <el-checkbox-group v-model="queryParams.brandCode">
-            <el-checkbox v-for="dict in yamada_fc_brand" :key="dict.value" :label="dict.value" style="margin-right: 60px;">{{ dict.label }}</el-checkbox>
+            <el-checkbox disabled v-for="dict in yamada_fc_brand" :key="dict.value" :label="dict.value" style="margin-right: 60px;">{{ dict.label }}</el-checkbox>
           </el-checkbox-group>
         </el-form-item>
         <el-form-item label="業種" prop="businessTypeCode" class="el-form-item__businessTypeCode">
           <div class="el-form-item__label" style="flex-shrink: 0; margin-right: 14px;"></div>
           <el-checkbox-group v-model="queryParams.businessTypeCode">
-            <el-checkbox v-for="dict in yamada_business_type" :key="dict.value" :label="dict.value" style="margin-right: 32px;">{{ dict.label }}</el-checkbox>
+            <el-checkbox disabled v-for="dict in yamada_business_type" :key="dict.value" :label="dict.value" style="margin-right: 32px;">{{ dict.label }}</el-checkbox>
           </el-checkbox-group>
         </el-form-item>
         <div class="container">
           <div class="area-header-row">
             <h1 class="area-title">エリア</h1>
-            <RegionTree class="region-tree-container"  :treeData="regionTree" @check-change="handleCheckChange" />
+            <RegionTree class="region-tree-container"  :treeData="regionTree" @check-change="handleCheckChange" disabled />
           </div>
         </div>
         <!-- 公開期間 -->
@@ -47,17 +48,19 @@
                 label="immediate"
                 v-model="queryParams.releaseType"
                 class="vertical-radio"
+                disabled
             >即時公開</el-radio>
             <el-radio
                 label="scheduled"
                 v-model="queryParams.releaseType"
                 class="scheduled-radio"
+                disabled
             >期間指定</el-radio>
             <div class="scheduled-row">
               <!-- 期間指定时显示的日期选择(同行) -->
               <div class="date-group"  >
                 <!-- 日期选择器代码保持不变 -->
-                <el-select v-model="queryParams.startYear" placeholder="" class="date-select"   :disabled="queryParams.releaseType === 'immediate'" @change="formatDate">
+                <el-select v-model="queryParams.startYear" placeholder="" class="date-select"   disabled @change="formatDate">
                   <el-option v-for="year in years" :key="year" :label="year" :value="year"></el-option>
                 </el-select>
                 <span class="date-label">年</span>
@@ -66,7 +69,7 @@
                     placeholder=""
                     class="date-select-small"
                     @change="formatDate"
-                    :disabled="queryParams.releaseType === 'immediate'"
+                    disabled
                 >
                   <el-option
                       v-for="month in months"
@@ -81,7 +84,7 @@
                     placeholder=""
                     class="date-select-small"
                     @change="formatDate"
-                    :disabled="queryParams.releaseType === 'immediate'"
+                    disabled
                 >
                   <el-option
                       v-for="day in days"
@@ -97,7 +100,7 @@
                     placeholder=""
                     class="date-select"
                     @change="formatDate"
-                    :disabled="queryParams.releaseType === 'immediate'"
+                    disabled
                 >
                   <el-option
                       v-for="year in years"
@@ -112,7 +115,7 @@
                     placeholder=""
                     class="date-select-small"
                     @change="formatDate"
-                    :disabled="queryParams.releaseType === 'immediate'"
+                    disabled
                 >
                   <el-option
                       v-for="month in months"
@@ -127,7 +130,7 @@
                     placeholder=""
                     class="date-select-small"
                     @change="formatDate"
-                    :disabled="queryParams.releaseType === 'immediate'"
+                    disabled
                 >
                   <el-option
                       v-for="day in days"
@@ -145,7 +148,7 @@
 
         <div v-for="(question, index) in questions" :key="question.sortOrder" class="question-block">
           <el-form-item style="margin-left: 50px; margin-top: 3px;">
-            <el-button class="append-button" @click="addQuestionAbove(index)">この上に設問を追加</el-button>
+            <el-button disabled class="append-button" @click="addQuestionAbove(index)">この上に設問を追加</el-button>
           </el-form-item>
           <el-form-item style="margin-left: 55px;">
             <template #label>
@@ -154,10 +157,10 @@
                 <span style="color: #666; margin-left: 8px;">: {{ question.sortOrder }}</span>
               </div>
             </template>
-            <el-input v-model="question.questionText" class="small-input" type="textarea" :rows="2" :maxlength="255"></el-input>
+            <el-input disabled  v-model="question.questionText" class="small-input" type="textarea" :rows="2" :maxlength="255"></el-input>
           </el-form-item>
           <el-form-item label="回答型" style="margin-left: 55px;margin-top: -15px">
-            <el-radio-group v-model="question.questionType" class="custom-radio-group" @change="handleQuestionTypeChange(question, $event)">
+            <el-radio-group disabled v-model="question.questionTypeStr" class="custom-radio-group" @change="handleQuestionTypeChange(question, $event)">
               <el-radio label="INPUT_BOX_50">入力ボックス(50文字)</el-radio>
               <el-radio label="INPUT_BOX_100">入力ボックス(100文字)</el-radio>
               <el-radio label="CHECK_BOX">チェックボックス</el-radio>
@@ -167,25 +170,27 @@
           </el-form-item>
           <el-form-item>
             <el-input
-                v-if="question.questionType === 'INPUT_BOX_50'"
+                v-if="question.questionTypeStr === 'INPUT_BOX_50'"
                 v-model="question.input50"
                 :maxlength="50"
                 class="textarea-input"
                 type="textarea"
                 :rows="2"
+                disabled
             ></el-input>
           </el-form-item>
           <el-form-item>
             <el-input
-                v-if="question.questionType === 'INPUT_BOX_100'"
+                v-if="question.questionTypeStr === 'INPUT_BOX_100'"
                 v-model="question.input100"
                 :maxlength="100"
                 class="textarea-input100"
                 type="textarea"
                 :rows="2"
+                disabled
             ></el-input>
           </el-form-item>
-          <el-form-item v-if="question.questionType === 'CHECK_BOX'" style="margin-left: 125px;margin-top: -60px;">
+          <el-form-item v-if="question.questionTypeStr === 'CHECK_BOX'" style="margin-left: 125px;margin-top: -60px;">
             <!-- 循环渲染每一行:复选框 + 输入框 + 削除按钮 -->
             <div
                 v-for="(item, itemIndex) in question.checkboxItems"
@@ -197,24 +202,28 @@
                 <el-checkbox
                     v-model="item.checked"
                     class="checkbox-item"
+                    disabled
                 ></el-checkbox>
                 <el-input
                     v-model="item.optionText"
                     class="input-item"
+                    disabled
                 ></el-input>
                 <el-button
                     type="text"
                     class="delete-btn"
                     @click="deleteCheckboxItem(index, itemIndex)"
+                    disabled
                 >削除</el-button>
               </div>
             </div>
             <el-button
                 class="append-btn"
                 @click="addCheckboxItem(index)"
+                disabled
             >追加</el-button>
           </el-form-item>
-          <el-form-item v-if="question.questionType === 'RADIO_BUTTON'" style="margin-left: 125px;margin-top: -60px;">
+          <el-form-item v-if="question.questionTypeStr === 'RADIO_BUTTON'" style="margin-left: 125px;margin-top: -60px;">
             <!-- 循环渲染每一行:单选按钮 + 输入框 + 削除按钮 -->
             <div
                 v-for="(item, itemIndex) in question.radioItems"
@@ -227,38 +236,42 @@
                     :label="item.value"
                     v-model="question.radioGroupValue"
                     class="hidden-label-radio"
+                    disabled
                 ></el-radio>
                 <el-input
                     v-model="item.optionText"
                     class="radio-item"
+                    disabled
                 ></el-input>
                 <el-button
                     type="text"
                     class="radio-btn"
                     @click="deleteRadioItem(index, itemIndex)"
+                    disabled
                 >削除</el-button>
               </div>
             </div>
             <el-button
                 class="append-btn"
                 @click="addRadioItem(index)"
+                disabled
             >追加</el-button>
           </el-form-item>
-          <el-form-item v-if="question.questionType === 'NUMBER_SELECT'" style="margin-left: 120px;margin-top: -50px">
+          <el-form-item v-if="question.questionTypeStr === 'NUMBER_SELECT'" style="margin-left: 120px;margin-top: -50px">
             <div style="display: flex; flex-direction: column; gap: 10px; width: 100%;">
               <!-- 選択肢部分 -->
               <div style="display: flex; align-items: center;  width: 100%;">
                 <span>選択肢</span>
                 <div style="width: 35px;"></div>
-                <el-input type="number" min="0" max="999" v-model="question.numberSelectStart" class="mx-2"
+                <el-input type="number" disabled min="0" max="999" v-model="question.numberSelectStart" class="mx-2"
                           style="width: 60px;margin-right: 10px;"></el-input>
                 <span>~</span>
-                <el-input type="number" min="0"  max="999" v-model="question.numberSelectEnd" class="mx-2"  style="width: 60px;margin-left: 10px;"></el-input>
+                <el-input disabled type="number" min="0"  max="999" v-model="question.numberSelectEnd" class="mx-2"  style="width: 60px;margin-left: 10px;"></el-input>
               </div>
               <!-- 単位部分 -->
               <div style="display: flex; align-items: center; width: 100%; flex-wrap: nowrap; white-space: nowrap;">
                 <span>単位</span>
-                <el-radio-group v-model="question.unitHas" class="mx-radio-group">
+                <el-radio-group disabled v-model="question.unitHas" class="mx-radio-group">
                   <el-radio :label="false" class="radio-group">なし</el-radio>
                   <el-radio :label="true">あり</el-radio>
                 </el-radio-group>
@@ -272,13 +285,9 @@
             </div>
           </el-form-item>
           <el-form-item style="margin-left: 50px; margin-top: -10px;">
-            <el-button class="append-button" @click="addQuestionBelow(index)">この下に設問を追加</el-button>
+            <el-button class="append-button" disabled @click="addQuestionBelow(index)">この下に設問を追加</el-button>
           </el-form-item>
         </div>
-
-        <el-form-item style="text-align: center;">
-          <el-button @click="Confirm" class="confirm-button">確認</el-button>
-        </el-form-item>
       </el-form>
     </div>
   </div>
@@ -287,7 +296,7 @@
 
 <script name="SurveyDetail" setup>
 
-import { getRegionTree, addSurvey} from "@/api/fcbi/survey.js"
+import { getRegionTree,listSurveyDetail} from "@/api/fcbi/survey.js"
 import { reactive, toRefs, ref, watch, onMounted } from 'vue';
 import RegionTree from '../../../components/RegionTree.vue';
 import { ElMessage } from "element-plus";
@@ -336,8 +345,8 @@ const data = reactive({
   questions: [
     {
       questionText: '',
-      questionType: 'INPUT_BOX_50',
-      oldQuestionType: 'INPUT_BOX_50',
+      questionTypeStr: 'INPUT_BOX_50',
+      oldQuestionTypeStr: 'INPUT_BOX_50',
       input50: '',
       input100: '',
       checkboxItems: [
@@ -429,7 +438,7 @@ const adjustSortOrders = (startIndex) => {
 // 回答类型切换时重置前一类型的状态
 const handleQuestionTypeChange = (question, newType) => {
   // 保存旧类型用于判断需要重置哪些数据
-  const oldType = question.questionType;
+  const oldType = question.questionTypeStr;
 
   // 如果类型未变化,不执行重置
   if (oldType === newType) return;
@@ -469,7 +478,7 @@ const handleQuestionTypeChange = (question, newType) => {
   }
 
   // 更新为新类型(确保数据同步)
-  question.questionType = newType;
+  question.questionTypeStr  = newType;
 };
 
 //ボタンの追加方法
@@ -571,20 +580,14 @@ watch(
 );
 
 watch(
-    () => data.questions.map(q => q.questionType),
+    () => data.questions.map(q => q.questionTypeStr),
     (newTypes, oldTypes) => {
       data.questions.forEach((question, index) => {
         const newType = newTypes[index];
         const oldType = oldTypes[index];
-
-        // 类型未变化则跳过
         if (newType === oldType) return;
-
-        // 执行重置逻辑
         resetOldTypeData(question, oldType);
-
-        // 更新旧类型记录
-        question.oldQuestionType = oldType;
+        question.oldQuestionTypeStr = oldType; // 记录旧类型
       });
     },
     { deep: true }
@@ -593,13 +596,12 @@ watch(
 const resetOldTypeData = (question, oldType) => {
   switch (oldType) {
     case 'INPUT_BOX_50':
-      question.input50 = ''; // 清空输入
+      question.input50 = '';
       break;
     case 'INPUT_BOX_100':
-      question.input100 = ''; // 清空输入
+      question.input100 = '';
       break;
     case 'CHECK_BOX':
-      // 强制重置为3个空选项
       question.checkboxItems = [
         { checked: false, optionText: '', sortOrder: 1 },
         { checked: false, optionText: '', sortOrder: 2 },
@@ -607,7 +609,6 @@ const resetOldTypeData = (question, oldType) => {
       ];
       break;
     case 'RADIO_BUTTON':
-      // 强制重置为3个空选项,清空选中值
       question.radioItems = [
         { value: 'option1', optionText: '', sortOrder: 1 },
         { value: 'option2', optionText: '', sortOrder: 2 },
@@ -616,7 +617,6 @@ const resetOldTypeData = (question, oldType) => {
       question.radioGroupValue = null;
       break;
     case 'NUMBER_SELECT':
-      // 清空所有数字选择器相关数据
       question.numberSelectStart = '';
       question.numberSelectEnd = '';
       question.unitHas = false;
@@ -626,32 +626,250 @@ const resetOldTypeData = (question, oldType) => {
 };
 
 onMounted(async () => {
-  const response = await getRegionTree();
-  if (response?.success) {
-    const regions = response.data.regions || []
+  // 先加载地区数据
+  const regionResponse = await getRegionTree();
+  if (regionResponse?.success) {
+    const regions = regionResponse.data.regions || []
     regionTree.value = regions
     surveyStore.setRegionTree(regions)
     if (regionTree.value.length > 0) {
       updateSelectedRegions(regionTree.value);
     }
   } else {
-    error.value = response?.message || '地域データの取得に失敗しました';
-    console.error('地域データの取得に失敗しました:', response);
+    error.value = regionResponse?.message || '地域データの取得に失敗しました';
+    console.error('地域データの取得に失敗しました:', regionResponse);
+  }
+
+  // 加载问卷详情数据
+  if (surveyId) {
+    try {
+      const requestData = { surveyId };
+      const surveyResponse = await listSurveyDetail(requestData);
+
+      if (surveyResponse.code === 200) {
+        // 从返回结果中获取问卷数据(假设rows是数组,取第一个元素)
+        const surveyData = surveyResponse.rows?.[0] || {};
+
+        // 绑定基本信息(标题、描述、公开范围等)
+        bindSurveyBasicInfo(surveyData);
+
+        // 处理问题数据(后端返回的是JSON字符串)
+        let questionArray = [];
+        if (surveyData.question) {
+          try {
+            // 解析JSON字符串为数组
+            questionArray = JSON.parse(surveyData.question);
+
+            // 验证解析结果是否为数组
+            if (!Array.isArray(questionArray)) {
+              console.warn('question字段解析后不是数组,已初始化为空数组');
+              questionArray = [];
+            }
+          } catch (e) {
+            // 处理JSON解析错误
+            console.error('question字段JSON解析失败:', e);
+            console.error('原始字符串内容:', surveyData.question);
+            ElMessage.error('アンケートの問題データ形式が無効です');
+            questionArray = [];
+          }
+        } else {
+          // 处理question字段为空的情况
+          console.log('question字段为空,初始化为空数组');
+          questionArray = [];
+        }
+
+        // 绑定问题列表
+        bindSurveyQuestions(questionArray);
+
+        // 绑定地区选择
+        bindSelectedRegions(surveyData.region || []);
+
+      } else {
+        // 处理接口返回错误状态
+        ElMessage.error(surveyResponse?.message || 'アンケートデータの取得に失敗しました');
+      }
+    } catch (err) {
+      // 处理接口调用异常
+      console.error('アンケートデータの取得中にエラーが発生しました:', err);
+      ElMessage.error('アンケートデータの取得中にエラーが発生しました');
+    }
   }
 });
 
+const bindSurveyBasicInfo = (surveyData) => {
+  // 标题和描述
+  queryParams.value.title = surveyData.title || '';
+  queryParams.value.description = surveyData.description || '';
+
+  // 公开范围 - FC
+  if (surveyData.brandCode) {
+    queryParams.value.brandCode = typeof surveyData.brandCode === 'string'
+        ? JSON.parse(surveyData.brandCode)
+        : (surveyData.brandCode || []);
+  } else {
+    queryParams.value.brandCode = [];
+  }
+
+  // 公开范围 - 業種
+  if (surveyData.businessTypeCode) {
+    queryParams.value.businessTypeCode = typeof surveyData.businessTypeCode === 'string'
+        ? JSON.parse(surveyData.businessTypeCode)
+        : (surveyData.businessTypeCode || []);
+  } else {
+    queryParams.value.businessTypeCode = [];
+  }
+
+  // 公开期间
+  if (surveyData.publicMode === 'INSTANT') {
+    queryParams.value.releaseType = 'immediate';
+  } else if (surveyData.publicMode === 'PERIOD') {
+    queryParams.value.releaseType = 'scheduled';
+    // 解析开始日期
+    if (surveyData.publicStartTime) {
+      const startDate = new Date(surveyData.publicStartTime);
+      queryParams.value.startYear = startDate.getFullYear();
+      queryParams.value.startMonth = startDate.getMonth() + 1;
+      queryParams.value.startDay = startDate.getDate();
+    }
+    // 解析结束日期
+    if (surveyData.publicEndTime) {
+      const endDate = new Date(surveyData.publicEndTime);
+      queryParams.value.endYear = endDate.getFullYear();
+      queryParams.value.endMonth = endDate.getMonth() + 1;
+      queryParams.value.endDay = endDate.getDate();
+    }
+    formatDate();
+  }
+};
+
+const bindSurveyQuestions = (questionsData) => {
+  if (!questionsData.length) return;
+
+  // 清空现有问题
+  data.questions = [];
+
+  // 绑定每个问题
+  questionsData.forEach((q, index) => {
+    const question = {
+      questionText: q.questionText || '',
+      questionTypeStr: q.questionTypeStr || 'INPUT_BOX_50',
+      oldQuestionTypeStr: q.questionTypeStr || 'INPUT_BOX_50',
+      input50: '',
+      input100: '',
+      checkboxItems: [],
+      radioItems: [],
+      radioGroupValue: null,
+      numberSelectStart: '',
+      numberSelectEnd: '',
+      unitHas: false,
+      sortOrder: index + 1,
+      questionUnit: ''
+    };
+
+    // 根据问题类型绑定不同的内容
+    switch (question.questionTypeStr) {
+      case 'INPUT_BOX_50':
+        question.input50 = q.input50 || '';
+        break;
+      case 'INPUT_BOX_100':
+        question.input100 = q.input100 || '';
+        break;
+      case 'CHECK_BOX':
+        question.checkboxItems = q.checkboxItems || [
+          { checked: false, optionText: '', sortOrder: 1 },
+          { checked: false, optionText: '', sortOrder: 2 },
+          { checked: false, optionText: '', sortOrder: 3 },
+        ];
+        break;
+      case 'RADIO_BUTTON':
+        question.radioItems = q.radioItems || [
+          { value: 'option1', optionText: '', sortOrder: 1 },
+          { value: 'option2', optionText: '', sortOrder: 2 },
+          { value: 'option3', optionText: '', sortOrder: 3 },
+        ];
+        question.radioGroupValue = q.radioGroupValue || null;
+        break;
+      case 'NUMBER_SELECT':
+        question.numberSelectStart = q.numberSelectStart || '';
+        question.numberSelectEnd = q.numberSelectEnd || '';
+        question.unitHas = q.unitHas || false;
+        question.questionUnit = q.questionUnit || '';
+        break;
+    }
+
+    data.questions.push(question);
+  });
+};
+
+const bindSelectedRegions = (region) => {
+
+  const regionData = typeof region === 'string' ? JSON.parse(region) : region;
+
+  selectedRegions.value = [...regionData];
+  queryParams.value.regions = [...regionData];
+
+  regionData.forEach(region => {
+    checkRegionNode(regionTree.value, region.regionCode);
+  });
+};
+
+const checkRegionNode = (nodes, regionCode, parentNode = null) => {
+  for (const node of nodes) {
+    if (node.regionCode === regionCode) {
+      node.checked = true;
+      // 子节点选中后,更新其父节点状态
+      updateParentNodeStatus(parentNode);
+      return true;
+    }
+    if (node.children && node.children.length > 0) {
+      // 递归查找子节点时,将当前节点作为父节点传入
+      const found = checkRegionNode(node.children, regionCode, node);
+      if (found) return true;
+    }
+  }
+  return false;
+};
+
+const updateParentNodeStatus = (parentNode) => {
+  if (!parentNode) return; // 没有父节点则终止
+
+  const children = parentNode.children || [];
+  // 统计子节点中选中的数量
+  const checkedCount = children.filter(child => child.checked).length;
+
+  if (checkedCount === 0) {
+    // 没有子节点选中:父节点不选中,也不是半选
+    parentNode.checked = false;
+    parentNode.indeterminate = false;
+  } else if (checkedCount === children.length) {
+    // 所有子节点都选中:父节点选中,不是半选
+    parentNode.checked = true;
+    parentNode.indeterminate = false;
+  } else {
+    // 部分子节点选中:父节点不选中,但为半选
+    parentNode.checked = false;
+    parentNode.indeterminate = true;
+  }
+
+  // 继续向上更新父节点的父节点(递归)
+  updateParentNodeStatus(parentNode.parent);
+};
+
+
+
+
 // 選択した状態変更の処理
 const handleCheckChange = (regionId, isChecked) => {
   const region = findRegionById(regionTree.value, regionId);
   if (region) {
     if (isChecked) {
-      if (!selectedRegions.value.some(r => r.region_code === region.region_code)) {
+      if (!selectedRegions.value.some(r => r.regionCode === region.regionCode)) {
         selectedRegions.value.push({
-          region_code: region.region_code
+          regionCode: region.regionCode  // 字段名修改
         });
       }
     } else {
-      selectedRegions.value = selectedRegions.value.filter(r => r.region_code !== region.region_code);
+      selectedRegions.value = selectedRegions.value.filter(r => r.regionCode !== region.regionCode);
     }
     queryParams.value.regions = selectedRegions.value;
   }
@@ -683,7 +901,6 @@ const updateSelectedRegions = (nodes) => {
 // 選択したすべてのサブエリアオブジェクトを再帰的に収集する(親ノードをスキップ)
 const collectSelectedRegions = (nodes, isParent = false) => {
   nodes.forEach(node => {
-    // 親ノード(上位ノード)の場合は、収集をスキップして再帰的な子ノードを続行します
     if (isParent) {
       if (node.children && node.children.length > 0) {
         collectSelectedRegions(node.children, false);
@@ -692,7 +909,7 @@ const collectSelectedRegions = (nodes, isParent = false) => {
     }
     if (node.checked) {
       selectedRegions.value.push({
-        region_code: node.region_code
+        regionCode: node.regionCode
       });
     }
     if (node.children && node.children.length > 0) {
@@ -700,157 +917,6 @@ const collectSelectedRegions = (nodes, isParent = false) => {
     }
   });
 };
-
-// 確認按钮点击处理函数
-const Confirm = async () => {
-  if (!queryParams.value.title) {
-    ElMessage.error('タイトルを入力してください');
-    return;
-  }
-  if (queryParams.value.releaseType === 'scheduled') {
-    if (!queryParams.value.startYear || !queryParams.value.startMonth || !queryParams.value.startDay ||
-        !queryParams.value.endYear || !queryParams.value.endMonth || !queryParams.value.endDay) {
-      ElMessage.error('期間指定の場合は全ての日付を入力してください');
-      return;
-    }
-  }
-  if (regionTree.value.length > 0) {
-    updateSelectedRegions(regionTree.value);
-  }
-  formatDate();
-  if (queryParams.value.releaseType === 'scheduled') {
-    // 确保日期格式正确(YYYY-MM-DD)
-    const startDate = new Date(queryParams.publicStartTime);
-    const endDate = new Date(queryParams.publicEndTime);
-
-    // 检查日期是否有效且开始时间大于结束时间
-    if (!isNaN(startDate.getTime()) && !isNaN(endDate.getTime()) && startDate > endDate) {
-      ElMessage.error('公開開始日時は公開終了日時より後に設定できません');
-      return; // 中断提交
-    }
-  }
-
-  let hasError = false;
-  const questionsData = data.questions.map(question => {
-    if (!question.questionText || question.questionText.trim() === '') {
-      ElMessage.warning(`設問文${question.sortOrder}の設問文を入力してください`);
-      hasError = true;
-      return null;
-    }
-    const questionData = {
-      questionText: question.questionText,
-      questionType: question.questionType,
-      input50: question.input50,
-      input100: question.input100,
-      numberSelectStart: question.numberSelectStart,
-      numberSelectEnd: question.numberSelectEnd,
-      questionUnit: question.questionUnit,
-      unitHas: question.unitHas,
-      sortOrder: question.sortOrder
-    };
-
-    // CHECKBOXタイプの問題を処理するオプション
-    if (question.questionType === 'CHECK_BOX') {
-      questionData.checkboxItems = question.checkboxItems.map((item, itemIndex) => {
-        // 新增:校验optionText是否为空
-        if (!item.optionText || item.optionText.trim() === '') {
-          ElMessage.warning(`設問文${question.sortOrder}の選択肢${itemIndex + 1}を入力してください`);
-          hasError = true;
-        }
-        return {
-          optionText: item.optionText,
-          sortOrder: item.sortOrder
-        };
-      });
-    }
-
-    // RADIOタイプの問題を処理するオプション
-    if (question.questionType === 'RADIO_BUTTON') {
-      questionData.radioItems = question.radioItems.map((item, itemIndex) => {
-        // 新增:校验optionText是否为空
-        if (!item.optionText || item.optionText.trim() === '') {
-          ElMessage.warning(`設問文${question.sortOrder}の選択肢${itemIndex + 1}を入力してください`);
-          hasError = true;
-        }
-        return {
-          optionText: item.optionText,
-          sortOrder: item.sortOrder
-        };
-      });
-    }
-
-    // SELECTタイプの問題:動的生成オプション
-    if (question.questionType === 'NUMBER_SELECT') {
-      // 先判断start或end是否为空(包括空字符串、纯空格)
-      const isStartEmpty = !question.numberSelectStart || question.numberSelectStart.trim() === '';
-      const isEndEmpty = !question.numberSelectEnd || question.numberSelectEnd.trim() === '';
-
-      if (isStartEmpty) {
-        ElMessage.warning(`設問文${question.sortOrder}の選択肢1を入力してください`);
-        hasError = true;
-      }
-
-      if (isEndEmpty) {
-        ElMessage.warning(`設問文${question.sortOrder}の選択肢2を入力してください`);
-        hasError = true;
-      }
-
-      if (isStartEmpty || isEndEmpty) {
-        return null;
-      }
-
-
-      const start = parseInt(question.numberSelectStart);
-      const end = parseInt(question.numberSelectEnd);
-
-      if (!isNaN(start) && !isNaN(end) && start <= end) {
-        // startからendへのオプションの動的生成
-        questionData.selectOptions = Array.from({ length: end - start + 1 }, (_, i) => ({
-          optionText: (start + i).toString(),
-          sortOrder: i + 1
-        }));
-      } else {
-        ElMessage.warning(`SELECTタイプ問題の範囲が無効です:${start}~${end}`);
-        hasError = true; // 标记有错误
-        return null; // 临时返回null
-      }
-      // 新增:単位「あり」时的输入框空值校验
-      if (question.unitHas && (!question.questionUnit || question.questionUnit.trim() === '')) {
-        ElMessage.warning(`設問文${question.sortOrder}の単位を入力してください`);
-        hasError = true;
-        return null;
-      }
-    }
-
-    return questionData;
-  });
-  if (hasError) {
-    return;
-  }
-  const validQuestionsData = questionsData.filter(q => q !== null);
-  const params = {
-    title: queryParams.value.title,
-    description: queryParams.value.description,
-    publicStartTime: queryParams.publicStartTime,
-    publicEndTime: queryParams.publicEndTime,
-    publicMode: queryParams.publicMode,
-    brandCodes: queryParams.value.brandCode,
-    businessTypeCodes: queryParams.value.businessTypeCode,
-    numberSelectStart: queryParams.value.numberSelectStart,
-    numberSelectEnd: queryParams.value.numberSelectEnd,
-    questions: validQuestionsData,
-    regions: queryParams.value.regions
-  };
-  addSurvey(params).then((res) => {
-    if (res.success) {
-      surveyStore.updateFormData({
-        queryParams: data.queryParams,
-        questions: data.questions
-      });
-      router.push({ name: 'SurveyDecision' });
-    }
-  });
-};
 </script>
 
 

+ 13 - 0
src/views/fcbi/wares/detail.vue

@@ -0,0 +1,13 @@
+<template>
+  <div class="app-container">
+
+  </div>
+</template>
+
+<script setup name="WaresDetail">
+
+</script>
+
+<style scoped>
+
+</style>

+ 268 - 0
src/views/fcbi/wares/index.vue

@@ -0,0 +1,268 @@
+<template>
+  <div class="app-container">
+    <!-- 分类筛选区域 -->
+    <div class="filter-section">
+      <p class="filter-title">カテゴリ絞り込み</p>
+      <div class="category-group" v-for="(group, groupIndex) in filterGroups" :key="groupIndex">
+        <el-checkbox-group v-model="checkedFilters" class="parent-category">
+          <el-checkbox :value="group.parent.value">
+            {{ group.parent.label }}
+          </el-checkbox>
+        </el-checkbox-group>
+
+        <el-checkbox-group v-model="checkedFilters" class="child-wrapper">
+          <div class="child-row" v-for="row in Math.ceil(group.children.length / 2)" :key="row">
+            <el-checkbox
+                v-for="(child, i) in group.children.slice((row-1)*2, row*2)"
+                :key="i"
+                :value="child.value"
+                class="child-item"
+            >
+              {{ child.label }}
+            </el-checkbox>
+          </div>
+
+        </el-checkbox-group>
+      </div>
+      <el-button class="search-btn" type="primary" @click="handleSearch">検索</el-button>
+    </div>
+
+    <!-- 商品列表区域 -->
+    <div class="goods-list">
+      <el-card
+          v-for="(item, index) in waresList"
+          :key="index"
+          class="goods-card"
+          shadow="hover"
+          @click="handleGoodsClick"
+      >
+        <div class="goods-info">
+          <el-image
+              :src="imageUrl"
+              class="goods-img"
+              fit="contain"
+              :alt="item.desc"
+          >
+          </el-image>
+          <div class="right-content">
+            <div class="desc">{{ item.desc }}</div>
+            <div class="price-container">
+              <span class="price-value">¥{{ item.price }}</span>
+              <span class="tax-text">(税抜)</span>
+            </div>
+          </div>
+        </div>
+      </el-card>
+    </div>
+
+    <!-- 分页区域 -->
+    <div class="pagination">
+      <button :disabled="currentPage === 1" @click="currentPage--">
+        &lt;
+      </button>
+      <span>{{ currentPage }} / {{ totalPage }}</span>
+      <button :disabled="currentPage === totalPage" @click="currentPage++">
+        &gt;
+      </button>
+    </div>
+  </div>
+</template>
+
+<script setup name="WaresList">
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+// 组件实例与状态管理
+const router = useRouter();
+// 基础数据与状态定义
+const imageUrl = new URL('@/assets/images/img.png', import.meta.url).href;
+
+const filterGroups = ref([
+  {
+    parent: { label: '家電', value: 'homeAppliance' },
+    children: [
+      { label: 'エアコン', value: 'airConditioner' },
+      { label: '冷蔵庫', value: 'refrigerator' },
+      { label: '洗濯機', value: 'washingMachine' },
+      { label: 'テレビ', value: 'tv' },
+      { label: '掃除機', value: 'vacuumCleaner' },
+    ]
+  },
+  {
+    parent: { label: '業種', value: 'industry' },
+    children: [
+      { label: '食品', value: 'food' },
+      { label: '衣料', value: 'clothing' },
+      { label: '電気', value: 'electricity' },
+      { label: '建設', value: 'construction' },
+      { label: '医療', value: 'medical' },
+    ]
+  }
+]);
+const checkedFilters = ref([]);
+
+// 商品列表和分页数据
+const waresList = ref([
+  {
+    desc: 'パナソニック エアコン 6畳 ナノイー搭載 スタンダードエアコン DRシリーズ CS-225DR 2025年モデル',
+    price: '32,800'
+  },
+  {
+    desc: '三菱電機 冷蔵庫 300L ノーフロスト 銀イオン除菌 右開き MR-B300',
+    price: '58,900'
+  },
+  {
+    desc: '東芝 洗濯機 7kg 全自動 風乾機能搭載 AW-D7000',
+    price: '45,600'
+  }
+]);
+const currentPage = ref(1);
+const totalPage = ref(50);
+
+const handleSearch = () => {
+};
+
+const handleGoodsClick = () => {
+  router.push({ name: 'waresDetail' });
+};
+</script>
+
+<style scoped>
+/* 筛选区域样式 */
+.filter-section {
+  margin-bottom: 20px;
+  padding: 15px;
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
+}
+.filter-title {
+  margin: 0 0 15px 0;
+  font-weight: bold;
+  color: #303133;
+}
+.category-group {
+  margin-bottom: 20px;
+}
+
+/* 父项样式 */
+.parent-category {
+  margin-bottom: 10px;
+  font-weight: bold;
+  padding-left: 20px;
+}
+
+/* 子项布局(改为网格布局,确保两列对齐) */
+.child-wrapper {
+  padding-left: 20px;
+}
+.child-row {
+  display: grid; /* 使用网格布局 */
+  grid-template-columns: repeat(2, 1fr); /* 平均分配两列宽度 */
+  gap: 10px 0; /* 行间距10px,列间距0 */
+}
+.child-item {
+  /* 移除flex相关样式,添加固定内边距确保对齐 */
+  padding: 5px 0;
+  min-width: 0;
+}
+
+.search-btn {
+  color: #fff;
+  border: none;
+  width: 350px;
+  margin-left: 320px;
+}
+@media (max-width: 1280px) {
+  .search-btn {
+    width: 600px;
+    margin-left: 25px;
+  }
+}
+@media (max-width: 1024px) {
+  .search-btn {
+    width: 400px;
+    margin-left: 50px;
+  }
+}
+@media (max-width: 767px) {
+  .search-btn {
+    width: 260px;
+    margin-left: 20px;
+  }
+}
+
+@media (max-width: 320px) {
+  .search-btn {
+    width: 200px;
+  }
+}
+
+/* 商品列表样式 */
+.goods-list {
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+}
+.goods-card {
+  border: 1px solid #e4e7ed;
+}
+.goods-info {
+  display: flex;
+  align-items: flex-start;
+  padding: 10px 0;
+  gap: 15px;
+}
+.right-content {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.goods-img {
+  width: 100%;
+  height: auto;
+  max-width: 80px;
+  max-height: 80px;
+}
+.desc {
+  flex: 1;
+  line-height: 1.6;
+  color: #606266;
+  word-wrap: break-word;
+  white-space: normal;
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.pagination button {
+  background-color: #fff;
+  border: 1px solid #ccc;
+  padding: 5px 10px;
+  cursor: pointer;
+  margin: 0 5px;
+}
+.pagination button:disabled {
+  cursor: not-allowed;
+  background-color: #f5f5f5;
+  color: #999;
+}
+.price-container {
+  display: flex;
+  align-items: center;
+}
+
+.price-value {
+  color: #338dcd;
+  font-weight: bold;
+  font-size: 14px;
+}
+
+.tax-text {
+  color: #303133;
+  font-size: 14px;
+}
+</style>