PLAN_SCHEME_GUIDE.md 12.5 KB

录入计划书方案开发规范

版本: v1.0 更新日期: 2026-01-31 用途: 指导新增计划书方案(SchemeC、SchemeD 等)的开发

目录


组件结构规范

基础结构

所有方案组件必须遵循以下三层结构:

<template>
  <div class="flex flex-col h-full bg-gray-50">
    <!-- 1. 顶部标题栏 -->
    <div class="flex justify-between items-center px-5 py-5 bg-white rounded-t-xl">
      <span class="text-lg font-normal text-gray-900">{{ title }}</span>
      <IconFont name="close" size="16" color="#9CA3AF" @click="close" />
    </div>

    <!-- 2. 滚动内容区 -->
    <div class="flex-1 overflow-y-auto p-4">
      <div class="bg-white rounded-xl p-5 shadow-sm">
        <!-- 表单字段 -->
      </div>
    </div>

    <!-- 3. 底部按钮区 -->
    <div class="p-4 pt-2 pb-8 flex justify-between gap-4 bg-gray-50">
      <div class="flex-1 py-3 text-center border border-blue-600 text-blue-600 rounded-lg text-base bg-white"
        @click="close">
        取消
      </div>
      <div class="flex-1 py-3 text-center bg-blue-600 text-white rounded-lg text-base" @click="submit">
        提交申请
      </div>
    </div>
  </div>
</template>

Props 定义

const props = defineProps({
  title: {
    type: String,
    default: '申请计划书'
  }
});

Emits 定义

const emit = defineEmits(['close', 'submit']);

表单字段规范

1. 标准文本输入框

适用场景: 客户姓名、年龄、金额等

<div class="text-sm text-gray-600 mb-2">字段标签</div>
<div class="border border-gray-200 rounded-lg mb-4 overflow-hidden">
  <nut-input
    v-model="form.fieldName"
    type="text"
    placeholder="请输入..."
    class="!p-0 !bg-transparent !text-sm !text-gray-900"
    :border="false"
  />
</div>

关键样式:

  • 容器: border border-gray-200 rounded-lg mb-4 overflow-hidden
  • 输入框: !p-0 !bg-transparent !text-sm !text-gray-900
  • 数字类型: 使用 type="digit"

2. 带单位的输入框

适用场景: 年收入区间、期望收益率、年交保费等

<div class="text-sm text-gray-600 mb-2">字段标签</div>
<div class="border border-gray-200 rounded-lg mb-4 flex items-center overflow-hidden">
  <nut-input
    v-model="form.fieldName"
    type="digit"
    placeholder="请输入..."
    class="!p-0 !bg-transparent flex-1 !text-sm !text-gray-900"
    :border="false"
  />
  <span class="text-sm text-gray-500 shrink-0 ml-2 mr-5">单位</span>
</div>

关键点:

  • 输入框: flex-1 (占据剩余空间)
  • 单位文字: shrink-0 ml-2 (防止被挤压)
  • 可选: mr-5 (右侧留白,可选)

3. 下拉选择框

适用场景: 行业选择等需要 Picker 的场景

<div class="text-sm text-gray-600 mb-2">字段标签</div>
<div
  class="flex justify-between items-center border border-gray-200 rounded-lg p-3 mb-4 overflow-hidden"
  @click="showPicker = true"
>
  <span :class="form.fieldName ? 'text-gray-900' : 'text-gray-400'" class="text-sm">
    {{ form.fieldName || '请选择...' }}
  </span>
  <IconFont name="right" size="14" color="#9CA3AF" />
</div>

<!-- Picker Popup -->
<nut-popup position="bottom" v-model:visible="showPicker">
  <nut-picker
    :columns="pickerColumns"
    title="选择标题"
    @confirm="confirmPicker"
    @cancel="showPicker = false"
  />
</nut-popup>

关键点:

  • 容器保留 p-3 内边距(因为有可点击内容)
  • 右侧箭头图标: IconFont name="right"
  • 占位文字颜色: text-gray-400
  • 已选文字颜色: text-gray-900

4. 单选字段

适用场景: 性别、交费期间等

<div class="text-sm text-gray-600 mb-2">字段标签</div>
<nut-radio-group v-model="form.fieldName" direction="horizontal" class="mb-4">
  <nut-radio
    v-for="option in options"
    :key="option.value"
    :label="option.value"
    class="mr-8"
  >
    {{ option.label }}
  </nut-radio>
</nut-radio-group>

关键点:

  • direction="horizontal" - 水平排列
  • class="mb-4" - 底部间距
  • class="mr-8" - 选项间距(两个选项)
  • class="mr-6" - 选项间距(三个及以上选项)

5. 多选字段

适用场景: 家庭结构、保险需求等

<div class="text-sm text-gray-600 mb-3">字段标签(多选)</div>
<div class="flex flex-wrap gap-3 mb-5">
  <div
    v-for="option in options"
    :key="option.value"
    class="px-4 py-2 rounded-lg text-sm cursor-pointer transition-colors border"
    :class="form.fieldName.includes(option.value) ? 'bg-blue-600 text-white border-blue-600' : 'bg-gray-50 text-gray-600 border-gray-200'"
    @click="toggleSelection('fieldName', option.value)"
  >
    {{ option.label }}
  </div>
</div>

关键点:

  • 标签使用 mb-3,容器使用 mb-5
  • flex flex-wrap gap-3 - 自动换行
  • cursor-pointer transition-colors - 交互效果
  • 选中状态: bg-blue-600 text-white border-blue-600
  • 未选中状态: bg-gray-50 text-gray-600 border-gray-200

多选切换逻辑:

const toggleSelection = (field, value) => {
  const index = form[field].indexOf(value);
  if (index === -1) {
    form[field].push(value);  // 添加选中
  } else {
    form[field].splice(index, 1);  // 取消选中
  }
};

6. 只读展示字段

适用场景: 币种、计划、保险期间等固定值展示

<div class="flex justify-between items-start mb-5">
  <span class="text-sm text-gray-600 mt-1.5">字段标签</span>
  <div class="bg-blue-50 rounded-md px-3 py-1.5">
    <span class="text-sm text-blue-600">显示值</span>
  </div>
</div>

关键点:

  • flex justify-between items-start - 标签和内容两端对齐
  • 标签: text-sm text-gray-600 mt-1.5 (顶部对齐)
  • 内容: bg-blue-50 rounded-md px-3 py-1.5
  • 文字: text-sm text-blue-600

样式规范

颜色系统

用途 颜色值 Tailwind 类
主色 #2563EB blue-600
标签文字 #4B5563 gray-600
输入文字 #111827 gray-900
占位文字 #9CA3AF gray-400
边框 #E5E7EB gray-200
背景 #F9FAFB gray-50
图标 #9CA3AF gray-400

间距系统

位置 间距 Tailwind 类
标签与输入框 8px mb-2
输入框底部 16px mb-4
多选按钮底部 20px mb-5
单选选项间距 32px mr-8
多选按钮间距 12px gap-3
顶部标题栏 20px px-5 py-5
内容卡片 20px p-5

圆角系统

元素 圆角 Tailwind 类
卡片 12px rounded-xl
输入框/按钮 8px rounded-lg
标签 6px rounded-md

文字大小

用途 大小 Tailwind 类
标题 18px text-lg
正文 14px text-sm
按钮 16px text-base

交互规范

全局样式覆盖

所有方案组件必须包含以下样式:

<style lang="less" scoped>
/* Override NutUI input styles to match design */
:deep(.nut-input) {
  padding: 0;
  background: transparent;
  border-radius: inherit;
}
</style>

图标使用

关闭图标:

<IconFont name="close" size="16" color="#9CA3AF" @click="close" />

右侧箭头:

<IconFont name="right" size="14" color="#9CA3AF" />

提示图标:

<IconFont name="tips" size="14" color="#9CA3AF" />

数据结构

Reactive 表单对象

const form = reactive({
  // 文本字段
  textField: '',

  // 数字字段
  numberField: '',

  // 单选字段
  radioField: 'defaultValue',

  // 多选字段
  multiSelectField: [],

  // 带单位字段
  amountField: ''
});

选项数据结构

单选选项:

const options = [
  { label: '显示文本', value: 'value1' },
  { label: '显示文本', value: 'value2' }
];

多选选项:

const options = [
  { label: '显示文本', value: 'value1' },
  { label: '显示文本', value: 'value2' }
];

Picker 数据:

const pickerColumns = [
  { text: '显示文本', value: 'value1' },
  { text: '显示文本', value: 'value2' }
];

代码模板

完整组件模板

<template>
  <div class="flex flex-col h-full bg-gray-50">
    <!-- Header -->
    <div class="flex justify-between items-center px-5 py-5 bg-white rounded-t-xl">
      <span class="text-lg font-normal text-gray-900">{{ title }}</span>
      <IconFont name="close" size="16" color="#9CA3AF" @click="close" />
    </div>

    <!-- Content -->
    <div class="flex-1 overflow-y-auto p-4">
      <div class="bg-white rounded-xl p-5 shadow-sm">
        <!-- 表单字段区域 -->
      </div>
    </div>

    <!-- Footer -->
    <div class="p-4 pt-2 pb-8 flex justify-between gap-4 bg-gray-50">
      <div
        class="flex-1 py-3 text-center border border-blue-600 text-blue-600 rounded-lg text-base bg-white"
        @click="close"
      >
        取消
      </div>
      <div
        class="flex-1 py-3 text-center bg-blue-600 text-white rounded-lg text-base"
        @click="submit"
      >
        提交申请
      </div>
    </div>
  </div>
</template>

<script setup>
/**
 * @description 录入计划书 - 方案X 内容组件
 * @emits close - 关闭弹窗事件
 * @emits submit - 提交事件,携带表单数据
 */
import { reactive } from 'vue';

const props = defineProps({
  title: {
    type: String,
    default: '申请计划书'
  }
});

const emit = defineEmits(['close', 'submit']);

const form = reactive({
  // 定义表单字段
  fieldName: ''
});

const close = () => {
  emit('close');
};

const submit = () => {
  console.log('Submit form:', form);
  emit('submit', form);
};
</script>

<style lang="less" scoped>
/* Override NutUI input styles to match design */
:deep(.nut-input) {
  padding: 0;
  background: transparent;
  border-radius: inherit;
}
</style>

检查清单

开发前检查

  • 阅读本文档
  • 确认字段类型(输入/单选/多选/下拉)
  • 准备选项数据
  • 确认是否有 Picker 弹窗

代码规范检查

  • 使用 <script setup> 语法
  • Props/Emits 定义完整
  • 表单对象使用 reactive
  • 多选逻辑使用 toggleSelection 函数
  • 包含 JSDoc 注释

样式检查

  • 所有输入框容器有 overflow-hidden
  • 输入框使用 !p-0 !bg-transparent
  • 圆角使用 rounded-lg
  • 边框颜色使用 border-gray-200
  • 带单位输入框使用 flex-1shrink-0

组件检查

  • 关闭按钮使用 IconFont
  • 单选使用 nut-radio-group
  • 多选使用自定义按钮样式
  • Picker 使用 nut-popup + nut-picker

测试检查

  • 输入框文字不贴边(有适当间距)
  • 圆角显示正常
  • 单选只能选中一个
  • 多选可以选中多个
  • Picker 弹窗正常弹出和选择
  • 提交按钮触发 emit 事件

常见问题

Q: 输入框圆角被截掉?

A: 确保容器添加了 overflow-hidden,并且样式覆盖中有 border-radius: inherit

Q: 带单位的输入框,单位文字被挤压?

A: 确保:

  • 输入框有 flex-1
  • 单位文字有 shrink-0
  • 可选:添加右侧留白 mr-5

Q: 多选按钮样式不一致?

A: 复制标准模板,检查:

  • 未选中状态:bg-gray-50 text-gray-600 border-gray-200
  • 选中状态:bg-blue-600 text-white border-blue-600
  • 必须包含:cursor-pointer transition-colors

Q: Picker 弹窗不显示?

A: 检查:

  • v-model:visible 绑定正确
  • Picker 数据格式正确:{ text: '', value: '' }
  • 确认事件处理正确

Q: 单选/多选数据格式?

A:

  • 单选:字符串 form.field = 'value'
  • 多选:数组 form.field = ['value1', 'value2']

版本历史

版本 日期 更新内容 作者
v1.0 2026-01-31 初始版本,基于 SchemeA 和 SchemeB 总结 Claude Code

相关文件