ow
This commit is contained in:
1 parent
dcc112c076
commit
b858386e86
15 files changed
+3634
-69
No files matched your search
@@ -0,0 +1,240 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 快速新增家族成员(底部抽屉):旧 WebVue components/master/FamilyPersonQuickCreateModal.vue 的移动端等价物
|
||||
*
|
||||
* 族谱关系维护里「新增配偶 / 新增孩子 / 新增祖先」都调它:只填 姓* / 名(谱名)* / 性别*,
|
||||
* 落库走 FamilyPersonService.Insert(TreeId 由调用方带入),成功后 emit("created", person),
|
||||
* created 取 result?.FamilyPerson || payload.FamilyPerson,由页面按用途回填到对应关系列表。
|
||||
* 性别用 option-picker 单选(数据来自 GenderPolicy 语言包),与成员详情页同口径。
|
||||
*/
|
||||
import type { FamilyPersonDisplayData } from "@/data/auto/familyPersonDisplayData";
|
||||
import { useLocale } from "uview-pro";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { usePolicyOptions } from "@/composables/usePolicyOptions";
|
||||
import { FamilyPersonData } from "@/data/auto/familyPersonData";
|
||||
import { FamilyPersonDisplayData as FamilyPersonDisplayDataCls } from "@/data/auto/familyPersonDisplayData";
|
||||
import familyPersonService from "@/service/master/familyPersonService";
|
||||
|
||||
const props = defineProps({
|
||||
visible: { type: Boolean, default: false },
|
||||
treeId: { type: String, default: "" },
|
||||
title: { type: String, default: "" },
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "update:visible", value: boolean): void;
|
||||
(e: "created", person: FamilyPersonDisplayData): void;
|
||||
}>();
|
||||
|
||||
const { t } = useLocale();
|
||||
const { getPolicyOptions, getPolicyText } = usePolicyOptions();
|
||||
|
||||
const genderItems = computed(() => getPolicyOptions("GenderPolicy"));
|
||||
|
||||
const surname = ref("");
|
||||
const genealogyName = ref("");
|
||||
const gender = ref("");
|
||||
const saving = ref(false);
|
||||
const genderPickerVisible = ref(false);
|
||||
|
||||
const genderLabel = computed(() => getPolicyText("GenderPolicy", gender.value));
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(on) => {
|
||||
if (on) {
|
||||
surname.value = "";
|
||||
genealogyName.value = "";
|
||||
gender.value = "";
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
function close(): void {
|
||||
emit("update:visible", false);
|
||||
}
|
||||
|
||||
function onGenderConfirm(key: string): void {
|
||||
gender.value = key;
|
||||
genderPickerVisible.value = false;
|
||||
}
|
||||
|
||||
async function onConfirm(): Promise<void> {
|
||||
if (!surname.value.trim()) {
|
||||
uni.showToast({ title: t("FamilyPersonPage.surnameRequired"), icon: "none" });
|
||||
return;
|
||||
}
|
||||
if (!genealogyName.value.trim()) {
|
||||
uni.showToast({ title: t("FamilyPersonPage.genealogyNameRequired"), icon: "none" });
|
||||
return;
|
||||
}
|
||||
if (!gender.value) {
|
||||
uni.showToast({ title: t("FamilyPersonPage.genderRequired"), icon: "none" });
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = new FamilyPersonData();
|
||||
payload.FamilyPerson = new FamilyPersonDisplayDataCls();
|
||||
payload.FamilyPerson.Surname = surname.value.trim();
|
||||
payload.FamilyPerson.GenealogyName = genealogyName.value.trim();
|
||||
payload.FamilyPerson.Gender = gender.value;
|
||||
payload.FamilyPerson.TreeId = props.treeId || "";
|
||||
|
||||
try {
|
||||
saving.value = true;
|
||||
const result = await familyPersonService.Insert(payload);
|
||||
const created = result?.FamilyPerson || payload.FamilyPerson;
|
||||
emit("created", created);
|
||||
close();
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
uni.showToast({ title: t("FamilyPersonPage.quickCreateFailed"), icon: "none" });
|
||||
}
|
||||
finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<u-popup :model-value="props.visible" mode="bottom" round="24" :close-on-click-overlay="!saving" @close="close">
|
||||
<view class="pqc">
|
||||
<text class="pqc__title">
|
||||
{{ props.title || t('FamilyPersonPage.quickCreateTitle') }}
|
||||
</text>
|
||||
|
||||
<view class="pqc__field">
|
||||
<text class="pqc__label">
|
||||
{{ t("FamilyPersonPage.surname") }}<text class="pqc__required">*</text>
|
||||
</text>
|
||||
<u-input v-model="surname" :border="true" :maxlength="100"
|
||||
:placeholder="t('FamilyPersonPage.surnamePlaceholder')" />
|
||||
</view>
|
||||
|
||||
<view class="pqc__field">
|
||||
<text class="pqc__label">
|
||||
{{ t("FamilyPersonPage.genealogyName") }}<text class="pqc__required">*</text>
|
||||
</text>
|
||||
<u-input v-model="genealogyName" :border="true" :maxlength="100"
|
||||
:placeholder="t('FamilyPersonPage.genealogyNamePlaceholder')" />
|
||||
</view>
|
||||
|
||||
<view class="pqc__field">
|
||||
<text class="pqc__label">
|
||||
{{ t("FamilyPersonPage.gender") }}<text class="pqc__required">*</text>
|
||||
</text>
|
||||
<view class="pqc__picker" @tap="genderPickerVisible = true">
|
||||
<text :class="{ 'pqc__picker-empty': !genderLabel }">
|
||||
{{ genderLabel || t('FamilyPersonPage.genderPlaceholder') }}
|
||||
</text>
|
||||
<u-icon name="arrow-right" size="26" color="#c4c8cf" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="pqc__footer">
|
||||
<view class="pqc__btn" @tap="close">
|
||||
<text class="pqc__btn-text">
|
||||
{{ t("AdminPage.cancelBut") }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="pqc__btn pqc__btn--primary" :class="{ 'pqc__btn--muted': saving }" @tap="onConfirm">
|
||||
<text class="pqc__btn-text pqc__btn-text--primary">
|
||||
{{ saving ? t("AdminPage.savingTip") : t("AdminPage.confirmBut") }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pqc__safe" />
|
||||
</view>
|
||||
|
||||
<option-picker :visible="genderPickerVisible" :title="t('FamilyPersonPage.gender')" :items="genderItems"
|
||||
:empty-text="t('FamilyPersonPage.genderEmpty')" @close="genderPickerVisible = false"
|
||||
@confirm="onGenderConfirm" />
|
||||
</u-popup>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pqc {
|
||||
padding: 40rpx 32rpx 0;
|
||||
background-color: #ffffff;
|
||||
|
||||
&__title {
|
||||
display: block;
|
||||
padding-bottom: 24rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #1f2329;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__field {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
&__label {
|
||||
display: block;
|
||||
margin-bottom: 12rpx;
|
||||
font-size: 26rpx;
|
||||
color: #646a73;
|
||||
}
|
||||
|
||||
&__required {
|
||||
margin-left: 2rpx;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
&__picker {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 76rpx;
|
||||
padding: 0 24rpx;
|
||||
font-size: 28rpx;
|
||||
color: #1f2329;
|
||||
border: 1px solid #e5e6eb;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
&__picker-empty {
|
||||
color: #8f959e;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
&__btn {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 76rpx;
|
||||
border-radius: 999rpx;
|
||||
background-color: #f5f6f8;
|
||||
|
||||
&--primary {
|
||||
background-color: #2b8fff;
|
||||
}
|
||||
|
||||
&--muted {
|
||||
background-color: #b9d6ff;
|
||||
}
|
||||
}
|
||||
|
||||
&__btn-text {
|
||||
font-size: 28rpx;
|
||||
color: #5c626b;
|
||||
|
||||
&--primary {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
&__safe {
|
||||
height: calc(32rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user