1261 lines
41 KiB
Vue
1261 lines
41 KiB
Vue
<template>
|
|
<view class="page">
|
|
<scroll-view scroll-y class="page-scroll">
|
|
<common-hero title="团员档案管理" :use-image-bg="true"></common-hero>
|
|
|
|
<view class="section-card">
|
|
<view class="section-head">
|
|
<view class="section-title">基础信息表单</view>
|
|
</view>
|
|
|
|
<view class="field-list">
|
|
<view v-for="field in fields" :key="field.key" class="field-item">
|
|
<view class="field-label">
|
|
{{ field.label }}
|
|
<text v-if="field.required" class="field-required">*</text>
|
|
</view>
|
|
|
|
<view
|
|
v-if="field.key === 'gender'"
|
|
class="field-picker"
|
|
@tap="openGenderPicker(field)"
|
|
>
|
|
<text :class="getFieldDisplayValue(field) ? 'field-value' : 'field-placeholder'">
|
|
{{ getFieldDisplayValue(field) || field.placeholder }}
|
|
</text>
|
|
</view>
|
|
|
|
<picker
|
|
v-else-if="field.key === 'nation'"
|
|
mode="selector"
|
|
:range="nationLabels"
|
|
:value="nationIndex"
|
|
:disabled="!nationOptions.length"
|
|
@change="handleNationChange"
|
|
>
|
|
<view class="field-picker" :class="{ 'field-picker--disabled': !nationOptions.length }">
|
|
<text :class="getFieldDisplayValue(field) ? 'field-value' : 'field-placeholder'">
|
|
{{ getFieldDisplayValue(field) || (nationOptions.length ? field.placeholder : '民族加载中') }}
|
|
</text>
|
|
</view>
|
|
</picker>
|
|
|
|
<view
|
|
v-else-if="field.key === 'politics'"
|
|
class="field-picker"
|
|
@tap="openPoliticsPicker()"
|
|
>
|
|
<text :class="getFieldDisplayValue(field) ? 'field-value' : 'field-placeholder'">
|
|
{{ getFieldDisplayValue(field) || field.placeholder }}
|
|
</text>
|
|
</view>
|
|
|
|
<view
|
|
v-else-if="field.key === 'leaguePosition'"
|
|
class="field-picker"
|
|
@tap="openLeaguePositionPicker(field)"
|
|
>
|
|
<text :class="getFieldDisplayValue(field) ? 'field-value' : 'field-placeholder'">
|
|
{{ getFieldDisplayValue(field) || field.placeholder }}
|
|
</text>
|
|
</view>
|
|
|
|
<view
|
|
v-else-if="field.key === 'collegeId'"
|
|
class="field-picker"
|
|
@tap="openCollegePicker()"
|
|
>
|
|
<text :class="getFieldDisplayValue(field) ? 'field-value' : 'field-placeholder'">
|
|
{{ getFieldDisplayValue(field) || field.placeholder }}
|
|
</text>
|
|
</view>
|
|
|
|
<view
|
|
v-else-if="field.key === 'classId'"
|
|
class="field-picker"
|
|
@tap="openClassPicker()"
|
|
>
|
|
<text :class="getFieldDisplayValue(field) ? 'field-value' : 'field-placeholder'">
|
|
{{ getFieldDisplayValue(field) || field.placeholder }}
|
|
</text>
|
|
</view>
|
|
|
|
<view
|
|
v-else-if="field.key === 'branchOrganizationId'"
|
|
class="field-picker"
|
|
@tap="openOrganizationPicker()"
|
|
>
|
|
<text :class="getFieldDisplayValue(field) ? 'field-value' : 'field-placeholder'">
|
|
{{ getFieldDisplayValue(field) || field.placeholder }}
|
|
</text>
|
|
</view>
|
|
|
|
<view
|
|
v-else-if="field.key === 'archiveInCurrentOrg'"
|
|
class="field-picker"
|
|
@tap="openArchiveInOrgPicker(field)"
|
|
>
|
|
<text :class="getFieldDisplayValue(field) ? 'field-value' : 'field-placeholder'">
|
|
{{ getFieldDisplayValue(field) || field.placeholder }}
|
|
</text>
|
|
</view>
|
|
|
|
<view
|
|
v-else-if="field.key === 'joinMonth'"
|
|
class="field-picker"
|
|
@tap="openJoinMonthPicker(field)"
|
|
>
|
|
<text :class="getFieldDisplayValue(field) ? 'field-value' : 'field-placeholder'">
|
|
{{ getFieldDisplayValue(field) || field.placeholder }}
|
|
</text>
|
|
</view>
|
|
|
|
<picker
|
|
v-else-if="field.type === 'select'"
|
|
mode="selector"
|
|
:range="field.options"
|
|
:value="getSelectIndex(field)"
|
|
@change="handleSelectChange(field, $event)"
|
|
>
|
|
<view class="field-picker">
|
|
<text :class="getFieldDisplayValue(field) ? 'field-value' : 'field-placeholder'">
|
|
{{ getFieldDisplayValue(field) || field.placeholder }}
|
|
</text>
|
|
</view>
|
|
</picker>
|
|
|
|
<view v-else-if="field.type === 'readonly' || field.key === 'phone'"
|
|
class="field-picker field-picker--readonly">
|
|
<text :class="getFieldDisplayValue(field) ? 'field-value' : 'field-placeholder'">
|
|
{{ getFieldDisplayValue(field) || field.placeholder }}
|
|
</text>
|
|
</view>
|
|
|
|
<uv-input
|
|
v-else
|
|
class="field-native-input"
|
|
:type="field.type === 'phone' ? 'number' : 'text'"
|
|
:value="formData[field.key]"
|
|
:placeholder="field.placeholder"
|
|
placeholder-style="color: #c0c4cc;"
|
|
:maxlength="-1"
|
|
border="none"
|
|
@input="handleTextInput(field, $event)"
|
|
/>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="action-card">
|
|
<button class="ghost-btn" @click="saveDraft">保存草稿</button>
|
|
<button class="primary-btn" @click="submitForm">提交档案</button>
|
|
</view>
|
|
</scroll-view>
|
|
|
|
<view v-if="searchPickerVisible" class="option-mask" @tap="closeSearchPicker">
|
|
<view class="option-popup" @tap.stop>
|
|
<view class="option-popup-head">
|
|
<view class="option-popup-btn" @tap="closeSearchPicker">取消</view>
|
|
<view class="option-popup-title">{{ searchPickerTitle }}</view>
|
|
<view class="option-popup-btn option-popup-btn--primary" @tap="confirmSearchPicker">确定</view>
|
|
</view>
|
|
|
|
<uv-input
|
|
:value="searchPickerKeyword"
|
|
class="option-search"
|
|
:placeholder="`搜索${searchPickerTitle}`"
|
|
border="none"
|
|
@input="handleSearchPickerInput"
|
|
/>
|
|
|
|
<view v-if="filteredSearchPickerOptions.length" class="option-picker-wrap">
|
|
<picker-view class="option-picker-view" :value="[searchPickerIndex]" @change="handleSearchPickerChange">
|
|
<picker-view-column>
|
|
<view v-for="item in filteredSearchPickerOptions" :key="`${searchPickerMode}-${item.value}`"
|
|
class="option-picker-item">
|
|
{{ item.label }}
|
|
</view>
|
|
</picker-view-column>
|
|
</picker-view>
|
|
</view>
|
|
<view v-else class="option-empty">没有匹配的选项</view>
|
|
</view>
|
|
</view>
|
|
|
|
<uv-picker
|
|
ref="genderPicker"
|
|
title="选择性别"
|
|
:columns="genderPickerColumns"
|
|
:defaultIndex="[genderPickerIndex]"
|
|
keyName="text"
|
|
@close="closeGenderPicker"
|
|
@cancel="closeGenderPicker"
|
|
@confirm="confirmGenderPicker"
|
|
></uv-picker>
|
|
|
|
<uv-picker
|
|
ref="leaguePositionPicker"
|
|
title="选择团内职务"
|
|
:columns="leaguePositionPickerColumns"
|
|
:defaultIndex="[leaguePositionPickerIndex]"
|
|
keyName="text"
|
|
@close="closeLeaguePositionPicker"
|
|
@cancel="closeLeaguePositionPicker"
|
|
@confirm="confirmLeaguePositionPicker"
|
|
></uv-picker>
|
|
|
|
<uv-picker
|
|
ref="organizationPicker"
|
|
title="选择所属团支部"
|
|
:columns="organizationPickerColumns"
|
|
:defaultIndex="organizationPickerIndexs"
|
|
keyName="text"
|
|
@change="handleOrganizationPickerChange"
|
|
@close="closeOrganizationPicker"
|
|
@cancel="closeOrganizationPicker"
|
|
@confirm="confirmOrganizationPicker"
|
|
></uv-picker>
|
|
|
|
<uv-picker
|
|
ref="archiveInOrgPicker"
|
|
title="选择团籍是否在本组织"
|
|
:columns="archiveInOrgPickerColumns"
|
|
:defaultIndex="[archiveInOrgPickerIndex]"
|
|
keyName="text"
|
|
@close="closeArchiveInOrgPicker"
|
|
@cancel="closeArchiveInOrgPicker"
|
|
@confirm="confirmArchiveInOrgPicker"
|
|
></uv-picker>
|
|
|
|
<uv-picker
|
|
ref="joinMonthPicker"
|
|
title="选择入团年月"
|
|
:columns="joinMonthPickerColumns"
|
|
:defaultIndex="joinMonthPickerIndexs"
|
|
keyName="text"
|
|
@change="handleJoinMonthPickerChange"
|
|
@close="closeJoinMonthPicker"
|
|
@cancel="closeJoinMonthPicker"
|
|
@confirm="confirmJoinMonthPicker"
|
|
></uv-picker>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import CommonHero from '../../components/common-hero/common-hero.vue'
|
|
import {
|
|
getCurrentTyglForm,
|
|
getCurrentUser,
|
|
getUserProfile,
|
|
listClasses,
|
|
listColleges,
|
|
listDictData,
|
|
listOrganizations,
|
|
saveTyglForm,
|
|
updateTyglForm
|
|
} from './service'
|
|
|
|
const STORAGE_KEY = 'tygl_member_archive_draft'
|
|
const POLITICS_DICT_ID = 172
|
|
const NATION_DICT_ID = 173
|
|
const LEAGUE_POSITION_DICT_ID = 174
|
|
|
|
const FALLBACK_NATION_OPTIONS = [
|
|
'汉族', '蒙古族', '回族', '藏族', '维吾尔族', '苗族', '彝族', '壮族', '布依族', '朝鲜族',
|
|
'满族', '侗族', '瑶族', '白族', '土家族', '哈尼族', '哈萨克族', '傣族', '黎族', '傈僳族',
|
|
'佤族', '畲族', '高山族', '拉祜族', '水族', '东乡族', '纳西族', '景颇族', '柯尔克孜族', '土族',
|
|
'达斡尔族', '仫佬族', '羌族', '布朗族', '撒拉族', '毛南族', '仡佬族', '锡伯族', '阿昌族', '普米族',
|
|
'塔吉克族', '怒族', '乌孜别克族', '俄罗斯族', '鄂温克族', '德昂族', '保安族', '裕固族', '京族', '塔塔尔族',
|
|
'独龙族', '鄂伦春族', '赫哲族', '门巴族', '珞巴族', '基诺族'
|
|
]
|
|
const FALLBACK_POLITICS_OPTIONS = ['中共党员', '中共预备党员', '共青团员', '群众', '民盟盟员', '民建会员', '其他']
|
|
const FALLBACK_LEAGUE_POSITION_OPTIONS = [
|
|
'普通团员',
|
|
'团支部书记',
|
|
'团支部副书记',
|
|
'组织委员',
|
|
'宣传委员',
|
|
'纪检委员',
|
|
'学习委员',
|
|
'文体委员',
|
|
'班级团支书',
|
|
'院级团学干部',
|
|
'校级团学干部',
|
|
'其他'
|
|
]
|
|
|
|
const fields = [
|
|
{key: 'name', label: '姓名', required: true, type: 'text', placeholder: '请输入姓名'},
|
|
{key: 'gender', label: '性别', type: 'select', placeholder: '请选择性别'},
|
|
{key: 'nation', label: '民族', type: 'search-select', placeholder: '请选择民族'},
|
|
{key: 'politics', label: '政治面貌', required: true, type: 'search-select', placeholder: '请选择政治面貌'},
|
|
{
|
|
key: 'collegeId',
|
|
label: '学院',
|
|
required: true,
|
|
type: 'college',
|
|
placeholder: '请选择学院',
|
|
displayKey: 'collegeName'
|
|
},
|
|
{key: 'classId', label: '班级', required: true, type: 'class', placeholder: '请选择班级', displayKey: 'className'},
|
|
{key: 'phone', label: '手机号码', type: 'readonly', placeholder: '自动读取当前用户手机号'},
|
|
{key: 'leaguePosition', label: '团内职务', type: 'text', placeholder: '请选择团内职务'},
|
|
{
|
|
key: 'branchOrganizationId',
|
|
label: '所属团支部',
|
|
type: 'organization',
|
|
placeholder: '请选择所属团支部',
|
|
displayKey: 'branchOrganizationName'
|
|
},
|
|
{key: 'idCardNo', label: '身份证号', required: true, type: 'text', placeholder: '请输入身份证号'},
|
|
{key: 'birthDate', label: '出生日期', type: 'readonly', placeholder: '将根据身份证号自动读取'},
|
|
{key: 'archiveInCurrentOrg', label: '团籍是否在本组织', type: 'select', options: ['是', '否'], placeholder: '请选择'},
|
|
{key: 'joinMonth', label: '入团年月', type: 'month', placeholder: '请选择入团年月'}
|
|
]
|
|
|
|
const createDefaultFormData = () => ({
|
|
name: '',
|
|
gender: '',
|
|
nation: '',
|
|
politics: '',
|
|
collegeId: '',
|
|
collegeName: '',
|
|
college: '',
|
|
classId: '',
|
|
className: '',
|
|
phone: '',
|
|
leaguePosition: '',
|
|
branchOrganizationId: '',
|
|
branchOrganizationName: '',
|
|
idCardNo: '',
|
|
birthDate: '',
|
|
archiveInCurrentOrg: '',
|
|
joinMonth: ''
|
|
})
|
|
|
|
const normalizeOptions = (list) =>
|
|
(list || []).map((item) => ({
|
|
label: item.label || item,
|
|
value: item.value || item
|
|
}))
|
|
|
|
export default {
|
|
components: {
|
|
CommonHero
|
|
},
|
|
data() {
|
|
return {
|
|
fields,
|
|
formId: null,
|
|
formData: createDefaultFormData(),
|
|
draftSavedAt: '',
|
|
nationOptions: normalizeOptions(FALLBACK_NATION_OPTIONS),
|
|
politicsOptions: normalizeOptions(FALLBACK_POLITICS_OPTIONS),
|
|
leaguePositionOptions: normalizeOptions(FALLBACK_LEAGUE_POSITION_OPTIONS),
|
|
collegeOptions: [],
|
|
classOptions: [],
|
|
organizationTree: [],
|
|
organizationOptions: [],
|
|
organizationPickerColumns: [],
|
|
organizationPickerIndexs: [],
|
|
archiveInOrgFieldKey: 'archiveInCurrentOrg',
|
|
archiveInOrgPickerColumns: [[
|
|
{text: '是', value: '是'},
|
|
{text: '否', value: '否'}
|
|
]],
|
|
joinMonthFieldKey: 'joinMonth',
|
|
joinMonthPickerColumns: [],
|
|
joinMonthPickerIndexs: [],
|
|
searchPickerVisible: false,
|
|
searchPickerTitle: '',
|
|
searchPickerMode: '',
|
|
searchPickerKeyword: '',
|
|
searchPickerOptions: [],
|
|
searchPickerIndex: 0,
|
|
searchPickerTempOption: null,
|
|
genderFieldKey: 'gender',
|
|
genderPickerColumns: [[
|
|
{text: '男', value: '男'},
|
|
{text: '女', value: '女'}
|
|
]],
|
|
leaguePositionFieldKey: 'leaguePosition',
|
|
leaguePositionPickerColumns: [normalizeOptions(FALLBACK_LEAGUE_POSITION_OPTIONS).map((item) => ({
|
|
text: item.label,
|
|
value: item.value
|
|
}))]
|
|
}
|
|
},
|
|
computed: {
|
|
nationLabels() {
|
|
return this.nationOptions.map((item) => item.label)
|
|
},
|
|
nationIndex() {
|
|
const index = this.nationOptions.findIndex((item) => item.value === this.formData.nation)
|
|
return index > -1 ? index : 0
|
|
},
|
|
filteredSearchPickerOptions() {
|
|
const keyword = String(this.searchPickerKeyword || '').trim().toLowerCase()
|
|
if (!keyword) {
|
|
return this.searchPickerOptions
|
|
}
|
|
return this.searchPickerOptions.filter((item) => String(item.label || '').toLowerCase().indexOf(keyword) > -1)
|
|
},
|
|
genderPickerIndex() {
|
|
const options = (this.genderPickerColumns[0] || []).map((item) => item.value)
|
|
const index = options.indexOf(this.formData[this.genderFieldKey])
|
|
return index > -1 ? index : 0
|
|
},
|
|
leaguePositionPickerIndex() {
|
|
const options = (this.leaguePositionPickerColumns[0] || []).map((item) => item.value)
|
|
const index = options.indexOf(this.formData[this.leaguePositionFieldKey])
|
|
return index > -1 ? index : 0
|
|
},
|
|
archiveInOrgPickerIndex() {
|
|
const options = (this.archiveInOrgPickerColumns[0] || []).map((item) => item.value)
|
|
const index = options.indexOf(this.formData[this.archiveInOrgFieldKey])
|
|
return index > -1 ? index : 0
|
|
}
|
|
},
|
|
watch: {
|
|
'formData.idCardNo'() {
|
|
this.syncBirthDateFromIdCard()
|
|
}
|
|
},
|
|
onLoad() {
|
|
this.restoreDraft()
|
|
this.fillCurrentUserPhone()
|
|
this.loadFormOptions()
|
|
this.loadCurrentTyglForm()
|
|
this.syncBirthDateFromIdCard()
|
|
const joinMonthPickerState = this.buildJoinMonthPickerState(this.formData.joinMonth)
|
|
this.joinMonthPickerColumns = joinMonthPickerState.columns
|
|
this.joinMonthPickerIndexs = joinMonthPickerState.indexs
|
|
},
|
|
methods: {
|
|
async loadCurrentTyglForm() {
|
|
try {
|
|
const result = await getCurrentTyglForm()
|
|
if (!result || !result.id) {
|
|
return
|
|
}
|
|
this.formId = result.id
|
|
this.formData = {
|
|
...this.formData,
|
|
...result,
|
|
collegeName: result.collegeName || result.college || this.formData.collegeName,
|
|
college: result.college || result.collegeName || this.formData.college,
|
|
className: result.className || this.formData.className
|
|
}
|
|
this.syncBirthDateFromIdCard()
|
|
const joinMonthPickerState = this.buildJoinMonthPickerState(this.formData.joinMonth)
|
|
this.joinMonthPickerColumns = joinMonthPickerState.columns
|
|
this.joinMonthPickerIndexs = joinMonthPickerState.indexs
|
|
if (this.formData.collegeId) {
|
|
await this.loadClassOptions(this.formData.collegeId)
|
|
}
|
|
} catch (error) {
|
|
}
|
|
},
|
|
buildSubmitPayload() {
|
|
return {
|
|
...(this.formId ? {id: this.formId} : {}),
|
|
name: this.formData.name,
|
|
gender: this.formData.gender,
|
|
nation: this.formData.nation,
|
|
college: this.formData.collegeName || this.formData.college,
|
|
className: this.formData.className,
|
|
politics: this.formData.politics,
|
|
phone: this.formData.phone,
|
|
leaguePosition: this.formData.leaguePosition,
|
|
branchOrganizationId: this.formData.branchOrganizationId || null,
|
|
branchOrganizationName: this.formData.branchOrganizationName,
|
|
idCardNo: this.formData.idCardNo,
|
|
birthDate: this.formData.birthDate,
|
|
archiveInCurrentOrg: this.formData.archiveInCurrentOrg,
|
|
joinMonth: this.formData.joinMonth
|
|
}
|
|
},
|
|
buildJoinMonthPickerState(currentValue) {
|
|
const currentDate = new Date()
|
|
const currentYear = currentDate.getFullYear()
|
|
const years = []
|
|
for (let year = 2000; year <= currentYear + 1; year += 1) {
|
|
years.push({
|
|
text: `${year}年`,
|
|
value: String(year)
|
|
})
|
|
}
|
|
const months = []
|
|
for (let month = 1; month <= 12; month += 1) {
|
|
months.push({
|
|
text: `${String(month).padStart(2, '0')}月`,
|
|
value: String(month).padStart(2, '0')
|
|
})
|
|
}
|
|
let yearIndex = years.length - 1
|
|
let monthIndex = 0
|
|
const normalizedValue = String(currentValue || '').trim()
|
|
if (/^\d{4}-\d{2}$/.test(normalizedValue)) {
|
|
const [yearValue, monthValue] = normalizedValue.split('-')
|
|
const nextYearIndex = years.findIndex((item) => item.value === yearValue)
|
|
const nextMonthIndex = months.findIndex((item) => item.value === monthValue)
|
|
yearIndex = nextYearIndex > -1 ? nextYearIndex : yearIndex
|
|
monthIndex = nextMonthIndex > -1 ? nextMonthIndex : monthIndex
|
|
}
|
|
return {
|
|
columns: [years, months],
|
|
indexs: [yearIndex, monthIndex]
|
|
}
|
|
},
|
|
async fillCurrentUserPhone() {
|
|
const tokenUser = getCurrentUser()
|
|
if (tokenUser && tokenUser.phone) {
|
|
this.formData.phone = tokenUser.phone
|
|
}
|
|
try {
|
|
const profile = await getUserProfile()
|
|
if (profile && profile.phone) {
|
|
this.formData.phone = profile.phone
|
|
}
|
|
} catch (error) {
|
|
}
|
|
},
|
|
showToast(title) {
|
|
uni.showToast({
|
|
title,
|
|
icon: 'none'
|
|
})
|
|
},
|
|
getFieldDisplayValue(field) {
|
|
if (field.displayKey) {
|
|
return this.formData[field.displayKey]
|
|
}
|
|
return this.formData[field.key]
|
|
},
|
|
async loadFormOptions() {
|
|
try {
|
|
const [politicsList, nationList, leaguePositionList, organizationList, collegeList] = await Promise.all([
|
|
listDictData({dictId: POLITICS_DICT_ID}).catch(() => []),
|
|
listDictData({dictId: NATION_DICT_ID}).catch(() => []),
|
|
listDictData({dictId: LEAGUE_POSITION_DICT_ID}).catch(() => []),
|
|
listOrganizations().catch(() => []),
|
|
listColleges().catch(() => [])
|
|
])
|
|
|
|
if (Array.isArray(politicsList) && politicsList.length) {
|
|
this.politicsOptions = normalizeOptions(
|
|
politicsList
|
|
.filter((item) => item && item.dictDataName)
|
|
.map((item) => ({label: item.dictDataName, value: item.dictDataName}))
|
|
)
|
|
}
|
|
if (Array.isArray(nationList) && nationList.length) {
|
|
this.nationOptions = normalizeOptions(
|
|
nationList
|
|
.filter((item) => item && item.dictDataName)
|
|
.map((item) => ({label: item.dictDataName, value: item.dictDataName}))
|
|
)
|
|
}
|
|
if (Array.isArray(leaguePositionList) && leaguePositionList.length) {
|
|
this.leaguePositionOptions = normalizeOptions(
|
|
leaguePositionList
|
|
.filter((item) => item && item.dictDataName)
|
|
.map((item) => ({label: item.dictDataName, value: item.dictDataName}))
|
|
)
|
|
this.leaguePositionPickerColumns = [this.leaguePositionOptions.map((item) => ({
|
|
text: item.label,
|
|
value: item.value
|
|
}))]
|
|
}
|
|
if (Array.isArray(organizationList) && organizationList.length) {
|
|
this.organizationTree = this.normalizeOrganizationTree(organizationList)
|
|
this.organizationOptions = this.flattenOrganizations(organizationList)
|
|
const organizationPickerState = this.buildOrganizationPickerState(
|
|
this.findOrganizationPathByValue(this.organizationTree, this.formData.branchOrganizationId) || []
|
|
)
|
|
this.organizationPickerColumns = organizationPickerState.columns
|
|
this.organizationPickerIndexs = organizationPickerState.indexs
|
|
}
|
|
if (Array.isArray(collegeList) && collegeList.length) {
|
|
this.collegeOptions = this.normalizeCollegeOptions(collegeList)
|
|
if (this.formData.collegeId) {
|
|
await this.loadClassOptions(this.formData.collegeId)
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.warn('tygl options load failed', error)
|
|
}
|
|
},
|
|
normalizeCollegeOptions(list) {
|
|
return (Array.isArray(list) ? list : [])
|
|
.map((item) => ({
|
|
label: item.collegeName || item.name || item.label || '',
|
|
value: Number(item.collegeId || item.id || item.value || 0) || String(item.collegeId || item.id || item.value || ''),
|
|
rawLabel: item.collegeName || item.name || item.label || ''
|
|
}))
|
|
.filter((item) => item.label && item.value !== '')
|
|
},
|
|
normalizeClassOptions(list) {
|
|
return (Array.isArray(list) ? list : [])
|
|
.map((item) => ({
|
|
label: item.className || item.name || item.label || '',
|
|
value: Number(item.classId || item.id || item.value || 0) || String(item.classId || item.id || item.value || ''),
|
|
rawLabel: item.className || item.name || item.label || ''
|
|
}))
|
|
.filter((item) => item.label && item.value !== '')
|
|
},
|
|
normalizeOrganizationTree(list) {
|
|
return (Array.isArray(list) ? list : []).map((item) => ({
|
|
text: item.organizationName || item.name || item.label || '',
|
|
value: Number(item.organizationId || item.id || item.value || 0) || String(item.organizationId || item.id || item.value || ''),
|
|
rawLabel: item.organizationName || item.name || item.label || '',
|
|
children: this.normalizeOrganizationTree(item.children || [])
|
|
})).filter((item) => item.text && item.value !== '')
|
|
},
|
|
async loadClassOptions(collegeId) {
|
|
if (!collegeId) {
|
|
this.classOptions = []
|
|
return
|
|
}
|
|
try {
|
|
const classList = await listClasses({collegeId})
|
|
this.classOptions = this.normalizeClassOptions(classList)
|
|
} catch (error) {
|
|
this.classOptions = []
|
|
}
|
|
},
|
|
flattenOrganizations(list) {
|
|
const source = Array.isArray(list) ? list : []
|
|
const hasChildren = source.some((item) => Array.isArray(item.children) && item.children.length)
|
|
if (hasChildren) {
|
|
return this.flattenOrganizationTree(source)
|
|
}
|
|
const map = {}
|
|
source.forEach((item) => {
|
|
map[item.organizationId] = {
|
|
...item,
|
|
children: []
|
|
}
|
|
})
|
|
const roots = []
|
|
source.forEach((item) => {
|
|
const current = map[item.organizationId]
|
|
const parentId = Number(item.parentId || 0)
|
|
if (parentId && map[parentId]) {
|
|
map[parentId].children.push(current)
|
|
} else {
|
|
roots.push(current)
|
|
}
|
|
})
|
|
return this.flattenOrganizationTree(roots)
|
|
},
|
|
flattenOrganizationTree(list, parentPath = '') {
|
|
const result = []
|
|
;(list || []).forEach((item) => {
|
|
const currentName = item.organizationName || ''
|
|
const label = parentPath ? `${parentPath} / ${currentName}` : currentName
|
|
if (item.organizationId) {
|
|
result.push({
|
|
label,
|
|
value: Number(item.organizationId),
|
|
rawLabel: currentName
|
|
})
|
|
}
|
|
if (Array.isArray(item.children) && item.children.length) {
|
|
result.push(...this.flattenOrganizationTree(item.children, label))
|
|
}
|
|
})
|
|
return result
|
|
},
|
|
restoreDraft() {
|
|
const draft = uni.getStorageSync(STORAGE_KEY)
|
|
if (!draft || !draft.formData) {
|
|
return
|
|
}
|
|
this.formData = {
|
|
...createDefaultFormData(),
|
|
...draft.formData
|
|
}
|
|
if (!this.formData.collegeName && this.formData.college) {
|
|
this.formData.collegeName = this.formData.college
|
|
}
|
|
this.draftSavedAt = draft.savedAt || ''
|
|
},
|
|
handleSelectChange(field, event) {
|
|
const index = Number(event.detail.value)
|
|
this.formData[field.key] = field.options[index] || ''
|
|
},
|
|
handleDateChange(field, event) {
|
|
this.formData[field.key] = event.detail.value
|
|
},
|
|
handleTextInput(field, event) {
|
|
const value = typeof event === 'string' ? event : (event.detail && event.detail.value) || ''
|
|
this.formData[field.key] = value || ''
|
|
},
|
|
openGenderPicker(field) {
|
|
this.genderFieldKey = field.key
|
|
this.$nextTick(() => {
|
|
this.$refs.genderPicker && this.$refs.genderPicker.open()
|
|
})
|
|
},
|
|
closeGenderPicker() {
|
|
return
|
|
},
|
|
confirmGenderPicker(event) {
|
|
const value = (((event || {}).value || [])[0] || {}).value || ''
|
|
this.formData[this.genderFieldKey] = value
|
|
this.closeGenderPicker()
|
|
},
|
|
openLeaguePositionPicker(field) {
|
|
this.leaguePositionFieldKey = field.key
|
|
this.$nextTick(() => {
|
|
this.$refs.leaguePositionPicker && this.$refs.leaguePositionPicker.open()
|
|
})
|
|
},
|
|
closeLeaguePositionPicker() {
|
|
return
|
|
},
|
|
confirmLeaguePositionPicker(event) {
|
|
const value = (((event || {}).value || [])[0] || {}).value || ''
|
|
this.formData[this.leaguePositionFieldKey] = value
|
|
this.closeLeaguePositionPicker()
|
|
},
|
|
openArchiveInOrgPicker(field) {
|
|
this.archiveInOrgFieldKey = field.key
|
|
this.$nextTick(() => {
|
|
this.$refs.archiveInOrgPicker && this.$refs.archiveInOrgPicker.open()
|
|
})
|
|
},
|
|
closeArchiveInOrgPicker() {
|
|
return
|
|
},
|
|
confirmArchiveInOrgPicker(event) {
|
|
const value = (((event || {}).value || [])[0] || {}).value || ''
|
|
this.formData[this.archiveInOrgFieldKey] = value
|
|
this.closeArchiveInOrgPicker()
|
|
},
|
|
openJoinMonthPicker(field) {
|
|
this.joinMonthFieldKey = field.key
|
|
const pickerState = this.buildJoinMonthPickerState(this.formData[this.joinMonthFieldKey])
|
|
this.joinMonthPickerColumns = pickerState.columns
|
|
this.joinMonthPickerIndexs = pickerState.indexs
|
|
this.$nextTick(() => {
|
|
this.$refs.joinMonthPicker && this.$refs.joinMonthPicker.open()
|
|
})
|
|
},
|
|
closeJoinMonthPicker() {
|
|
return
|
|
},
|
|
handleJoinMonthPickerChange(event) {
|
|
this.joinMonthPickerIndexs = (event && event.indexs) || this.joinMonthPickerIndexs
|
|
},
|
|
confirmJoinMonthPicker(event) {
|
|
const values = (event && event.value) || []
|
|
const yearValue = (values[0] && values[0].value) || ''
|
|
const monthValue = (values[1] && values[1].value) || ''
|
|
if (yearValue && monthValue) {
|
|
this.formData[this.joinMonthFieldKey] = `${yearValue}-${monthValue}`
|
|
}
|
|
this.joinMonthPickerIndexs = (event && event.indexs) || this.joinMonthPickerIndexs
|
|
this.closeJoinMonthPicker()
|
|
},
|
|
handleNationChange(event) {
|
|
const index = Number(event.detail.value)
|
|
const option = this.nationOptions[index]
|
|
this.formData.nation = (option && option.value) || ''
|
|
},
|
|
openPoliticsPicker() {
|
|
this.openSearchPicker({
|
|
title: '政治面貌',
|
|
mode: 'politics',
|
|
options: this.politicsOptions,
|
|
currentValue: this.formData.politics
|
|
})
|
|
},
|
|
openOrganizationPicker() {
|
|
if (!this.organizationTree.length) {
|
|
this.showToast('暂无团支部数据')
|
|
return
|
|
}
|
|
const pickerState = this.buildOrganizationPickerState(
|
|
this.findOrganizationPathByValue(this.organizationTree, this.formData.branchOrganizationId) || []
|
|
)
|
|
this.organizationPickerColumns = pickerState.columns
|
|
this.organizationPickerIndexs = pickerState.indexs
|
|
this.$nextTick(() => {
|
|
this.$refs.organizationPicker && this.$refs.organizationPicker.open()
|
|
})
|
|
},
|
|
closeOrganizationPicker() {
|
|
return
|
|
},
|
|
handleOrganizationPickerChange(event) {
|
|
const pickerState = this.buildOrganizationPickerState((event && event.indexs) || [])
|
|
this.organizationPickerColumns = pickerState.columns
|
|
this.organizationPickerIndexs = pickerState.indexs
|
|
},
|
|
confirmOrganizationPicker(event) {
|
|
const pickerState = this.buildOrganizationPickerState((event && event.indexs) || this.organizationPickerIndexs || [])
|
|
const pathNodes = pickerState.pathNodes || []
|
|
const selectedNode = pathNodes[pathNodes.length - 1]
|
|
if (!selectedNode) {
|
|
this.closeOrganizationPicker()
|
|
return
|
|
}
|
|
this.formData.branchOrganizationId = selectedNode.value
|
|
this.formData.branchOrganizationName = pathNodes.map((item) => item.rawLabel || item.text).filter(Boolean).join(' / ')
|
|
this.organizationPickerIndexs = pickerState.indexs
|
|
this.closeOrganizationPicker()
|
|
},
|
|
findOrganizationPathByValue(list, targetValue, path = []) {
|
|
const source = Array.isArray(list) ? list : []
|
|
const normalizedTarget = String(targetValue || '')
|
|
for (let index = 0; index < source.length; index += 1) {
|
|
const item = source[index]
|
|
const nextPath = path.concat(index)
|
|
if (String(item.value) === normalizedTarget) {
|
|
return nextPath
|
|
}
|
|
if (Array.isArray(item.children) && item.children.length) {
|
|
const result = this.findOrganizationPathByValue(item.children, targetValue, nextPath)
|
|
if (result) {
|
|
return result
|
|
}
|
|
}
|
|
}
|
|
return null
|
|
},
|
|
buildOrganizationPickerState(indexs = []) {
|
|
const columns = []
|
|
const normalizedIndexs = []
|
|
const pathNodes = []
|
|
let currentList = Array.isArray(this.organizationTree) ? this.organizationTree : []
|
|
let depth = 0
|
|
while (Array.isArray(currentList) && currentList.length) {
|
|
columns.push(currentList.map((item) => ({
|
|
text: item.text,
|
|
value: item.value,
|
|
rawLabel: item.rawLabel
|
|
})))
|
|
let currentIndex = Number(indexs[depth] || 0)
|
|
if (currentIndex < 0 || currentIndex >= currentList.length) {
|
|
currentIndex = 0
|
|
}
|
|
normalizedIndexs.push(currentIndex)
|
|
const currentNode = currentList[currentIndex]
|
|
if (!currentNode) {
|
|
break
|
|
}
|
|
pathNodes.push(currentNode)
|
|
currentList = Array.isArray(currentNode.children) ? currentNode.children : []
|
|
depth += 1
|
|
}
|
|
return {
|
|
columns,
|
|
indexs: normalizedIndexs,
|
|
pathNodes
|
|
}
|
|
},
|
|
openCollegePicker() {
|
|
this.openSearchPicker({
|
|
title: '学院',
|
|
mode: 'college',
|
|
options: this.collegeOptions,
|
|
currentValue: this.formData.collegeId
|
|
})
|
|
},
|
|
openClassPicker() {
|
|
if (!this.formData.collegeId) {
|
|
this.showToast('请先选择学院')
|
|
return
|
|
}
|
|
this.openSearchPicker({
|
|
title: '班级',
|
|
mode: 'class',
|
|
options: this.classOptions,
|
|
currentValue: this.formData.classId
|
|
})
|
|
},
|
|
openSearchPicker({title, mode, options, currentValue}) {
|
|
this.searchPickerTitle = title
|
|
this.searchPickerMode = mode
|
|
this.searchPickerOptions = Array.isArray(options) ? options : []
|
|
this.searchPickerKeyword = ''
|
|
this.searchPickerVisible = true
|
|
this.$nextTick(() => {
|
|
this.syncSearchPickerValue(currentValue)
|
|
})
|
|
},
|
|
closeSearchPicker() {
|
|
this.searchPickerVisible = false
|
|
},
|
|
syncSearchPickerValue(currentValue) {
|
|
const list = this.filteredSearchPickerOptions
|
|
if (!list.length) {
|
|
this.searchPickerIndex = 0
|
|
this.searchPickerTempOption = null
|
|
return
|
|
}
|
|
let index = list.findIndex((item) => item.value === currentValue || item.label === currentValue)
|
|
if (index < 0) {
|
|
index = 0
|
|
}
|
|
this.searchPickerIndex = index
|
|
this.searchPickerTempOption = list[index]
|
|
},
|
|
handleSearchPickerInput(event) {
|
|
const value = typeof event === 'string' ? event : (event.detail && event.detail.value) || ''
|
|
this.searchPickerKeyword = value || ''
|
|
this.$nextTick(() => {
|
|
const currentValue = this.searchPickerTempOption ? this.searchPickerTempOption.value : ''
|
|
this.syncSearchPickerValue(currentValue)
|
|
})
|
|
},
|
|
handleSearchPickerChange(event) {
|
|
const index = Number((event.detail.value || [0])[0] || 0)
|
|
this.searchPickerIndex = index
|
|
this.searchPickerTempOption = this.filteredSearchPickerOptions[index] || null
|
|
},
|
|
async confirmSearchPicker() {
|
|
const option = this.searchPickerTempOption
|
|
if (!option) {
|
|
this.closeSearchPicker()
|
|
return
|
|
}
|
|
if (this.searchPickerMode === 'politics') {
|
|
this.formData.politics = option.value
|
|
} else if (this.searchPickerMode === 'college') {
|
|
const nextCollegeId = option.value
|
|
const nextCollegeName = option.label
|
|
const collegeChanged = String(this.formData.collegeId || '') !== String(nextCollegeId || '')
|
|
this.formData.collegeId = nextCollegeId
|
|
this.formData.collegeName = nextCollegeName
|
|
this.formData.college = nextCollegeName
|
|
if (collegeChanged) {
|
|
this.formData.classId = ''
|
|
this.formData.className = ''
|
|
this.classOptions = []
|
|
await this.loadClassOptions(nextCollegeId)
|
|
}
|
|
} else if (this.searchPickerMode === 'class') {
|
|
this.formData.classId = option.value
|
|
this.formData.className = option.label
|
|
}
|
|
this.closeSearchPicker()
|
|
},
|
|
getSelectIndex(field) {
|
|
const currentValue = this.formData[field.key]
|
|
const index = field.options.indexOf(currentValue)
|
|
return index > -1 ? index : 0
|
|
},
|
|
parseBirthDateFromIdCard(idCardNo) {
|
|
const value = String(idCardNo || '').trim().toUpperCase()
|
|
let rawBirth = ''
|
|
if (/^\d{17}[\dX]$/.test(value)) {
|
|
rawBirth = value.slice(6, 14)
|
|
} else if (/^\d{15}$/.test(value)) {
|
|
rawBirth = `19${value.slice(6, 12)}`
|
|
} else {
|
|
return ''
|
|
}
|
|
const year = rawBirth.slice(0, 4)
|
|
const month = rawBirth.slice(4, 6)
|
|
const day = rawBirth.slice(6, 8)
|
|
const date = new Date(`${year}/${month}/${day}`)
|
|
if (Number.isNaN(date.getTime())) {
|
|
return ''
|
|
}
|
|
return `${year}-${month}-${day}`
|
|
},
|
|
syncBirthDateFromIdCard() {
|
|
this.formData.birthDate = this.parseBirthDateFromIdCard(this.formData.idCardNo)
|
|
},
|
|
validateForm() {
|
|
for (const field of this.fields) {
|
|
if (field.required && !String(this.getFieldDisplayValue(field) || '').trim()) {
|
|
this.showToast(`请完善:${field.label}`)
|
|
return false
|
|
}
|
|
}
|
|
if (this.formData.phone && !/^1\d{10}$/.test(this.formData.phone)) {
|
|
this.showToast('请输入正确的手机号码')
|
|
return false
|
|
}
|
|
if (this.formData.idCardNo && !this.formData.birthDate) {
|
|
this.showToast('身份证号格式不正确,无法识别出生日期')
|
|
return false
|
|
}
|
|
if (this.formData.collegeId && !this.formData.classId) {
|
|
this.showToast('请选择班级')
|
|
return false
|
|
}
|
|
return true
|
|
},
|
|
saveDraft() {
|
|
const savedAt = this.formatNow()
|
|
uni.setStorageSync(STORAGE_KEY, {
|
|
formData: this.formData,
|
|
savedAt
|
|
})
|
|
this.draftSavedAt = savedAt
|
|
uni.showToast({
|
|
title: '草稿已保存',
|
|
icon: 'success'
|
|
})
|
|
},
|
|
async submitForm() {
|
|
if (!this.validateForm()) {
|
|
return
|
|
}
|
|
try {
|
|
const payload = this.buildSubmitPayload()
|
|
const result = this.formId
|
|
? await updateTyglForm(payload)
|
|
: await saveTyglForm(payload)
|
|
if (!this.formId && result && result.id) {
|
|
this.formId = result.id
|
|
}
|
|
const savedAt = this.formatNow()
|
|
uni.setStorageSync(STORAGE_KEY, {
|
|
formData: this.formData,
|
|
savedAt,
|
|
status: 'submitted'
|
|
})
|
|
this.draftSavedAt = savedAt
|
|
uni.showModal({
|
|
title: '提交成功',
|
|
content: this.formId ? '团员档案已更新。' : '团员档案已创建。',
|
|
showCancel: false
|
|
})
|
|
} catch (error) {
|
|
this.showToast((error && error.message) || '保存失败')
|
|
}
|
|
},
|
|
formatNow() {
|
|
const now = new Date()
|
|
const pad = (value) => String(value).padStart(2, '0')
|
|
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}`
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.page {
|
|
min-height: 100vh;
|
|
background: rgba(241, 241, 241, 1);
|
|
//radial-gradient(circle at top right, rgba(20, 150, 242, 0.14), transparent 30%),
|
|
//linear-gradient(180deg, #f5fbff 0%, #eef7ff 100%);
|
|
}
|
|
|
|
.page-scroll {
|
|
height: 100vh;
|
|
padding: 0 0 40rpx;
|
|
}
|
|
|
|
.section-card{
|
|
border-radius: 30rpx;
|
|
background: rgba(255, 255, 255, 1);
|
|
}
|
|
|
|
.action-card {
|
|
border-radius: 30rpx;
|
|
//background: rgba(255, 255, 255, 0.94);
|
|
//border: 1rpx solid rgba(20, 150, 242, 0.08);
|
|
//box-shadow: 0 10rpx 28rpx rgba(34, 94, 142, 0.08);
|
|
}
|
|
|
|
.section-card,
|
|
.action-card {
|
|
margin-top: 24rpx;
|
|
padding: 26rpx;
|
|
margin-left: 24rpx;
|
|
margin-right: 24rpx;
|
|
}
|
|
|
|
.section-head {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-end;
|
|
margin-bottom: 18rpx;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 30rpx;
|
|
font-weight: 700;
|
|
color: #1f2329;
|
|
}
|
|
|
|
.field-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 22rpx;
|
|
}
|
|
|
|
.field-label {
|
|
margin-bottom: 12rpx;
|
|
font-size: 25rpx;
|
|
font-weight: 600;
|
|
color: #2b3037;
|
|
}
|
|
|
|
.field-required {
|
|
margin-left: 8rpx;
|
|
color: #1496f2;
|
|
}
|
|
|
|
.field-picker {
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
padding: 22rpx 24rpx;
|
|
border-radius: 22rpx;
|
|
background: #F4FCFF;
|
|
border: 1rpx solid rgba(220,220,220,1);
|
|
font-size: 24rpx;
|
|
color: #2a2e35;
|
|
}
|
|
|
|
.field-picker--readonly {
|
|
background: #f9fafb;
|
|
}
|
|
|
|
:deep(.field-native-input.uv-input) {
|
|
width: 100%;
|
|
height: 88rpx;
|
|
padding: 0 24rpx !important;
|
|
border-radius: 12rpx;
|
|
border: 1px solid #dcdfe6 !important;
|
|
background: #ffffff !important;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
:deep(.field-native-input.uv-input .uv-input__content__field-wrapper__field) {
|
|
font-size: 28rpx;
|
|
line-height: 88rpx;
|
|
color: #303133;
|
|
}
|
|
|
|
.field-placeholder {
|
|
color: #aa9f98;
|
|
}
|
|
|
|
.field-value {
|
|
color: #2a2e35;
|
|
}
|
|
|
|
.action-card {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
gap: 18rpx;
|
|
}
|
|
|
|
.option-mask {
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
z-index: 99;
|
|
display: flex;
|
|
align-items: flex-end;
|
|
background: rgba(15, 23, 42, 0.34);
|
|
}
|
|
|
|
.option-popup {
|
|
width: 100%;
|
|
padding: 24rpx 24rpx calc(24rpx + env(safe-area-inset-bottom));
|
|
border-radius: 32rpx 32rpx 0 0;
|
|
background: #fff;
|
|
}
|
|
|
|
.option-popup-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.option-popup-title {
|
|
font-size: 28rpx;
|
|
font-weight: 700;
|
|
color: #1f2329;
|
|
}
|
|
|
|
.option-popup-btn {
|
|
font-size: 24rpx;
|
|
color: #7c736e;
|
|
}
|
|
|
|
.option-popup-btn--primary {
|
|
color: #1496f2;
|
|
font-weight: 600;
|
|
}
|
|
|
|
:deep(.option-search.uv-input) {
|
|
width: 100%;
|
|
height: 84rpx;
|
|
margin-top: 20rpx;
|
|
padding: 0 24rpx !important;
|
|
border-radius: 22rpx;
|
|
background: #f8f4f1 !important;
|
|
border: 1rpx solid #eadfd7 !important;
|
|
}
|
|
|
|
:deep(.option-search.uv-input .uv-input__content__field-wrapper__field) {
|
|
font-size: 24rpx;
|
|
color: #2a2e35;
|
|
}
|
|
|
|
.option-picker-wrap {
|
|
margin-top: 20rpx;
|
|
border-radius: 24rpx;
|
|
background: #fafcff;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.option-picker-view {
|
|
width: 100%;
|
|
height: 420rpx;
|
|
}
|
|
|
|
.option-picker-item {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 84rpx;
|
|
padding: 0 24rpx;
|
|
font-size: 28rpx;
|
|
color: #2a2e35;
|
|
text-align: center;
|
|
}
|
|
|
|
.option-empty {
|
|
padding: 60rpx 0 40rpx;
|
|
text-align: center;
|
|
font-size: 24rpx;
|
|
color: #aa9f98;
|
|
}
|
|
|
|
.ghost-btn,
|
|
.primary-btn {
|
|
height: 88rpx;
|
|
line-height: 88rpx;
|
|
border-radius: 22rpx;
|
|
font-size: 28rpx;
|
|
font-weight: 700;
|
|
margin: 0;
|
|
}
|
|
|
|
.ghost-btn {
|
|
background: #FFA2DA;
|
|
color: #ffffff;
|
|
border: none;
|
|
border-radius: 999px;
|
|
}
|
|
|
|
.primary-btn {
|
|
background: linear-gradient(147.22deg, rgba(0, 180, 255, 1) 37.65%, rgba(88, 206, 255, 1) 80.42%);
|
|
color: #fff;
|
|
border-radius: 999px;
|
|
}
|
|
</style>
|