| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- import Parse from '../../../../shared/db/parse-client.js';
- import { deriveLifecyclePhase, type LifecyclePhase } from '../utils/lifecycle.util.js';
- import { listStores } from './organization.service.js';
- export interface CommunityDto {
- id: string;
- name: string;
- address: string;
- deliveryDate: string;
- lifecyclePhase: LifecyclePhase;
- totalHouseholds: number;
- avgPrice: number;
- storeId: string;
- storeName: string;
- groupCount: number;
- status: string;
- }
- export interface LifecycleSummaryDto {
- phase: LifecyclePhase;
- label: string;
- count: number;
- communities: CommunityDto[];
- }
- const SEED_COMMUNITIES: Array<{
- name: string;
- address: string;
- deliveryDate: string;
- totalHouseholds: number;
- avgPrice: number;
- storeCode: string;
- }> = [
- { name: '翠湖天地', address: '上海市黄浦区', deliveryDate: '2027-06', totalHouseholds: 1200, avgPrice: 168000, storeCode: 'SH001' },
- { name: '万达瑞华公馆', address: '上海市徐汇区', deliveryDate: '2026-08', totalHouseholds: 500, avgPrice: 185000, storeCode: 'SH001' },
- { name: '汤臣一品', address: '上海市浦东新区', deliveryDate: '2025-12', totalHouseholds: 800, avgPrice: 250000, storeCode: 'SH001' },
- { name: '华侨城苏河湾', address: '上海市静安区', deliveryDate: '2024-03', totalHouseholds: 600, avgPrice: 135000, storeCode: 'SH001' },
- { name: '北京壹号院', address: '北京市朝阳区', deliveryDate: '2026-09', totalHouseholds: 900, avgPrice: 180000, storeCode: 'BJ001' },
- { name: '万柳书院', address: '北京市海淀区', deliveryDate: '2022-01', totalHouseholds: 650, avgPrice: 155000, storeCode: 'BJ001' },
- { name: '深圳湾一号', address: '深圳市南山区', deliveryDate: '2025-06', totalHouseholds: 1000, avgPrice: 200000, storeCode: 'SZ001' },
- { name: '保利天珺', address: '深圳市福田区', deliveryDate: '2020-03', totalHouseholds: 600, avgPrice: 160000, storeCode: 'SZ001' },
- ];
- function toDto(obj: Parse.Object): CommunityDto {
- const deliveryDate = obj.get('deliveryDate') || '';
- const lifecyclePhase = (obj.get('lifecyclePhase') as LifecyclePhase)
- || deriveLifecyclePhase(deliveryDate);
- return {
- id: obj.id!,
- name: obj.get('name') || '',
- address: obj.get('address') || '',
- deliveryDate,
- lifecyclePhase,
- totalHouseholds: obj.get('totalHouseholds') ?? 0,
- avgPrice: obj.get('avgPrice') ?? 0,
- storeId: obj.get('storeId') || '',
- storeName: obj.get('storeName') || '',
- groupCount: obj.get('groupCount') ?? 0,
- status: obj.get('status') || 'active',
- };
- }
- export async function listCommunities(filters: {
- storeId?: string;
- lifecyclePhase?: LifecyclePhase;
- } = {}): Promise<CommunityDto[]> {
- const query = new Parse.Query('Community');
- query.equalTo('status', 'active');
- if (filters.storeId) query.equalTo('storeId', filters.storeId);
- if (filters.lifecyclePhase) query.equalTo('lifecyclePhase', filters.lifecyclePhase);
- query.ascending('name');
- query.limit(500);
- const results = await query.find({ useMasterKey: true });
- return results.map(toDto);
- }
- export function groupCommunitiesByLifecycle(communities: CommunityDto[]): LifecycleSummaryDto[] {
- const phases: LifecyclePhase[] = ['pre_handover', 'near_handover', 'post_handover', 'legacy'];
- const labels: Record<LifecyclePhase, string> = {
- pre_handover: '交房前',
- near_handover: '临交房',
- post_handover: '已交房',
- legacy: '老小区',
- };
- return phases.map((phase) => {
- const items = communities.filter((c) => c.lifecyclePhase === phase);
- return { phase, label: labels[phase], count: items.length, communities: items };
- });
- }
- export async function getCommunityLifecycleMap(): Promise<Map<string, LifecyclePhase>> {
- const communities = await listCommunities();
- const map = new Map<string, LifecyclePhase>();
- for (const c of communities) {
- map.set(c.id, c.lifecyclePhase);
- }
- return map;
- }
- export async function bootstrapCommunities(): Promise<void> {
- const stores = await listStores();
- const storeByCode = new Map(stores.map((s) => [s.code, s]));
- let created = 0;
- let updated = 0;
- for (const seed of SEED_COMMUNITIES) {
- const store = storeByCode.get(seed.storeCode);
- if (!store) continue;
- const lifecyclePhase = deriveLifecyclePhase(seed.deliveryDate);
- const query = new Parse.Query('Community');
- query.equalTo('name', seed.name);
- const existing = await query.first({ useMasterKey: true });
- if (existing) {
- existing.set('address', seed.address);
- existing.set('deliveryDate', seed.deliveryDate);
- existing.set('lifecyclePhase', lifecyclePhase);
- existing.set('totalHouseholds', seed.totalHouseholds);
- existing.set('avgPrice', seed.avgPrice);
- existing.set('storeId', store.id);
- existing.set('storeName', store.name);
- existing.set('status', 'active');
- await existing.save(null, { useMasterKey: true });
- updated++;
- continue;
- }
- const obj = new Parse.Object('Community');
- obj.set('name', seed.name);
- obj.set('address', seed.address);
- obj.set('deliveryDate', seed.deliveryDate);
- obj.set('lifecyclePhase', lifecyclePhase);
- obj.set('totalHouseholds', seed.totalHouseholds);
- obj.set('avgPrice', seed.avgPrice);
- obj.set('storeId', store.id);
- obj.set('storeName', store.name);
- obj.set('groupCount', 0);
- obj.set('status', 'active');
- await obj.save(null, { useMasterKey: true });
- created++;
- }
- if (created > 0 || updated > 0) {
- console.log(`[Community] 小区种子已同步:新增 ${created},更新 ${updated}`);
- }
- }
|