城市合伙人端开店城市屁默认郑州
This commit is contained in:
@@ -1,7 +1,12 @@
|
|||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { codeToText } from 'element-china-area-data';
|
import { codeToText } from 'element-china-area-data';
|
||||||
import { CHINA_REGION_OPTIONS, formatRegionLabel, parseRegionCodes } from '../lib/china-region';
|
import {
|
||||||
|
CHINA_REGION_OPTIONS,
|
||||||
|
DEFAULT_REGION_CODES,
|
||||||
|
formatRegionLabel,
|
||||||
|
parseRegionCodes,
|
||||||
|
} from '../lib/china-region';
|
||||||
|
|
||||||
type RegionNode = {
|
type RegionNode = {
|
||||||
value: string;
|
value: string;
|
||||||
@@ -40,10 +45,26 @@ function lockBodyScroll(lock: boolean) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildInitialDraft(value: string[]): { draft: string[]; step: number } {
|
||||||
|
if (value.length === 3) {
|
||||||
|
return { draft: [...value], step: 2 };
|
||||||
|
}
|
||||||
|
if (value.length > 0) {
|
||||||
|
const draft = [...value];
|
||||||
|
for (let i = value.length; i < DEFAULT_REGION_CODES.length; i += 1) {
|
||||||
|
draft.push(DEFAULT_REGION_CODES[i]);
|
||||||
|
}
|
||||||
|
return { draft, step: Math.min(value.length, 2) };
|
||||||
|
}
|
||||||
|
return { draft: [...DEFAULT_REGION_CODES], step: 1 };
|
||||||
|
}
|
||||||
|
|
||||||
export default function ChinaRegionPicker({ value = [], onChange, disabled }: ChinaRegionPickerProps) {
|
export default function ChinaRegionPicker({ value = [], onChange, disabled }: ChinaRegionPickerProps) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [draft, setDraft] = useState<string[]>(value);
|
const [draft, setDraft] = useState<string[]>(value);
|
||||||
const [step, setStep] = useState(0);
|
const [step, setStep] = useState(0);
|
||||||
|
const listRef = useRef<HTMLDivElement>(null);
|
||||||
|
const activeItemRef = useRef<HTMLButtonElement | null>(null);
|
||||||
|
|
||||||
const options = CHINA_REGION_OPTIONS as RegionNode[];
|
const options = CHINA_REGION_OPTIONS as RegionNode[];
|
||||||
const parsed = parseRegionCodes(value);
|
const parsed = parseRegionCodes(value);
|
||||||
@@ -69,11 +90,23 @@ export default function ChinaRegionPicker({ value = [], onChange, disabled }: Ch
|
|||||||
return () => lockBodyScroll(false);
|
return () => lockBodyScroll(false);
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!open) return;
|
||||||
|
const timer = window.setTimeout(() => {
|
||||||
|
const container = listRef.current;
|
||||||
|
const activeEl = activeItemRef.current;
|
||||||
|
if (!container || !activeEl) return;
|
||||||
|
const offset = activeEl.offsetTop - container.clientHeight / 2 + activeEl.clientHeight / 2;
|
||||||
|
container.scrollTo({ top: Math.max(0, offset), behavior: 'smooth' });
|
||||||
|
}, 0);
|
||||||
|
return () => window.clearTimeout(timer);
|
||||||
|
}, [open, step, activeCode, listItems]);
|
||||||
|
|
||||||
function openPicker() {
|
function openPicker() {
|
||||||
if (disabled) return;
|
if (disabled) return;
|
||||||
const next = value.length === 3 ? [...value] : [];
|
const { draft: next, step: initialStep } = buildInitialDraft(value);
|
||||||
setDraft(next);
|
setDraft(next);
|
||||||
setStep(next.length >= 3 ? 2 : next.length);
|
setStep(initialStep);
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,13 +180,14 @@ export default function ChinaRegionPicker({ value = [], onChange, disabled }: Ch
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="partner-region-list" role="listbox">
|
<div className="partner-region-list" role="listbox" ref={listRef}>
|
||||||
{listItems.map((item) => (
|
{listItems.map((item) => (
|
||||||
<button
|
<button
|
||||||
key={item.value}
|
key={item.value}
|
||||||
type="button"
|
type="button"
|
||||||
role="option"
|
role="option"
|
||||||
aria-selected={activeCode === item.value}
|
aria-selected={activeCode === item.value}
|
||||||
|
ref={activeCode === item.value ? (el) => { activeItemRef.current = el; } : undefined}
|
||||||
className={`partner-region-item${activeCode === item.value ? ' partner-region-item--active' : ''}`}
|
className={`partner-region-item${activeCode === item.value ? ' partner-region-item--active' : ''}`}
|
||||||
onClick={() => selectItem(item.value)}
|
onClick={() => selectItem(item.value)}
|
||||||
>
|
>
|
||||||
@@ -175,4 +209,4 @@ export default function ChinaRegionPicker({ value = [], onChange, disabled }: Ch
|
|||||||
{typeof document !== 'undefined' ? createPortal(modal, document.body) : null}
|
{typeof document !== 'undefined' ? createPortal(modal, document.body) : null}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,20 @@ export function formatRegionLabel(region: ParsedChinaRegion): string {
|
|||||||
return `${region.province} / ${region.city} / ${region.district}`;
|
return `${region.province} / ${region.city} / ${region.district}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 合伙人录店默认省市区 adcode:河南省 / 郑州市 / 金水区 */
|
||||||
|
export const DEFAULT_REGION_CODES = ['41', '4101', '410105'] as const;
|
||||||
|
|
||||||
|
export function getDefaultPartnerRegionForm() {
|
||||||
|
const regionCodes = [...DEFAULT_REGION_CODES];
|
||||||
|
const parsed = parseRegionCodes(regionCodes);
|
||||||
|
return {
|
||||||
|
regionCodes,
|
||||||
|
province: parsed?.province ?? '河南省',
|
||||||
|
city: parsed?.city ?? '郑州市',
|
||||||
|
district: parsed?.district ?? '金水区',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function matchOpenCityId(cities: OpenCityRef[], districtCode: string): string | undefined {
|
export function matchOpenCityId(cities: OpenCityRef[], districtCode: string): string | undefined {
|
||||||
const cityCode = districtCodeToCityCode(districtCode);
|
const cityCode = districtCodeToCityCode(districtCode);
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -27,12 +27,11 @@ export function storeDraftKey(accountId?: string): string {
|
|||||||
return accountId ? `${STORE_DRAFT_KEY}_${accountId}` : STORE_DRAFT_KEY;
|
return accountId ? `${STORE_DRAFT_KEY}_${accountId}` : STORE_DRAFT_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import { getDefaultPartnerRegionForm } from './china-region';
|
||||||
|
|
||||||
export const defaultStoreForm = (): StoreDraftForm => ({
|
export const defaultStoreForm = (): StoreDraftForm => ({
|
||||||
regionCodes: [],
|
...getDefaultPartnerRegionForm(),
|
||||||
cityId: '',
|
cityId: '',
|
||||||
province: '',
|
|
||||||
city: '',
|
|
||||||
district: '',
|
|
||||||
name: '',
|
name: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
address: '',
|
address: '',
|
||||||
@@ -54,7 +53,7 @@ export function normalizeStringArray(raw: unknown, length: number): string[] {
|
|||||||
|
|
||||||
function normalizeForm(raw: Record<string, unknown>): StoreDraftForm {
|
function normalizeForm(raw: Record<string, unknown>): StoreDraftForm {
|
||||||
const base = defaultStoreForm();
|
const base = defaultStoreForm();
|
||||||
const regionCodes = Array.isArray(raw.regionCodes)
|
const regionCodes = Array.isArray(raw.regionCodes) && raw.regionCodes.length >= 3
|
||||||
? raw.regionCodes.map((code) => String(code))
|
? raw.regionCodes.map((code) => String(code))
|
||||||
: base.regionCodes;
|
: base.regionCodes;
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -168,6 +168,30 @@ export default function StoreCreatePage() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
if (!cities.length || form.regionCodes.length < 3 || form.cityId) return;
|
||||||
|
|
||||||
|
const binding = resolveRegionBinding(form.regionCodes, cities);
|
||||||
|
|
||||||
|
if (!binding) return;
|
||||||
|
|
||||||
|
patchForm({
|
||||||
|
|
||||||
|
cityId: binding.cityId ?? '',
|
||||||
|
|
||||||
|
province: binding.region.province,
|
||||||
|
|
||||||
|
city: binding.region.city,
|
||||||
|
|
||||||
|
district: binding.region.district,
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}, [cities, form.regionCodes, form.cityId]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const regionBindingHint = useMemo(() => {
|
const regionBindingHint = useMemo(() => {
|
||||||
|
|
||||||
if (!form.regionCodes.length) return null;
|
if (!form.regionCodes.length) return null;
|
||||||
|
|||||||
Reference in New Issue
Block a user