Angular新建项目指南
一 参考资料:
https://opentiny.design/
中后台解决方案:https://opentiny.design/pro/home
https://opentiny.design/ng-pro/docs/introduction
组件库介绍文档:https://opentiny.design/tiny-ng/overview
华为云云速建站服务:https://www.huaweicloud.com/product/cloudsite/course.html
https://www.huaweicloud.com/product/cloudsite.html?utm_source=3.baidu.com&utm_medium=organic&utm_adplace=kapian
搭建个人博客网站:https://www.huaweicloud.com/zhishi/edits-15808163.html
华为云搭建网站:https://www.huaweicloud.com/special/hwcjianzhan.html
自主建站方式:https://support.huaweicloud.com/bestpractice-ecs/ecs_web_0001.html#section2
弹性公网IP说明:https://support.huaweicloud.com/productdesc-eip/eip_pro_0001.html
nodejs:http://nodejs.p2hp.com/learn/
expressJS:https://www.expressjs.com.cn/
http://127.0.0.1:3000/
https://www.expressjs.com.cn/starter/generator.html
ng generate component xxx
ng generate module xxx --route xxx --module pages.module
二 重要设置
tsconfig.json :
"paths": {
"@shared/all": [
"src/app/@shared/index.ts"
],
"@images/*": [ "src/assets/images/*" ]
}
angular.json:
"outputPath": "server/public",
"styles": [
"node_modules/@opentiny/ng/themes/styles.css", // 基础样式
"node_modules/@opentiny/ng/themes/theme-default.css", // 主题样式
"src/styles.less"
],
server/app.js
app.use(express.static(path.join(__dirname, 'public')));
三 目录结构
四 核心代码
4.1 shangji.component.html
<ti-halfmodal #halfmodal id="halfmodal-content" [backdrop]="true">
<ti-halfmodal-header>配置</ti-halfmodal-header>
<ti-halfmodal-body>
<ng-container *ngIf="halfmodalOpts.show">
<ti-formfield>
<ti-item [label]="halfmodalOpts.data.id.label" [required]="true" [show]="true">
<div class="sj-shangji-id">
{{halfmodalOpts.data.id.value}}
</div>
</ti-item>
<ti-item [label]="halfmodalOpts.data.source.label" [required]="true" [show]="true">
<input type="text" tiText style="width:300px" [(ngModel)]="halfmodalOpts.data.source.value">
</ti-item>
<ti-item [label]="halfmodalOpts.data.time.label" [required]="true" [show]="true">
<div class="sj-shangji-id">
{{halfmodalOpts.data.time.value | date:'yyyy.MM.dd HH:mm'}}
</div>
</ti-item>
<ti-item [label]="halfmodalOpts.data.province.label" [required]="true" [show]="true">
<ti-select
id="select-basic-province"
class="sj-shangji-formfield-width"
[options]="halfmodalOpts.data.province.options"
[(ngModel)]="halfmodalOpts.data.province.value"
(select)="halfmodalOpts.data.province.onSelect($event)"
placeholder="请选择省份">
</ti-select>
</ti-item>
<ti-item [label]="halfmodalOpts.data.contactInformation.label" [required]="true" [show]="true">
<input type="text" tiText style="width:300px" [(ngModel)]="halfmodalOpts.data.contactInformation.value">
</ti-item>
<ti-item [label]="halfmodalOpts.data.type.label" [required]="true" [show]="true">
<ti-select
id="select-basic-type"
class="sj-shangji-formfield-width"
[options]="halfmodalOpts.data.type.options"
[(ngModel)]="halfmodalOpts.data.type.value"
placeholder="请选择类型">
</ti-select>
</ti-item>
<ti-item [label]="halfmodalOpts.data.accessPeoples.label" [required]="true" [show]="true">
<ti-select
id="select-basic-accessPeoples"
class="sj-shangji-formfield-width"
[options]="halfmodalOpts.data.accessPeoples.options"
[(ngModel)]="halfmodalOpts.data.accessPeoples.value"
placeholder="请选择接入人">
</ti-select>
</ti-item>
<ti-item [label]="halfmodalOpts.data.regionalManager.label" [required]="true" [show]="true">
<ti-select
id="select-basic-regionalManager"
class="sj-shangji-formfield-width"
[options]="halfmodalOpts.data.regionalManager.options"
[(ngModel)]="halfmodalOpts.data.regionalManager.value"
placeholder="请选择区域经理">
</ti-select>
</ti-item>
<ti-item [label]="halfmodalOpts.data.companyName.label" [required]="false" [show]="true">
<input type="text" tiText style="width:300px" [(ngModel)]="halfmodalOpts.data.companyName.value">
</ti-item>
<ti-item [label]="halfmodalOpts.data.registeredCapital.label" [required]="false" [show]="true">
<input type="text" tiText style="width:300px" [(ngModel)]="halfmodalOpts.data.registeredCapital.value">
</ti-item>
<ti-item [label]="halfmodalOpts.data.customerContactPerson.label" [required]="false" [show]="true">
<input type="text" tiText style="width:300px" [(ngModel)]="halfmodalOpts.data.customerContactPerson.value">
</ti-item>
<ti-item [label]="halfmodalOpts.data.jobTitle.label" [required]="false" [show]="true">
<input type="text" tiText style="width:300px" [(ngModel)]="halfmodalOpts.data.jobTitle.value">
</ti-item>
<ti-item [label]="halfmodalOpts.data.customerLevel.label" [required]="false" [show]="true">
<ti-select
id="select-basic-regionalManager"
class="sj-shangji-formfield-width"
[options]="halfmodalOpts.data.customerLevel.options"
[(ngModel)]="halfmodalOpts.data.customerLevel.value"
placeholder="请选择客户等级">
</ti-select>
</ti-item>
<ti-item [label]="halfmodalOpts.data.salesType.label" [required]="false" [show]="true">
<ti-select
id="select-basic-regionalManager"
class="sj-shangji-formfield-width"
[options]="halfmodalOpts.data.salesType.options"
[(ngModel)]="halfmodalOpts.data.salesType.value"
placeholder="请选择类型">
</ti-select>
</ti-item>
<ti-item [label]="halfmodalOpts.data.intendedproduct.label" [required]="false" [show]="true">
<ti-select
id="select-basic-regionalManager"
class="sj-shangji-formfield-width"
[options]="halfmodalOpts.data.intendedproduct.options"
[(ngModel)]="halfmodalOpts.data.intendedproduct.value"
placeholder="请选择意向产品">
</ti-select>
</ti-item>
<ti-item [label]="halfmodalOpts.data.status.label" [required]="false" [show]="true">
<ti-select
id="select-basic-regionalManager"
class="sj-shangji-formfield-width"
[options]="halfmodalOpts.data.status.options"
[(ngModel)]="halfmodalOpts.data.status.value"
placeholder="请选择状态">
</ti-select>
</ti-item>
<ti-item [label]="halfmodalOpts.data.dealMoney.label" [required]="false" [show]="true">
<input type="text" tiText style="width:300px" [(ngModel)]="halfmodalOpts.data.dealMoney.value">
</ti-item>
<ti-item [label]="halfmodalOpts.data.dealTime.label" [required]="false" [show]="true">
<ti-date
class="mb-3"
id="date-basic-empty"
[(ngModel)]="halfmodalOpts.data.dealTime.value">
</ti-date>
</ti-item>
<ti-item [label]="halfmodalOpts.data.followUpDate.label" [required]="false" [show]="true">
<div class="sj-shangji-id">
{{halfmodalOpts.data.followUpDate.value}}
</div>
</ti-item>
</ti-formfield>
</ng-container>
</ti-halfmodal-body>
<ti-halfmodal-footer>
<button style="margin-right: 8px;" id="halfmodal-content-ok" tiButton color="danger" (click)="halfmodalOpts.ok()">确定</button>
<button id="halfmodal-content-cancel" tiButton (click)="halfmodalOpts.cancel()">取消</button>
</ti-halfmodal-footer>
</ti-halfmodal>
<button class="sj-shangji-filter-button" id="halfmodal-content-show" tiButton (click)="halfmodalOpts.create()">创建一条商机</button>
<button class="sj-shangji-filter-button" tiButton (click)="refreshLists()">全部商机</button>
<!--<button class="sj-shangji-filter-button" tiButton (click)="calNotFollow()">未跟进信息统计</button>-->
<button class="sj-shangji-filter-button" tiButton (click)="exportLists()" id="export">导出excel</button>
<div class="sj-shangji-filter-group">
<div class="sj-shangji-filter-group-label">条件过滤:</div>
<ti-select
id="select-multiple3"
class="sj-shangji-filter-group-item"
[options]="filterGroup.source.options"
[(ngModel)]="filterGroup.source.value"
[multiple]="true"
(select)="filterGroup.source.onSelect($event)"
(clear)="filterGroup.time.clear($event)"
[clearable]="true"
placeholder="请选择来源">
</ti-select>
<ti-select
id="select-multiple2"
class="sj-shangji-filter-group-item"
style="width: 250px;"
[options]="filterGroup.time.options"
[(ngModel)]="filterGroup.time.value"
(select)="filterGroup.time.onSelect($event)"
(clear)="filterGroup.time.clear($event)"
[clearable]="true"
[multiple]="true"
placeholder="请选择接入月份">
</ti-select>
<ti-select
id="select-multiple2"
class="sj-shangji-filter-group-item"
style="width: 150px;"
[options]="filterGroup.province.options"
[(ngModel)]="filterGroup.province.value"
(select)="filterGroup.province.onSelect($event)"
(clear)="filterGroup.province.clear($event)"
[clearable]="true"
[multiple]="true"
placeholder="请选择省份">
</ti-select>
<ti-select
id="select-multiple2"
class="sj-shangji-filter-group-item"
style="width: 150px;"
[options]="filterGroup.type.options"
[(ngModel)]="filterGroup.type.value"
(select)="filterGroup.type.onSelect($event)"
(clear)="filterGroup.type.clear($event)"
[clearable]="true"
[multiple]="true"
placeholder="请选择分类">
</ti-select>
<ti-select
id="select-multiple2"
class="sj-shangji-filter-group-item"
style="width: 250px;"
[options]="filterGroup.accessPeoples.options"
[(ngModel)]="filterGroup.accessPeoples.value"
(select)="filterGroup.accessPeoples.onSelect($event)"
(clear)="filterGroup.accessPeoples.clear($event)"
[clearable]="true"
[multiple]="true"
placeholder="请选择接入人">
</ti-select>
<ti-select
id="select-multiple2"
class="sj-shangji-filter-group-item"
style="width: 150px;"
[options]="filterGroup.regionalManager.options"
[(ngModel)]="filterGroup.regionalManager.value"
(select)="filterGroup.regionalManager.onSelect($event)"
(clear)="filterGroup.regionalManager.clear($event)"
[clearable]="true"
[multiple]="true"
placeholder="请选择接区域经理">
</ti-select>
<ti-select
id="select-multiple2"
class="sj-shangji-filter-group-item"
style="width: 150px;"
[options]="filterGroup.customerLevel.options"
[(ngModel)]="filterGroup.customerLevel.value"
(select)="filterGroup.customerLevel.onSelect($event)"
(clear)="filterGroup.customerLevel.clear($event)"
[clearable]="true"
[multiple]="true"
placeholder="请选择接客户等级">
</ti-select>
<ti-select
id="select-multiple2"
class="sj-shangji-filter-group-item"
style="width: 250px;"
[options]="filterGroup.salesType.options"
[(ngModel)]="filterGroup.salesType.value"
(select)="filterGroup.salesType.onSelect($event)"
(clear)="filterGroup.salesType.clear($event)"
[clearable]="true"
[multiple]="true"
placeholder="请选择销售类型">
</ti-select>
<ti-select
id="select-multiple2"
class="sj-shangji-filter-group-item"
style="width: 250px;"
[options]="filterGroup.intendedproduct.options"
[(ngModel)]="filterGroup.intendedproduct.value"
(select)="filterGroup.intendedproduct.onSelect($event)"
(clear)="filterGroup.intendedproduct.clear($event)"
[clearable]="true"
[multiple]="true"
placeholder="请选择意向产品">
</ti-select>
<ti-select
id="select-multiple2"
class="sj-shangji-filter-group-item"
style="width: 250px;"
[options]="filterGroup.status.options"
[(ngModel)]="filterGroup.status.value"
(select)="filterGroup.status.onSelect($event)"
(clear)="filterGroup.status.clear($event)"
[clearable]="true"
[multiple]="true"
placeholder="请选择接订单状态">
</ti-select>
</div>
<ti-table [srcData]="lists.srcData" [(displayedData)]="lists.displayedData" [columns]="lists.columns"
style="position: relative"
[tiColsResizable]='true'>
<ti-cols-toggle class="sj-shangji-lists-cols-toggle" [searchable]="lists.colsToggle.searchable" [selectAll]="lists.colsToggle.selectAll"></ti-cols-toggle>
<div class="ti3-resize-wrapper ti3-table-container">
<table>
<thead>
<tr>
<ng-container *ngFor="let column of lists.columns; index as i">
<th class="sj-shangji-filter-table-th" *ngIf="i === 0" details-icon-column>{{lists.columns[0].title}}</th>
<th class="sj-shangji-filter-table-th" *ngIf="i !== 0 && (column.show || column.show === undefined)"
[tiColumnFixed]="column.fixed"
width="{{column.width}}">
<ti-cell-text>{{column.title}}</ti-cell-text>
<ti-head-sort *ngIf="column.isSort" [sortKey]="column.sortKey"></ti-head-sort>
</th>
</ng-container>
</tr>
</thead>
<tbody>
<ng-container *ngFor="let row of lists.displayedData; index as i">
<tr>
<td details-icon-column>
<ti-details-icon [row]="row" [index]="i"></ti-details-icon>
</td>
<td *ngIf="lists.columns[1].show" tiOverflow>{{row.id}}</td>
<td *ngIf="lists.columns[2].show" tiOverflow>{{row.source}}</td>
<td *ngIf="lists.columns[3].show" tiOverflow>{{row.time | date:'yyyy.MM.dd HH:mm'}}</td>
<td *ngIf="lists.columns[4].show" tiOverflow>{{row.province}}</td>
<td *ngIf="lists.columns[5].show" tiOverflow>{{row.contactInformation}}</td>
<td *ngIf="lists.columns[6].show" tiOverflow>{{row.type}}</td>
<td *ngIf="lists.columns[7].show" tiOverflow>{{row.accessPeoples}}</td>
<td *ngIf="lists.columns[8].show" tiOverflow>{{row.regionalManager}}</td>
<td *ngIf="lists.columns[9].show" tiOverflow>{{row.companyName}}</td>
<td *ngIf="lists.columns[10].show" tiOverflow>{{row.registeredCapital}}</td>
<td *ngIf="lists.columns[11].show" tiOverflow>{{row.customerContactPerson}}</td>
<td *ngIf="lists.columns[12].show" tiOverflow>{{row.jobTitle}}</td>
<td *ngIf="lists.columns[13].show" tiOverflow>{{row.customerLevel}}</td>
<td *ngIf="lists.columns[14].show" tiOverflow>{{row.salesType}}</td>
<td *ngIf="lists.columns[15].show" tiOverflow>{{row.intendedproduct}}</td>
<td *ngIf="lists.columns[16].show" tiOverflow>{{row.status}}</td>
<td *ngIf="lists.columns[17].show" tiOverflow>{{row.dealMoney}}</td>
<td *ngIf="lists.columns[18].show" tiOverflow>{{row.dealTime | date:'yyyy.MM.dd'}}</td>
<td *ngIf="lists.columns[19].show" tiOverflow>{{row.followUpDate | date:'yyyy.MM.dd HH:mm'}}</td>
<td tiColumnFixed="right">
<ti-actionmenu [items]="lists.actions.editingItems" (select)="lists.actions.onSelectEditing($event, row)"></ti-actionmenu>
</td>
</tr>
<tr *tiDetailsTr="row">
<td tiColspan>
<div class="ti3-table-detail-container">
<div class="sj-shangji-follow-label">跟进信息记录:</div>
<ng-container *ngFor="let f of row.followUpInformation; index as j">
<div>{{f.time | date:'yyyy.MM.dd HH:mm'}} : {{f.contents}}</div>
</ng-container>
<div class="sj-shangji-add-follow-information">
<div class="sj-shangji-add-follow-information-label">增加新的跟进记录:</div>
<input type="text" tiText style="width:700px;" [(ngModel)]="lists.newFollow.value">
<button tiButton color="danger" (click)="lists.newFollow.add(row)">添加</button>
</div>
</div>
</td>
</tr>
</ng-container>
</tbody>
</table>
</div>
<ti-pagination [(currentPage)]="lists.pagination.currentPage" [pageSize]="lists.pagination.pageSize" [(totalNumber)]="lists.pagination.totalNumber"></ti-pagination>
</ti-table>
4.2 shangji.component.ts
import {Component, OnInit, ViewChild, Inject, LOCALE_ID} from '@angular/core';
import {TiHalfmodalComponent} from '@opentiny/ng';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {formatDate} from '@angular/common';
import {expoerExcel} from "./excelOpt";
import {Constants} from "../constants";
declare var window: any;
@Component({
selector: 'app-shangji',
templateUrl: './shangji.component.html',
styleUrls: ['./shangji.component.less']
})
export class ShangjiComponent implements OnInit {
public lists: any;
@ViewChild('halfmodal', {static: true}) halfmodal!: TiHalfmodalComponent;
public halfmodalOpts: any;
public filterGroup: any;
constructor(
@Inject(LOCALE_ID) public locale: string,
private http: HttpClient,
) {
}
ngOnInit(): void {
this.initListTable();
this.initHalfmodal();
this.initFilterGroup();
}
private initFilterGroup(): void {
this.filterGroup = {};
this.filterGroup.source = {
options: Constants.source,
value: [],
onSelect: (option: any) => {
this.filterListsTable();
},
clear: (option: any) => {
this.filterListsTable();
},
};
this.filterGroup.time = {
options: Constants.time,
value: [],
onSelect: (option: any) => {
this.filterListsTable();
},
clear: (option: any) => {
this.filterListsTable();
},
};
this.filterGroup.province = {
options: Constants.province,
value: [],
onSelect: (option: any) => {
this.filterListsTable();
},
clear: (option: any) => {
this.filterListsTable();
},
};
this.filterGroup.type = {
options: Constants.type,
value: [],
onSelect: (option: any) => {
this.filterListsTable();
},
clear: (option: any) => {
this.filterListsTable();
},
};
this.filterGroup.accessPeoples = {
options: Constants.accessPeoples,
value: [],
onSelect: (option: any) => {
this.filterListsTable();
},
clear: (option: any) => {
this.filterListsTable();
},
};
this.filterGroup.regionalManager = {
options: Constants.regionalManager,
value: [],
onSelect: (option: any) => {
this.filterListsTable();
},
clear: (option: any) => {
this.filterListsTable();
},
};
this.filterGroup.customerLevel = {
options: Constants.customerLevel,
value: [],
onSelect: (option: any) => {
this.filterListsTable();
},
clear: (option: any) => {
this.filterListsTable();
},
};
this.filterGroup.salesType = {
options: Constants.salesType,
value: [],
onSelect: (option: any) => {
this.filterListsTable();
},
clear: (option: any) => {
this.filterListsTable();
},
};
this.filterGroup.intendedproduct = {
options: Constants.intendedproduct,
value: [],
onSelect: (option: any) => {
this.filterListsTable();
},
clear: (option: any) => {
this.filterListsTable();
},
};
this.filterGroup.status = {
options: Constants.status,
value: [],
onSelect: (option: any) => {
this.filterListsTable();
},
clear: (option: any) => {
this.filterListsTable();
},
};
setTimeout(() => {
this.filterGroup.accessPeoples.options = window.sj.accessPeoples;
this.filterGroup.regionalManager.options = window.sj.regionalManager;
}, 3000);
}
private filterListsTable(): void {
const destData: any = [];
this.lists.allData.forEach((v: any) => {
if (
this.isMatch(v.source, this.filterGroup.source.value)
&& this.isMatch(v.time, this.filterGroup.time.value)
&& this.isMatch(v.province, this.filterGroup.province.value)
&& this.isMatch(v.type, this.filterGroup.type.value)
&& this.isMatch(v.accessPeoples, this.filterGroup.accessPeoples.value)
&& this.isMatch(v.regionalManager, this.filterGroup.regionalManager.value)
&& this.isMatch(v.customerLevel, this.filterGroup.customerLevel.value)
&& this.isMatch(v.salesType, this.filterGroup.salesType.value)
&& this.isMatch(v.intendedproduct, this.filterGroup.intendedproduct.value)
&& this.isMatch(v.status, this.filterGroup.status.value)
) {
destData.push(v);
}
});
this.lists.srcData.data = this.changeListData(destData);
this.lists.displayedData = this.lists.srcData.data;
this.lists.pagination.totalNumber = this.lists.srcData.data.length;
}
private isMatch(value: any, option: any) {
if (option.length === 0) {
return true;
}
let isMatch = false;
option.forEach((o: any) => {
if (o.label === value) {
isMatch = true;
}
});
return isMatch;
}
private initListTable(): void {
this.lists = {
allData: [],
displayedData: [],
srcData: {
data: [],
state: undefined
},
columns: [
{
title: ''
},
{
title: '编号',
show: false,
sortKey: 'id',
width: '110px',
},
{
title: '来源',
show: true,
sortKey: 'source',
width: '60px',
},
{
title: '首次接入日期',
show: true,
sortKey: 'time',
width: '120px',
isSort: true,
},
{
title: '省',
show: true,
sortKey: 'province',
width: '70px',
},
{
title: '联系方式',
show: true,
sortKey: 'contactInformation',
width: '100px',
},
{
title: '分类',
show: true,
sortKey: 'type',
width: '60px',
},
{
title: '接入人',
show: true,
sortKey: 'accessPeoples',
width: '60px',
},
{
title: '区域经理',
show: true,
sortKey: 'regionalManager',
width: '100px',
},
{
title: '公司名称',
show: true,
sortKey: 'companyName',
width: '100px',
},
{
title: '注册资金',
show: false,
sortKey: 'registeredCapital',
width: '100px',
},
{
title: '客户联系人',
show: true,
sortKey: 'customerContactPerson',
width: '100px',
},
{
title: '职务',
show: false,
sortKey: 'jobTitle',
width: '100px',
},
{
title: '客户等级',
show: true,
sortKey: 'customerLevel',
width: '100px',
},
{
title: '类型',
show: true,
sortKey: 'salesType',
width: '100px',
},
{
title: '意向产品',
show: true,
sortKey: 'intendedproduct',
width: '100px',
},
{
title: '商机状态',
show: true,
sortKey: 'status',
width: '100px',
},
{
title: '成交金额(元)',
show: true,
sortKey: 'dealMoney',
width: '120px',
isSort: true,
},
{
title: '成交时间',
show: true,
sortKey: 'dealTime',
width: '120px',
isSort: true,
},
{
title: '跟进日期',
show: true,
sortKey: 'followUpDate',
width: '100px',
},
{
title: '操作',
show: true,
width: '100px',
fixed: 'right',
},
],
colsToggle: {
searchable: true,
selectAll: true,
},
actions: {
editingItems: [
{
label: '编辑'
},
{
label: '删除',
disabled: window.sj.userType !== 'adm'
},
],
onSelectEditing: (item: any, row: any) => {
if (item.label === '编辑') {
this.halfmodalOpts.edit(row);
}
if (item.label === '删除') {
this.deleteListData(row);
}
},
},
pagination: {
currentPage: 1,
totalNumber: 0,
pageSize: {
options: [5, 10, 20, 40, 50, 100],
size: 10
}
},
newFollow: {
value: '',
add: (row: any) => {
this.addNewFollowInformation(row);
},
}
};
this.setListTableData();
}
private addNewFollowInformation(row: any): void {
if (!row.followUpInformation) {
row.followUpInformation = [];
}
const time = formatDate(Date.now(), 'yyyy.MM.dd HH:mm', this.locale);
row.followUpInformation.push({
"time": time,
"contents": this.lists.newFollow.value,
});
row.followUpDate = time;
this.http.put('./sj/shangji/list/edit', row).subscribe((data: any) => {
}, (error: any) => {
console.log('error');
});
}
private deleteListData(listData: any): void {
this.http.put('./sj/shangji/list/del', listData).subscribe((data: any) => {
this.setListTableData();
}, (error: any) => {
console.log('error');
});
}
private setListTableData(): void {
this.http.get('./sj/shangji/list', {
params: {name: 11, id: 233}
}).subscribe((data: any) => {
console.log(data);
data.forEach((row: any) => {
row.showDetails = false;
})
this.lists.srcData.data = this.changeListData(data);
this.lists.displayedData = this.lists.srcData.data;
this.lists.pagination.totalNumber = this.lists.srcData.data.length;
this.lists.allData = this.lists.srcData.data;
}, (error: any) => {
});
}
private changeListData(srcData: any): void {
const listTableData = srcData;
return listTableData;
}
private addNewOrEditShangJi(type: any): void {
const srcData = this.halfmodalOpts.data;
const newData = {
"id": srcData.id.value,
"source": srcData.source.value,
"time": srcData.time.value,
"province": srcData.province.value.label,
"contactInformation": srcData.contactInformation.value,
"type": srcData.type.value.label,
"regionalManager": srcData.regionalManager.value.label,
"accessPeoples": srcData.accessPeoples.value.label,
"companyName": srcData.companyName.value,
"registeredCapital": srcData.registeredCapital.value,
"customerContactPerson": srcData.customerContactPerson.value,
"jobTitle": srcData.jobTitle.value,
"customerLevel": srcData.customerLevel.value.label,
"salesType": srcData.salesType.value.label,
"intendedproduct": srcData.intendedproduct.value.label,
"status": srcData.status.value.label,
"dealMoney": srcData.dealMoney.value,
"dealTime": formatDate(srcData.dealTime.value, 'yyyy.MM.dd', this.locale),
"followUpDate": srcData.followUpDate.value,
"followUpInformation": srcData.followUpInformation,
"showDetails": false,
};
console.log(newData)
if (type === 'create') {
this.http.put('./sj/shangji/list/create', newData).subscribe((data: any) => {
this.setListTableData();
}, (error: any) => {
console.log('error');
});
return;
}
if (type === 'edit') {
this.http.put('./sj/shangji/list/edit', newData).subscribe((data: any) => {
this.setListTableData();
}, (error: any) => {
console.log('error');
});
}
}
private initHalfmodal(): void {
this.halfmodalOpts = {};
this.halfmodalOpts.type = 'create'; // or 'edit'
this.halfmodalOpts.show = false;
this.halfmodalOpts.create = () => {
this.halfmodalOpts.type = 'create';
this.createNewShangJi();
this.halfmodal.show();
this.halfmodalOpts.show = true;
};
this.halfmodalOpts.edit = (data: any) => {
this.halfmodalOpts.type = 'edit';
this.createNewShangJi();
console.log(data);
this.setHalfmodalOptsData(data);
this.halfmodal.show();
this.halfmodalOpts.show = true;
};
this.halfmodalOpts.ok = () => {
if (this.halfmodalOpts.type === 'create') {
this.addNewOrEditShangJi('create');
}
if (this.halfmodalOpts.type === 'edit') {
this.addNewOrEditShangJi('edit');
}
this.halfmodal.hide();
this.halfmodalOpts.show = false;
};
this.halfmodalOpts.cancel = () => {
this.halfmodal.hide();
this.halfmodalOpts.show = false;
};
}
private createNewShangJi() {
const data: any = {};
data.id = {
label: '编号',
value: Date.now(),
};
data.source = {
label: '来源',
value: '',
};
data.time = {
label: '首次接入日期',
value: formatDate(Date.now(), 'yyyy.MM.dd HH:mm', this.locale),
};
data.province = {
label: '省',
value: '',
options: Constants.province,
onSelect: (value: any) => {
window.sj.provinceAndManager.forEach((v: any) => {
if (v.province === value.label) {
this.halfmodalOpts.data.regionalManager.value = {
label: v.regionalManager
};
}
});
}
};
data.contactInformation = {
label: '联系方式',
value: '',
};
data.type = {
label: '分类',
value: '',
options: Constants.type
};
data.regionalManager = {
label: '区域经理',
value: '',
options: window.sj.regionalManager,
};
data.accessPeoples = {
label: '接入人',
value: '',
options: window.sj.accessPeoples,
};
data.companyName = {
label: '公司名称',
value: '',
};
data.registeredCapital = {
label: '注册资金',
value: '',
};
data.customerContactPerson = {
label: '客户联系人',
value: '',
};
data.jobTitle = {
label: '职务',
value: '',
};
data.customerLevel = {
label: '客户等级',
value: '',
options: Constants.customerLevel
};
data.salesType = {
label: '类型',
value: '',
options: Constants.salesType
};
data.intendedproduct = {
label: '意向产品',
value: '',
options: [
{
label: '原料',
},
{
label: '成品',
},
{
label: '贴牌',
},
{
label: '其它',
},
]
};
data.status = {
label: '商机状态',
value: '',
options: [
{
label: '跟进中',
},
{
label: '已成交',
},
{
label: '不跟进',
},
{
label: '无效(确定无成交可能)',
},
]
};
data.dealMoney = {
label: '成交金额',
value: '',
};
data.dealTime = {
label: '成交时间',
format: 'yyyy.MM.dd',
value: '',
};
data.followUpDate = {
label: '跟进日期',
value: '',
};
data.followUpInformation = [];
this.halfmodalOpts.data = data;
}
private setHalfmodalOptsData(srcData: any) {
const data = this.halfmodalOpts.data;
data.id.value = srcData.id;
data.source.value = srcData.source;
data.time.value = srcData.time;
data.province.value = {label: srcData.province};
data.contactInformation.value = srcData.contactInformation;
data.type.value = {label: srcData.type};
data.regionalManager.value = {label: srcData.regionalManager};
data.accessPeoples.value = {label: srcData.accessPeoples};
data.companyName.value = srcData.companyName;
data.registeredCapital.value = srcData.registeredCapital;
data.customerContactPerson.value = srcData.customerContactPerson;
data.jobTitle.value = srcData.jobTitle;
data.customerLevel.value = {label: srcData.customerLevel};
data.salesType.value = {label: srcData.salesType};
data.intendedproduct.value = {label: srcData.intendedproduct};
data.status.value = {label: srcData.status};
data.dealMoney.value = srcData.dealMoney;
data.dealTime.value = new Date(srcData.dealTime),
data.followUpDate.value = srcData.followUpDate;
data.followUpInformation = srcData.followUpInformation;
console.log(data)
}
public calNotFollow() {
this.setListFilterData('followUpDate', '');
}
private setListFilterData(key: any, value: any) {
this.http.get('./sj/shangji/list').subscribe((data: any) => {
console.log(data);
const newData: any = [];
data.forEach((row: any) => {
row.showDetails = false;
if (row[key] === value) {
newData.push(row);
}
})
this.lists.srcData.data = this.changeListData(newData);
this.lists.displayedData = this.lists.srcData.data;
this.lists.pagination.totalNumber = this.lists.srcData.data.length;
}, (error: any) => {
});
}
public refreshLists() {
this.setListTableData();
}
public exportLists() {
// const header:any= ['name', 'id'];
// const body:any = [['zhao', 2],['ma', 3]];
// const name:any = '数据导出';
const header: any = this.getExportTableHeader();
const body: any = this.getExportTableBody();
const name: any = formatDate(Date.now(), 'yyyy.MM.dd HH:mm', this.locale);
expoerExcel(header, body, name);
}
public getExportTableHeader() {
const header = [];
const columns = this.lists.columns;
for (let i = 1; i < columns.length - 1; i++) {
header.push(columns[i].title);
}
return header;
}
public getExportTableBody() {
const body = [];
const columns = this.lists.columns;
const data = this.lists.srcData.data;
for (let i = 0; i < data.length; i++) {
const row = [];
for (let j = 1; j < columns.length - 1; j++) {
row.push(data[i][columns[j].sortKey]);
}
data[i].followUpInformation.forEach((f: any) => {
console.log(this.locale)
row.push(formatDate(f.time, 'yyyy.MM.dd HH:mm', this.locale) + ' : ' + f.contents);
});
body.push(row);
}
return body;
}
}
4.3 shangji.component.less
.sj-shangji-id {
display: inline-block;
line-height: 27px;
}
.sj-shangji-formfield-width {
width: 300px;
}
.sj-shangji-lists-cols-toggle {
position: absolute;
top: -40px;
right: 14px;
display: inline-block;
}
.sj-shangji-follow-label {
font-size: 14px;
font-weight: bold;
}
.sj-shangji-add-follow-information {
display: inline-block;
font-size: 14px;
font-weight: bold;
}
.sj-shangji-add-follow-information-label {
display: inline-block;
}
.sj-shangji-filter-button {
margin: 5px;
}
.sj-shangji-filter-table-th {
background-color: #7495e0 !important;
color: #0a0a0a !important;
font-size: 14px;
}
.sj-shangji-filter-group {
margin-top: 15px;
margin-bottom: 15px;
margin-left: 3px;
}
.sj-shangji-filter-group-label {
font-size: 14px;
font-weight: bold;
display: inline-block;
}
::ng-deep .ti3-icon-clear:before {
display: none !important;
}
::ng-deep .ti3-icon-close-staic {
height: 1px !important;
}
.sj-shangji-filter-group-item {
display: inline-block;
//width: 400px;
margin-bottom: 10px;
margin-right: 20px;
}
4.4 constants.ts
declare var window: any;
const Constants: any = {};
Constants.source = [
{ label : '阿里'},
{ label : '百度'},
{ label : '自开发'},
{ label : '其它'},
];
Constants.time = [
{ label: '2023.12',},
{ label: '2023.11',},
{ label: '2023.10',},
{ label: '2023.09',},
{ label: '2023.08',},
{ label: '2023.07',},
{ label: '2023.06',},
{ label: '2023.05',},
{ label: '2023.04',},
{ label: '2023.03',},
{ label: '2023.02',},
{ label: '2023.01',},
{ label: '2022.12',},
{ label: '2022.11',},
{ label: '2022.10',},
{ label: '2022.09',},
{ label: '2022.08',},
{ label: '2022.07',},
{ label: '2022.06',},
{ label: '2022.05',},
{ label: '2022.04',},
{ label: '2022.03',},
{ label: '2022.02',},
{ label: '2022.01',},
{ label: '2021.12',},
{ label: '2021.11',},
{ label: '2021.10',},
{ label: '2021.09',},
{ label: '2021.08',},
{ label: '2021.07',},
{ label: '2021.06',},
{ label: '2021.05',},
{ label: '2021.04',},
{ label: '2021.03',},
{ label: '2021.02',},
{ label: '2021.01',},
];
Constants.province = [
{
"label": "北京市"
},
{
"label": "天津市"
},
{
"label": "上海市"
},
{
"label": "重庆市"
},
{
"label": "河北省"
},
{
"label": "河南省"
},
{
"label": "云南省"
},
{
"label": "辽宁省"
},
{
"label": "黑龙江省"
},
{
"label": "湖南省"
},
{
"label": "安徽省"
},
{
"label": "山东省"
},
{
"label": "新疆维吾尔"
},
{
"label": "江苏省"
},
{
"label": "浙江省"
},
{
"label": "江西省"
},
{
"label": "湖北省"
},
{
"label": "广西壮族"
},
{
"label": "甘肃省"
},
{
"label": "山西省"
},
{
"label": "内蒙古"
},
{
"label": "陕西省"
},
{
"label": "吉林省"
},
{
"label": "福建省"
},
{
"label": "贵州省"
},
{
"label": "广东省"
},
{
"label": "青海省"
},
{
"label": "西藏"
},
{
"label": "四川省"
},
{
"label": "宁夏"
},
{
"label": "海南省"
},
{
"label": "台湾省"
},
{
"label": "香港"
},
{
"label": "澳门"
},
{
"label": "其它"
}
];
Constants.type = [
{
label: '零售',
},
{
label: '经销',
},
{
label: '其它',
},
];
Constants.accessPeoples = window.sj?.accessPeoples || [];
Constants.regionalManager = window.sj?.regionalManager || [];
Constants.customerLevel = [
{
label: 'A',
},
{
label: 'B',
},
{
label: 'C',
},
{
label: 'D',
},
{
label: 'E',
},
];
Constants.salesType = [
{
label: '经销商',
},
{
label: '代理',
},
{
label: '直播',
},
{
label: '其它',
},
];
Constants.intendedproduct = [
{
label: '原料',
},
{
label: '成品',
},
{
label: '贴牌',
},
{
label: '其它',
},
];
Constants.status = [
{
label: '跟进中',
},
{
label: '已成交',
},
{
label: '不跟进',
},
{
label: '无效(确定无成交可能)',
},
];
export { Constants };
4.4 app.component.ts
import {Component, Inject, LOCALE_ID, OnInit} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Constants} from "./page/constants";
declare var window: any;
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.less']
})
export class AppComponent implements OnInit{
title = 'shaji-console';
public isLogin: any = false;
public login:any = {
userName: '',
password: '',
};
constructor(
private http: HttpClient,
) {
}
ngOnInit(): void {
window.sj = {
isLogin: false,
userType: 'guest',
regionalManager: [],
provinceAndManager: [],
accessPeoples: [],
};
this.initLogin();
this.initRegionalManager();
this.initAccessPeoples();
}
private initRegionalManager() {
this.http.get('./sj/users', {
params: { userType : window.sj.userType }
}).subscribe((data: any) => {
this.setManagerProvinces(data.provinceAndManager);
}, (error: any) => {
});
}
private setManagerProvinces(data: any) {
const ma = new Map();
data.forEach((d:any) => {
if (ma.get(d.regionalManager)) {
ma.set(d.regionalManager, ma.get(d.regionalManager) + ' ' + d.province);
} else {
ma.set(d.regionalManager, d.province);
}
});
for( let m of ma.keys()) {
window.sj.regionalManager.push({
label: m
});
}
window.sj.provinceAndManager = data;
Constants.regionalManager = window.sj.regionalManager;
}
private initAccessPeoples() {
this.http.get('./sj/users/accessPeoples', {
}).subscribe((data: any) => {
window.sj.accessPeoples = data;
Constants.accessPeoples = window.sj.accessPeoples;
console.log(data)
}, (error: any) => {
});
}
private initLogin() {
// 如果cookie中有登陆信息,将这些信息设置到window全局变量中,并且重新刷新cookie的超时时间
if (this.getCookie('isLogin') === 'true') {
this.isLogin = true;
window.sj.userType = this.getCookie('userType');
window.sj.isLogin = true;
this.setSjCoolie();
}
this.login.ok = () => {
this.setUser({
name: this.login.userName,
password: this.login.password
});
}
}
private setUser(user: any) {
this.http.get('./sj/me', {
params: { name : user.name, password: user.password}
}).subscribe((data: any) => {
if (data.userType === 'adm') {
this.isLogin = true;
} else if (data.userType === 'common') {
this.isLogin = true;
} else {
this.isLogin = false;
alert('登陆失败:用户名或者二密码不对');
}
window.sj.userType = data.userType;
window.sj.isLogin = this.isLogin;
this.setSjCoolie();
console.log(data);
}, (error: any) => {
alert('登陆失败:用户名或者二密码不对');
});
}
private setSjCoolie() {
this.setCookie('isLogin', window.sj.isLogin, 0.5);
this.setCookie('userType', window.sj.userType, 0.5);
}
private setCookie(cname: any, cvalue: any, exdays: any) {
var d:any = new Date();
d.setTime(d.getTime()+(exdays*24*60*60*1000));
var expires = "expires="+ d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires;
}
private getCookie(cname:any) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++)
{
var c = ca[i].trim();
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
}
return "";
}
}