|
@@ -3,17 +3,9 @@ import { CommonModule } from '@angular/common';
|
|
|
import { FormsModule } from '@angular/forms';
|
|
import { FormsModule } from '@angular/forms';
|
|
|
import { CustomerService } from '../services/customer.service';
|
|
import { CustomerService } from '../services/customer.service';
|
|
|
import { FmodeObject } from 'fmode-ng/core';
|
|
import { FmodeObject } from 'fmode-ng/core';
|
|
|
|
|
+import { FmodeParse } from 'fmode-ng/parse';
|
|
|
import { CustomerProfileComponent } from '../../../../modules/project/pages/contact/contact.component';
|
|
import { CustomerProfileComponent } from '../../../../modules/project/pages/contact/contact.component';
|
|
|
|
|
|
|
|
-interface Customer {
|
|
|
|
|
- id: string;
|
|
|
|
|
- name: string;
|
|
|
|
|
- mobile: string;
|
|
|
|
|
- external_userid?: string;
|
|
|
|
|
- source?: string;
|
|
|
|
|
- createdAt?: Date;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
@Component({
|
|
@Component({
|
|
|
selector: 'app-admin-customers',
|
|
selector: 'app-admin-customers',
|
|
|
standalone: true,
|
|
standalone: true,
|
|
@@ -22,51 +14,28 @@ interface Customer {
|
|
|
styleUrl: './customers.scss'
|
|
styleUrl: './customers.scss'
|
|
|
})
|
|
})
|
|
|
export class Customers implements OnInit {
|
|
export class Customers implements OnInit {
|
|
|
- // 统计
|
|
|
|
|
total = signal(0);
|
|
total = signal(0);
|
|
|
loading = signal(false);
|
|
loading = signal(false);
|
|
|
|
|
+ customers = signal<FmodeObject[]>([]);
|
|
|
|
|
|
|
|
- // 数据
|
|
|
|
|
- customers = signal<Customer[]>([]);
|
|
|
|
|
- customerObjects: Map<string, FmodeObject> = new Map(); // 存储Parse对象
|
|
|
|
|
-
|
|
|
|
|
- // 客户详情面板
|
|
|
|
|
showCustomerPanel = false;
|
|
showCustomerPanel = false;
|
|
|
selectedCustomer: FmodeObject | null = null;
|
|
selectedCustomer: FmodeObject | null = null;
|
|
|
|
|
+ currentUserForContact: FmodeObject | null = null;
|
|
|
|
|
+ panelProjectId: string | null = null;
|
|
|
|
|
|
|
|
constructor(private customerService: CustomerService) {}
|
|
constructor(private customerService: CustomerService) {}
|
|
|
|
|
|
|
|
ngOnInit(): void {
|
|
ngOnInit(): void {
|
|
|
this.loadCustomers();
|
|
this.loadCustomers();
|
|
|
|
|
+ this.setupCurrentUserForContact();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async loadCustomers(): Promise<void> {
|
|
async loadCustomers(): Promise<void> {
|
|
|
this.loading.set(true);
|
|
this.loading.set(true);
|
|
|
try {
|
|
try {
|
|
|
const custs = await this.customerService.findCustomers();
|
|
const custs = await this.customerService.findCustomers();
|
|
|
-
|
|
|
|
|
- // 清空之前的对象映射
|
|
|
|
|
- this.customerObjects.clear();
|
|
|
|
|
-
|
|
|
|
|
- const custList: Customer[] = custs.map(c => {
|
|
|
|
|
- const json = this.customerService.toJSON(c);
|
|
|
|
|
- const customerId = json.objectId;
|
|
|
|
|
-
|
|
|
|
|
- // 保存Parse对象以便后续使用
|
|
|
|
|
- this.customerObjects.set(customerId, c);
|
|
|
|
|
-
|
|
|
|
|
- return {
|
|
|
|
|
- id: customerId,
|
|
|
|
|
- name: json.name || '未知客户',
|
|
|
|
|
- mobile: json.mobile || '',
|
|
|
|
|
- external_userid: json.external_userid,
|
|
|
|
|
- source: json.source,
|
|
|
|
|
- createdAt: json.createdAt?.iso || json.createdAt
|
|
|
|
|
- };
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- this.customers.set(custList);
|
|
|
|
|
- this.total.set(custList.length);
|
|
|
|
|
|
|
+ this.customers.set(custs);
|
|
|
|
|
+ this.total.set(custs.length);
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('加载客户列表失败:', error);
|
|
console.error('加载客户列表失败:', error);
|
|
|
} finally {
|
|
} finally {
|
|
@@ -74,37 +43,39 @@ export class Customers implements OnInit {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 打开客户详情面板
|
|
|
|
|
- openCustomerDetail(customer: Customer) {
|
|
|
|
|
- const customerObj = this.customerObjects.get(customer.id);
|
|
|
|
|
- if (customerObj) {
|
|
|
|
|
- this.selectedCustomer = customerObj;
|
|
|
|
|
- this.showCustomerPanel = true;
|
|
|
|
|
|
|
+ setupCurrentUserForContact() {
|
|
|
|
|
+ const companyId = localStorage.getItem('company');
|
|
|
|
|
+ if (companyId) {
|
|
|
|
|
+ const Company = (FmodeParse.with('nova') as any).Object.extend('Company');
|
|
|
|
|
+ const company = new Company();
|
|
|
|
|
+ company.id = companyId;
|
|
|
|
|
+ const companyPtr = company.toPointer();
|
|
|
|
|
+ this.currentUserForContact = { get: (key: string) => key === 'company' ? companyPtr : (key === 'roleName' ? '管理员' : null) } as any;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 关闭客户详情面板
|
|
|
|
|
- closeCustomerPanel() {
|
|
|
|
|
|
|
+ openCustomerDetail(customer: FmodeObject) {
|
|
|
|
|
+ this.selectedCustomer = customer;
|
|
|
|
|
+ this.showCustomerPanel = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async closeCustomerPanel(refresh: boolean = false) {
|
|
|
this.showCustomerPanel = false;
|
|
this.showCustomerPanel = false;
|
|
|
this.selectedCustomer = null;
|
|
this.selectedCustomer = null;
|
|
|
|
|
+ if (refresh) await this.loadCustomers();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 筛选
|
|
|
|
|
keyword = signal('');
|
|
keyword = signal('');
|
|
|
status = signal<'all' | 'active' | 'inactive'>('all');
|
|
status = signal<'all' | 'active' | 'inactive'>('all');
|
|
|
level = signal<'all' | 'normal' | 'vip' | 'svip'>('all');
|
|
level = signal<'all' | 'normal' | 'vip' | 'svip'>('all');
|
|
|
|
|
|
|
|
- // 面板状态
|
|
|
|
|
- showPanel = false;
|
|
|
|
|
- panelMode: 'add' | 'detail' | 'edit' = 'add';
|
|
|
|
|
- currentCustomer: Customer | null = null;
|
|
|
|
|
- formModel: Partial<Customer> = {};
|
|
|
|
|
-
|
|
|
|
|
get filtered() {
|
|
get filtered() {
|
|
|
const kw = this.keyword().trim().toLowerCase();
|
|
const kw = this.keyword().trim().toLowerCase();
|
|
|
return this.customers().filter(c => {
|
|
return this.customers().filter(c => {
|
|
|
- const m1 = !kw || c.name.toLowerCase().includes(kw) || c.mobile.includes(kw);
|
|
|
|
|
- return m1;
|
|
|
|
|
|
|
+ if (!kw) return true;
|
|
|
|
|
+ const name = (c.get('name') || c.get('data')?.name || '').toLowerCase();
|
|
|
|
|
+ const mobile = c.get('mobile') || '';
|
|
|
|
|
+ return name.includes(kw) || mobile.includes(kw);
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -112,15 +83,14 @@ export class Customers implements OnInit {
|
|
|
this.keyword.set('');
|
|
this.keyword.set('');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 导出当前筛选客户为 CSV
|
|
|
|
|
exportCustomers() {
|
|
exportCustomers() {
|
|
|
const header = ['客户名称','手机号','企微ID','来源','创建时间'];
|
|
const header = ['客户名称','手机号','企微ID','来源','创建时间'];
|
|
|
const rows = this.filtered.map(c => [
|
|
const rows = this.filtered.map(c => [
|
|
|
- c.name,
|
|
|
|
|
- c.mobile,
|
|
|
|
|
- c.external_userid || '',
|
|
|
|
|
- c.source || '',
|
|
|
|
|
- c.createdAt instanceof Date ? c.createdAt.toISOString().slice(0, 10) : String(c.createdAt || '')
|
|
|
|
|
|
|
+ c.get('name') || c.get('data')?.name || '',
|
|
|
|
|
+ c.get('mobile') || '',
|
|
|
|
|
+ c.get('external_userid') || '',
|
|
|
|
|
+ c.get('source') || '',
|
|
|
|
|
+ (c.get('createdAt') instanceof Date) ? (c.get('createdAt') as Date).toISOString().slice(0, 10) : String(c.get('createdAt') || '')
|
|
|
]);
|
|
]);
|
|
|
this.downloadCSV('客户列表.csv', [header, ...rows]);
|
|
this.downloadCSV('客户列表.csv', [header, ...rows]);
|
|
|
}
|
|
}
|
|
@@ -140,5 +110,4 @@ export class Customers implements OnInit {
|
|
|
a.click();
|
|
a.click();
|
|
|
URL.revokeObjectURL(url);
|
|
URL.revokeObjectURL(url);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
}
|
|
}
|