恢复修改的数据

This commit is contained in:
wangzzpeng
2026-09-28 10:47:49 +08:00
parent f1e64ef864
commit 43c2dc0d8d
57 changed files with 4557 additions and 1642 deletions

View File

@@ -1,131 +1,143 @@
<script setup lang="ts">
// 需求提报(单页三段卡片 + 底部固定操作条,数据全部走真实接口)
// 页面 → store → api;页面不直接 import api
import { onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import { useRouter } from 'vue-router'
import { AppButton, StepForm } from '@/components'
import { useDemandStore } from '@/stores/modules/demand'
import { useUserStore } from '@/stores/modules/user'
import type { BusinessType } from '@/types/api'
import type { Demand } from '@/types/business/demand'
import DemandStep1Business from './cpns/DemandStep1Business.vue'
import DemandStep2Info from './cpns/DemandStep2Info.vue'
import DemandStep3Confirm from './cpns/DemandStep3Confirm.vue'
import type { Demand, DemandAttachment } from '@/types/business/demand'
import DemandActionBar from './cpns/DemandActionBar.vue'
import DemandBizTypes from './cpns/DemandBizTypes.vue'
import DemandConfirmForm from './cpns/DemandConfirmForm.vue'
import DemandInfoForm from './cpns/DemandInfoForm.vue'
const STEP_TITLES = ['选择业务类型', '填写需求信息', '确认信息并补充备注']
const router = useRouter()
const demandStore = useDemandStore()
const userStore = useUserStore()
const { form, step, loading } = storeToRefs(demandStore)
const {
form,
bizTypeOptions,
budgetOptions,
loading,
saving,
submitting,
uploading,
} = storeToRefs(demandStore)
function onSelectBusiness(type: BusinessType): void {
demandStore.patchForm({ businessType: type })
function onBizType(value: string): void {
demandStore.patchForm({ bizType: value })
}
function onUpdateDemand(partial: Partial<Demand>): void {
function onUpdate(partial: Partial<Demand>): void {
demandStore.patchForm(partial)
}
function onUpload(file: File): void {
demandStore.addAttachment(file)
void demandStore.addAttachment(file)
}
function onRemoveFile(file: Demand['attachments'][number]): void {
function onRemoveFile(file: DemandAttachment): void {
demandStore.removeAttachment(file)
}
function goPrev(): void {
if (step.value > 1) demandStore.setStep(step.value - 1)
}
function goNext(): void {
if (step.value < 3) demandStore.setStep(step.value + 1)
}
async function onSubmit(): Promise<void> {
const ok = await demandStore.submit()
if (ok && userStore.isLoggedIn) {
void router.push('/project')
}
}
function onSaveDraft(): void {
void demandStore.saveDraft()
}
function onReset(): void {
demandStore.reset()
void demandStore.reset()
}
async function onSubmit(): Promise<void> {
await demandStore.submit()
}
onMounted(() => {
void demandStore.loadDraft()
void demandStore.init()
})
</script>
<template>
<div class="demand">
<header class="demand__head">
<h1 class="demand__title">
需求提报
</h1>
<p class="demand__subtitle text-secondary">
填写您的需求信息,专业顾问将快速与您联系
</p>
</header>
<div class="demand-page">
<div class="container demand" :class="{ 'is-loading': loading }">
<header class="demand__head">
<h1 class="demand__title">
需求提报
</h1>
<p class="demand__subtitle">
填写您的需求信息,专业顾问将快速与您联系
</p>
</header>
<StepForm :titles="STEP_TITLES" :current="step - 1">
<DemandStep1Business
v-if="step === 1"
:demand="form"
@select="onSelectBusiness"
/>
<DemandStep2Info
v-else-if="step === 2"
:demand="form"
@update:demand="onUpdateDemand"
@upload="onUpload"
@remove-file="onRemoveFile"
/>
<DemandStep3Confirm
v-else
:demand="form"
@update:demand="onUpdateDemand"
/>
</StepForm>
<!-- ① 选择业务类型 -->
<section class="demand__card">
<h2 class="demand__section">
<span class="demand__index">1</span>
选择业务类型<span class="demand__required">*</span>
</h2>
<DemandBizTypes
:options="bizTypeOptions"
:model-value="form.bizType"
@update:model-value="onBizType"
/>
</section>
<div class="demand__nav">
<AppButton :disabled="step === 1 || loading" @click="goPrev">
上一步
</AppButton>
<AppButton v-if="step < 3" type="primary" :disabled="loading" @click="goNext">
下一步
</AppButton>
<!-- ② 填写需求信息 -->
<section class="demand__card">
<h2 class="demand__section">
<span class="demand__index">2</span>
填写需求信息<span class="demand__required">*</span>
</h2>
<DemandInfoForm
:demand="form"
:budget-options="budgetOptions"
:uploading="uploading"
@update="onUpdate"
@upload="onUpload"
@remove-file="onRemoveFile"
/>
</section>
<!-- ③ 确认信息并补充备注 -->
<section class="demand__card">
<h2 class="demand__section">
<span class="demand__index">3</span>
确认信息并补充备注
</h2>
<DemandConfirmForm
:demand="form"
@update="onUpdate"
/>
</section>
</div>
<div class="demand__actions">
<AppButton type="primary" size="lg" :loading="loading" @click="onSubmit">
立即提报
</AppButton>
<AppButton size="lg" :disabled="loading" @click="onSaveDraft">
保存草稿
</AppButton>
<AppButton size="lg" :disabled="loading" @click="onReset">
重置
</AppButton>
</div>
<DemandActionBar
:saving="saving"
:submitting="submitting"
@save-draft="onSaveDraft"
@reset="onReset"
@submit="onSubmit"
/>
</div>
</template>
<style lang="less" scoped>
.demand {
.flex(column, flex-start);
gap: @spacing-base;
padding-top: @spacing-xl;
padding-bottom: @spacing-xxl;
.demand-page {
padding-top: @spacing-lg;
// 固定底条 72px + 呼吸间距,避免遮住 ③ 卡片
padding-bottom: 104px;
&.is-loading {
.demand {
opacity: 0.6;
pointer-events: none;
}
}
}
.demand {
// 设计稿:页头下与首块间距 ≈ 20px
&__head {
.flex(column, flex-start);
.flex(column, flex-start, stretch);
gap: @spacing-xs;
margin-bottom: @spacing-base;
}
&__title {
@@ -136,16 +148,44 @@ onMounted(() => {
&__subtitle {
font-size: @font-size-base;
color: @text-color-secondary;
}
&__nav {
.flex(row, space-between);
width: 100%;
&__card {
padding: @spacing-lg;
border-radius: @radius-base;
background: @white;
// 设计稿块间距 18px
& + & {
margin-top: 18px;
}
}
&__actions {
.flex(row, center);
gap: @spacing-base;
&__section {
.flex(row, flex-start, center);
gap: @spacing-sm;
margin-bottom: @spacing-base;
font-size: @font-size-lg;
font-weight: 600;
color: @heading-color;
}
/** 区块序号:实心蓝圆 + 白色数字 */
&__index {
.flex(row, center, center);
width: 18px;
height: 18px;
border-radius: 50%;
background: @primary-color;
font-size: @font-size-sm;
font-weight: 600;
color: @white;
}
&__required {
margin-left: 2px;
color: @danger-color;
}
}
</style>