[init] init version
This commit is contained in:
16
.editorconfig
Normal file
16
.editorconfig
Normal file
@@ -0,0 +1,16 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
42
.gitignore
vendored
Normal file
42
.gitignore
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/bazel-out
|
||||
|
||||
# Node
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# IDEs and editors
|
||||
.idea/
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# Miscellaneous
|
||||
/.angular/cache
|
||||
.sass-cache/
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
4
.vscode/extensions.json
vendored
Normal file
4
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
||||
"recommendations": ["angular.ng-template"]
|
||||
}
|
||||
20
.vscode/launch.json
vendored
Normal file
20
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ng serve",
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: start",
|
||||
"url": "http://localhost:4200/"
|
||||
},
|
||||
{
|
||||
"name": "ng test",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: test",
|
||||
"url": "http://localhost:9876/debug.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
42
.vscode/tasks.json
vendored
Normal file
42
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "start",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "(.*?)"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation complete"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "test",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "(.*?)"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation complete"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
161
@note/input.html
Normal file
161
@note/input.html
Normal file
@@ -0,0 +1,161 @@
|
||||
------------------------------------------------------------
|
||||
# INPUT
|
||||
------------------------------------------------------------
|
||||
<mat-label></mat-label>
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
name="KEY"
|
||||
#KEY="ngModel"
|
||||
[(ngModel)]="dataForm.KEY"
|
||||
required
|
||||
>
|
||||
<mat-error *ngIf="isFieldValid(ngf, KEY)"> กรุณากรอกข้อมูล</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
------------------------------------------------------------
|
||||
# textarea
|
||||
------------------------------------------------------------
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label></mat-label>
|
||||
<textarea
|
||||
matInput
|
||||
name="KEY"
|
||||
#KEY="ngModel"
|
||||
[(ngModel)]="dataForm.KEY"
|
||||
required
|
||||
>
|
||||
</textarea>
|
||||
<mat-error *ngIf="isFieldValid(ngf, KEY)"> กรุณากรอกข้อมูล</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
# SELECT
|
||||
------------------------------------------------------------
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label></mat-label>
|
||||
<mat-select
|
||||
name="KEY"
|
||||
#KEY="ngModel"
|
||||
[(ngModel)]="dataForm.KEY"
|
||||
required
|
||||
>
|
||||
<mat-option [value]=""></mat-option>
|
||||
<mat-option
|
||||
*ngFor="let item of select.KEY"
|
||||
[value]="item.KEY">
|
||||
{{item.KEY}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="isFieldValid(ngf, KEY)"> กรุณากรอกข้อมูล</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
# SELECT 2
|
||||
------------------------------------------------------------
|
||||
|
||||
<mat-label></mat-label>
|
||||
<ng-select
|
||||
name="budget_year_uid"
|
||||
#KEY="ngModel"
|
||||
[(ngModel)]="dataForm.KEY"
|
||||
(change)="onSelect()"
|
||||
appendTo="body"
|
||||
required
|
||||
>
|
||||
<ng-option value=""></ng-option>
|
||||
<ng-option
|
||||
*ngFor="let item of select.KEY"
|
||||
[value]="item.KEY">
|
||||
{{item.KEY}}
|
||||
</ng-option>
|
||||
</ng-select>
|
||||
<mat-error *ngIf="isFieldValid(ngf, KEY)"> กรุณากรอกข้อมูล</mat-error>
|
||||
|
||||
<mat-label></mat-label>
|
||||
<ng-select
|
||||
#KEY="ngModel"
|
||||
(change)="onSelectionChange('KEY',$event)"
|
||||
[(ngModel)]="dataForm.KEY"
|
||||
[items]="select.KEY"
|
||||
appendTo="body"
|
||||
bindLabel="KEY"
|
||||
bindValue="KEY"
|
||||
name="KEY"
|
||||
>
|
||||
</ng-select>
|
||||
<mat-error *ngIf="isFieldValid(ngf, KEY)"> กรุณากรอกข้อมูล</mat-error>
|
||||
|
||||
------------------------------------------------------------
|
||||
# AUTOCOMPLETE
|
||||
------------------------------------------------------------
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label></mat-label>
|
||||
<input
|
||||
matInput
|
||||
name="KEY"
|
||||
#KEY="ngModel"
|
||||
[(ngModel)]="dataForm.KEY"
|
||||
[matAutocomplete]="MATAUTO"
|
||||
>
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
</mat-form-field>
|
||||
<mat-autocomplete #MATAUTO="matAutocomplete" autoActiveFirstOption>
|
||||
<mat-option
|
||||
(onSelectionChange)="onSelectionChange('KEY', item)"
|
||||
*ngFor="let item of select.KEY | searchAuto : dataForm.KEY : 'KEY'"
|
||||
[value]="item.KEY">
|
||||
{{item.KEY}}
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
|
||||
------------------------------------------------------------
|
||||
# DATEPICKER
|
||||
------------------------------------------------------------
|
||||
<mat-form-field>
|
||||
<mat-label>วันที่</mat-label>
|
||||
<input
|
||||
matInput
|
||||
name="KEY"
|
||||
#KEY="ngModel"
|
||||
(click)="dpkName.open()"
|
||||
[(ngModel)]="dataForm.KEY"
|
||||
[matDatepicker]="dpkName"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
<mat-datepicker-toggle [for]="dpkName" matSuffix></mat-datepicker-toggle>
|
||||
<mat-datepicker #dpkName></mat-datepicker>
|
||||
<mat-error *ngIf="isFieldValid(ngf, KEY)"> กรุณากรอกข้อมูล</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
# DIALOG
|
||||
------------------------------------------------------------
|
||||
<form #ngf="ngForm" (ngSubmit)="onSubmit(ngf)" autocomplete="off" class="dialog-main dialog-form ">
|
||||
<div class="dialog-main">
|
||||
<div class="dialog-header">
|
||||
<h2>{{title}}</h2>
|
||||
</div>
|
||||
<div class="dialog-body">
|
||||
|
||||
|
||||
</div>
|
||||
<div class="dialog-footer">
|
||||
<button cdkFocusInitial mat-dialog-close mat-raised-button type="button">ยกเลิก</button>
|
||||
<button class="bg-bpi-primary-color" color="primary" mat-raised-button type="submit">บันทึก</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
# ICON LINK
|
||||
------------------------------------------------------------
|
||||
<i [routerLink]="['/app/research-and-evaluation/evaluate-collect/send', item.budget_policy_uid]" class="material-icons" style="cursor: pointer;color: #F8A300;">create</i>
|
||||
140
@note/note.txt
Normal file
140
@note/note.txt
Normal file
@@ -0,0 +1,140 @@
|
||||
ประเมินราคา/ค่ามัดจำ
|
||||
ประเมินราคาครั้งที่ 1
|
||||
ประเมินราคาครั้งที่ 2
|
||||
ประเมินราคาครั้งที่ 3
|
||||
การเงิน
|
||||
ใบเสนอราคา
|
||||
ใบแจ้งชำระเงิน
|
||||
ใบแจ้งหนี้
|
||||
รับชำระเงิน/ใบเสร็จรับเงิน
|
||||
คืนเงินค่ามัดจำ
|
||||
สัญญา
|
||||
ทำสัญญา
|
||||
ข้อมูลการผ่อนชำระ
|
||||
คลังสินค้า
|
||||
สินค้า
|
||||
ค่าเบี่ยงเบนการวัด
|
||||
ยี่ห้อ
|
||||
หมวดหมู่
|
||||
ตั้งค่าระบบ
|
||||
ลูกค้า
|
||||
|
||||
|
||||
Appraisals
|
||||
AppraisalP1
|
||||
AppraisalP2
|
||||
AppraisalP3
|
||||
finance
|
||||
quotation
|
||||
bill payment
|
||||
invoice
|
||||
Receive payment/receipt
|
||||
refund deposit
|
||||
contract
|
||||
make a contract
|
||||
installment information
|
||||
warehouse
|
||||
product
|
||||
measurement deviation
|
||||
brand
|
||||
category
|
||||
system settings
|
||||
customer(แก้ไขแล้ว)เรียกคืนต้นฉบับ
|
||||
|
||||
'code','name','brandId','size','color','year','price','latestPrice',
|
||||
|
||||
|
||||
กรอกข้อมูลการจัดผ่อน (ราคาล่าสุด 257,000.00 บาท)
|
||||
วันที่เริ่มจัดผ่อน
|
||||
8/03/2023
|
||||
บาท (THB)
|
||||
ราคา (Price)
|
||||
499,999.00
|
||||
บาท (THB)
|
||||
มัดจำแม่ค้า
|
||||
0.00
|
||||
บาท (THB)
|
||||
มัดจำ CMFS
|
||||
150,000.00
|
||||
บาท (THB)
|
||||
เงินต้นคงเหลือ (Total)
|
||||
349,000.00
|
||||
บาท (THB)
|
||||
ต้องการผ่อน (Term)
|
||||
3
|
||||
งวด
|
||||
ล้างข้อมูล
|
||||
คำนวน
|
||||
|
||||
|
||||
รายละเอียดค่าใช้จ่ายในการโอนเงิน
|
||||
มัดจำ CMFS Deposit
|
||||
150,000.00
|
||||
บาท (THB)
|
||||
หัก เงินมัดจำแม่ค้า
|
||||
0.00
|
||||
บาท (THB)
|
||||
บวก Packing
|
||||
500.00
|
||||
บาท (THB)
|
||||
บวก Luxury handbag
|
||||
authentication
|
||||
3,500.00
|
||||
บาท (THB)
|
||||
บวก Bank fee,
|
||||
Insurance , Storage
|
||||
200.00
|
||||
บาท (THB)
|
||||
สรุปยอดโอน
|
||||
154,200.00
|
||||
บาท (THB)
|
||||
|
||||
งวดที่
|
||||
กำหนดจ่ายวันที่ Due date
|
||||
เงินต้น
|
||||
Principle
|
||||
ดอกเบี้ย(บาท)
|
||||
Interest Total
|
||||
Bank fee, Insurance ,Storage
|
||||
รวมยอดจ่ายต่อเดือน Total payment
|
||||
เงินต้นคงเหลือ Principle Total
|
||||
|
||||
|
||||
ข้อมูลลูกค้า
|
||||
ชื่อลูกค้า
|
||||
นามสกุล
|
||||
เบอร์โทร
|
||||
นางสาวน้ำค้าง
|
||||
ทดสอบศรี
|
||||
0896765555
|
||||
รหัสสินค้า
|
||||
เลขที่ใบเสนอราคา
|
||||
A660092
|
||||
As00022
|
||||
ชื่อพนักงาน
|
||||
นางสาวปาดวาด ศิริทรัพย์
|
||||
|
||||
|
||||
customerFirstName
|
||||
customerLastName
|
||||
customerPhone
|
||||
customerIdentificationCard
|
||||
customerIdentificationCardImage
|
||||
customerAddress
|
||||
customerEmail
|
||||
customerLine
|
||||
customerLineShop
|
||||
customerFacebook
|
||||
customerOccupation: string;
|
||||
|
||||
customerIg
|
||||
|
||||
|
||||
<button type="button" class="btn btn-export" (click)="onExport()">Export</button>
|
||||
|
||||
|
||||
onExport() {
|
||||
const filter = generateParamsValue(this.dataFilter);
|
||||
const url = `${API.customer}/export?${filter ? '&' + filter : '' }`;
|
||||
window.open(url);
|
||||
}
|
||||
14
DockerFile
Normal file
14
DockerFile
Normal file
@@ -0,0 +1,14 @@
|
||||
FROM node:16 AS compile-image
|
||||
|
||||
WORKDIR /opt/ng
|
||||
COPY package.json /opt/ng/package.json
|
||||
RUN npm install
|
||||
RUN npm install -g @angular/cli
|
||||
ENV PATH="./node_modules/.bin:$PATH"
|
||||
|
||||
COPY . ./
|
||||
RUN ng build --configuration production --base-href /cm-finance-web/ --deploy-url /cm-finance-web/
|
||||
|
||||
FROM nginx
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=compile-image /opt/ng/dist/cm-finance-web /usr/share/nginx/html
|
||||
27
README.md
Normal file
27
README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# CmFinanceWeb
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.2.2.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||
121
angular.json
Normal file
121
angular.json
Normal file
@@ -0,0 +1,121 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"cm-finance-web": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/cm-finance-web",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": [
|
||||
"zone.js"
|
||||
],
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"@angular/material/prebuilt-themes/indigo-pink.css",
|
||||
"node_modules/bootstrap-icons/font/bootstrap-icons.scss",
|
||||
"src/styles/app.scss",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"allowedCommonJsDependencies": [
|
||||
"sweetalert2",
|
||||
"autoprefixer"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kb",
|
||||
"maximumError": "2mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true,
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.development.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "cm-finance-web:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "cm-finance-web:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "cm-finance-web:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
],
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"@angular/material/prebuilt-themes/indigo-pink.css",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
23
bitbucket-pipelines.yml
Normal file
23
bitbucket-pipelines.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
pipelines:
|
||||
branches:
|
||||
master:
|
||||
- step:
|
||||
size: 2x
|
||||
services:
|
||||
- docker
|
||||
caches:
|
||||
- docker
|
||||
script: # Modify the commands below to build your repository.
|
||||
- docker login --username $DOCKER_USERNAME --password $DOCKER_PASSWORD
|
||||
- docker build -f DockerFile -t 71dev/cm-finance-web:dev .
|
||||
- docker push 71dev/cm-finance-web:dev
|
||||
- step:
|
||||
name: Deploy to kubernates
|
||||
image: atlassian/pipelines-kubectl
|
||||
script:
|
||||
- echo $KUBE_CONFIG_DELL | base64 -d > kubeconfig
|
||||
- kubectl --insecure-skip-tls-verify --kubeconfig=kubeconfig rollout restart deployment/cm-finance-web-deployment -n cm-finance-web
|
||||
definitions:
|
||||
services:
|
||||
docker:
|
||||
memory: 7128
|
||||
30
nginx.conf
Normal file
30
nginx.conf
Normal file
@@ -0,0 +1,30 @@
|
||||
server {
|
||||
gzip on;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/js
|
||||
text/xml
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/x-javascript
|
||||
application/json
|
||||
application/xml
|
||||
application/rss+xml
|
||||
image/svg+xml;
|
||||
listen 8080;
|
||||
gzip_proxied no-cache no-store private expired auth;
|
||||
gzip_min_length 1000;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
include /etc/nginx/mime.types;
|
||||
|
||||
|
||||
location / {
|
||||
try_files $uri /index.html;
|
||||
}
|
||||
|
||||
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
|
||||
expires 365d;
|
||||
}
|
||||
}
|
||||
22203
package-lock.json
generated
Normal file
22203
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
48
package.json
Normal file
48
package.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "cm-finance-web",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve --hmr --configuration development",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^15.2.0",
|
||||
"@angular/cdk": "^15.2.2",
|
||||
"@angular/common": "^15.2.0",
|
||||
"@angular/compiler": "^15.2.0",
|
||||
"@angular/core": "^15.2.0",
|
||||
"@angular/forms": "^15.2.0",
|
||||
"@angular/material": "^15.2.2",
|
||||
"@angular/platform-browser": "^15.2.0",
|
||||
"@angular/platform-browser-dynamic": "^15.2.0",
|
||||
"@angular/router": "^15.2.0",
|
||||
"@ng-select/ng-select": "^10.0.3",
|
||||
"bootstrap-icons": "^1.10.3",
|
||||
"date-fns": "^2.29.3",
|
||||
"rxjs": "~7.8.0",
|
||||
"sweetalert2": "^11.7.3",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^15.2.2",
|
||||
"@angular/cli": "~15.2.2",
|
||||
"@angular/compiler-cli": "^15.2.0",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@types/jasmine": "~4.3.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"jasmine-core": "~4.5.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.0.0",
|
||||
"postcss": "^8.4.21",
|
||||
"tailwindcss": "^3.2.7",
|
||||
"typescript": "~4.9.4"
|
||||
}
|
||||
}
|
||||
BIN
src/android-chrome-192x192.png
Normal file
BIN
src/android-chrome-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
src/android-chrome-512x512.png
Normal file
BIN
src/android-chrome-512x512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
23
src/app/@common/base/base-form.component.ts
Normal file
23
src/app/@common/base/base-form.component.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { CDialogConfig, IDialogConfig } from "../interface/Dialog";
|
||||
|
||||
|
||||
@Component({ template: "", standalone: true })
|
||||
export class BaseFormComponent {
|
||||
|
||||
dataForm: any = {};
|
||||
dataFilter: any = {};
|
||||
ids: any;
|
||||
action: any;
|
||||
params: any = {};
|
||||
dialogConfig: IDialogConfig = CDialogConfig;
|
||||
|
||||
|
||||
public isFieldValid(form: any, field: any) {
|
||||
return field.errors && (field.dirty || field.touched || form.submitted);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
123
src/app/@common/base/base-list.component.ts
Normal file
123
src/app/@common/base/base-list.component.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import {Component, ViewChild} from '@angular/core';
|
||||
import {MatPaginator} from '@angular/material/paginator';
|
||||
import {MatSort} from '@angular/material/sort';
|
||||
|
||||
import generateParamsValue from '../utils/GenerateParamsValue';
|
||||
|
||||
import {MatTableDataSource} from '@angular/material/table';
|
||||
import {IListPageDefault, IListResponse} from "../interface/ListResponse";
|
||||
import {CDialogConfig, IDialogConfig} from "../interface/Dialog";
|
||||
import { STORAGE } from "../../@config/app";
|
||||
|
||||
@Component({template: ''})
|
||||
export abstract class BaseListComponent {
|
||||
|
||||
dataFilter: any = {};
|
||||
dataSource: any = [];
|
||||
dataSourceList = new MatTableDataSource<any>([]);
|
||||
dataSourceCount = 0;
|
||||
pageSizeOptions = [10, 20, 50];
|
||||
pageIndex: number = 1;
|
||||
pageSize: number = 10;
|
||||
totalItem: any = 0;
|
||||
totalOfElement: number = 10;
|
||||
isTab: string = '';
|
||||
storage: any = STORAGE;
|
||||
|
||||
|
||||
dialogConfig: IDialogConfig = CDialogConfig;
|
||||
default: IListPageDefault = {
|
||||
pageIndex: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
|
||||
@ViewChild(MatSort, {static: true}) sort: MatSort | any;
|
||||
@ViewChild(MatPaginator, {static: true}) paginator: MatPaginator | any;
|
||||
|
||||
protected setParams(url: string, $event? : any) {
|
||||
this.pageIndex = $event ? $event.pageIndex + 1 : this.default.pageIndex;
|
||||
this.pageSize = $event ? $event.pageSize : this.default.pageSize;
|
||||
const filter = generateParamsValue(this.dataFilter);
|
||||
return `${url}?page=${this.pageIndex}&perPage=${this.pageSize}${filter ? '&' + filter : '' }`;
|
||||
}
|
||||
|
||||
|
||||
protected setDataSource<T>(data: IListResponse<T>) {
|
||||
this.totalItem = data ? data.totalItem : 0;
|
||||
this.totalOfElement = data ? data.totalOfElement : 0;
|
||||
this.paginator.length = data ? data.totalItem : 0;
|
||||
this.dataSourceCount = data ? data.totalItem : 0;
|
||||
return data ? data.data : [];
|
||||
}
|
||||
|
||||
protected getCurrentPage() {
|
||||
return {pageIndex: this.pageIndex - 1, pageSize: this.pageSize};
|
||||
}
|
||||
|
||||
protected setDataSourceList<T>(data : any) {
|
||||
this.dataSourceList = new MatTableDataSource<T>(data);
|
||||
this.dataSourceList.paginator = this.paginator;
|
||||
this.dataSourceCount = data ? data.length : 0;
|
||||
}
|
||||
|
||||
protected setFilterPredicate<T>() {
|
||||
this.dataSourceList.filterPredicate = (data: T, filtersJson: string) => {
|
||||
const matchFilter : any = [];
|
||||
const filters = JSON.parse(filtersJson);
|
||||
filters.forEach((filter : any) => {
|
||||
// @ts-ignore
|
||||
const val = data[filter.id] ? data[filter.id] : '';
|
||||
filter.value = filter.value ? filter.value : '';
|
||||
matchFilter.push(val.toLowerCase().includes(filter.value.toLowerCase()));
|
||||
});
|
||||
return matchFilter.every(Boolean);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
protected onFilterPredicate() {
|
||||
const tableFilters : any = [];
|
||||
Object.keys(this.dataFilter).forEach(key => {
|
||||
if (key) tableFilters.push({id: key, value: this.dataFilter[key]});
|
||||
});
|
||||
this.dataSourceList.filter = JSON.stringify(tableFilters);
|
||||
|
||||
if (this.dataSourceList.paginator) {
|
||||
this.dataSourceList.paginator.firstPage();
|
||||
}
|
||||
}
|
||||
|
||||
protected setFilterLocal(page : any) {
|
||||
const data = {
|
||||
page,
|
||||
filter: this.dataFilter
|
||||
};
|
||||
const filterLocalData = [];
|
||||
const filterLocal: any = localStorage.getItem('filterLocal');
|
||||
|
||||
if (filterLocal) {
|
||||
const parse = JSON.parse(filterLocal);
|
||||
const mapData = parse.map((item : any) => {
|
||||
if (item.page === page) return data;
|
||||
return item;
|
||||
});
|
||||
return localStorage.setItem('filterLocal', JSON.stringify(mapData));
|
||||
}
|
||||
|
||||
filterLocalData.push(data);
|
||||
localStorage.setItem('filterLocal', JSON.stringify(filterLocalData));
|
||||
}
|
||||
|
||||
protected getFilterLocal(page : any) {
|
||||
const filterLocal: any = localStorage.getItem('filterLocal');
|
||||
if (!filterLocal) return;
|
||||
const parse = JSON.parse(filterLocal);
|
||||
const isPage = parse.filter((f : any) => f.page === page);
|
||||
if (!isPage[0]) return;
|
||||
this.dataFilter = isPage[0].filter;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
15
src/app/@common/base/base-popup.component.ts
Normal file
15
src/app/@common/base/base-popup.component.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
import {CDialogConfig, IDialogConfig} from "../interface/Dialog";
|
||||
|
||||
@Component({template: ''})
|
||||
export abstract class BasePopupComponent {
|
||||
|
||||
ids: any;
|
||||
dataForm: any = {};
|
||||
dialogConfig: IDialogConfig = CDialogConfig;
|
||||
|
||||
public isFieldValid(form : any, field : any) {
|
||||
return field.errors && (field.dirty || field.touched || form.submitted);
|
||||
}
|
||||
}
|
||||
21
src/app/@common/interface/Dialog.ts
Normal file
21
src/app/@common/interface/Dialog.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import {EAction} from "../../@config/app";
|
||||
|
||||
export const CDialogConfig: IDialogConfig = {
|
||||
width: '80%',
|
||||
height: '80%',
|
||||
data: {}
|
||||
};
|
||||
|
||||
|
||||
export interface IDialogConfig {
|
||||
width: string;
|
||||
height: string;
|
||||
data: IDialogConfigData;
|
||||
}
|
||||
|
||||
export interface IDialogConfigData {
|
||||
action?: EAction;
|
||||
ids?: string;
|
||||
datas?: any;
|
||||
dataForm?: any;
|
||||
}
|
||||
12
src/app/@common/interface/ListResponse.ts
Normal file
12
src/app/@common/interface/ListResponse.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export interface IListResponse<T> {
|
||||
data: T[];
|
||||
totalItem: number;
|
||||
totalOfElement: number;
|
||||
page: number;
|
||||
rowsPerPage: number;
|
||||
lastPage: number;
|
||||
}
|
||||
export interface IListPageDefault {
|
||||
pageIndex: number;
|
||||
pageSize: number;
|
||||
}
|
||||
201
src/app/@common/interface/Quotation.ts
Normal file
201
src/app/@common/interface/Quotation.ts
Normal file
@@ -0,0 +1,201 @@
|
||||
export interface IQuotation {
|
||||
id?: number
|
||||
step?: number
|
||||
quotationNo?: string
|
||||
productId?: any
|
||||
typeCode?: any
|
||||
productNo?: string
|
||||
productName?: string
|
||||
productBrandName?: string
|
||||
productSize?: string
|
||||
productColor?: string
|
||||
productWeight?: any
|
||||
productYear?: string
|
||||
productPrice?: string
|
||||
productLatestPrice?: string
|
||||
productImages?: any
|
||||
images?: any
|
||||
openingVideo?: any
|
||||
coverImage?: string
|
||||
startDate?: string
|
||||
deposit?: string
|
||||
cmfsDeposit?: string
|
||||
price?: string
|
||||
lessSellerDeposit?: string
|
||||
sellerDeposit?: string
|
||||
sellerDeposit2ndTime?: any
|
||||
sellerDeposit3rdTime?: any
|
||||
sellerDepositSum?: any
|
||||
plusPacking?: string
|
||||
plusLuxuryHandbag?: string
|
||||
principalBalanceTotal?: string
|
||||
wantToInstallmentTerm?: number
|
||||
installment?: any
|
||||
plusBankFee?: string
|
||||
transferSummary?: string
|
||||
customerId?: number
|
||||
sellerId?: any
|
||||
customerPrefix?: any
|
||||
customerFirstName?: string
|
||||
customerLastName?: string
|
||||
customerPhone?: string
|
||||
customerIdCard?: any
|
||||
customerIdCardImage?: any
|
||||
customerAddress?: any
|
||||
customerEmail?: any
|
||||
customerLine?: any
|
||||
customerLineShop?: any
|
||||
customerFacebook?: any
|
||||
customerOccupation?: any
|
||||
customerIg?: any
|
||||
userFullName?: string
|
||||
sellerName?: string
|
||||
sellerPhone?: string
|
||||
sellerEmail?: any
|
||||
sellerLine?: any
|
||||
sellerLineShop?: any
|
||||
sellerFacebook?: any
|
||||
sellerIg?: any
|
||||
sellerSnProduct?: any
|
||||
status?: string
|
||||
status2ndTime?: string
|
||||
status3rdTime?: string
|
||||
statusContract?: string
|
||||
contractDate?: any
|
||||
contractApprovedDate?: any
|
||||
contractCancelDate?: any
|
||||
contractBankName?: any
|
||||
contractAccountName?: any
|
||||
contractAccountNumber?: any
|
||||
contractDetail?: any
|
||||
isContractClosing?: any
|
||||
contractPrice?: any
|
||||
contractInterest?: any
|
||||
contractPriceSum?: any
|
||||
receivedDate?: any
|
||||
statusWarehouse?: any
|
||||
areaId?: any
|
||||
areaCode?: any
|
||||
areaName?: any
|
||||
areaRoomName?: any
|
||||
areaLocation?: any
|
||||
areaFloor?: any
|
||||
areaRoomSize?: any
|
||||
storageBoxId?: any
|
||||
storageBoxCode?: any
|
||||
storageBoxName?: any
|
||||
storageBoxSize?: any
|
||||
disbursementDate?: any
|
||||
disbursementType?: any
|
||||
deliveryWorker?: any
|
||||
isCheckInspection?: any
|
||||
isReceived?: any
|
||||
type?: string
|
||||
pickType?: any
|
||||
settingInterestRate?: any
|
||||
settingCmfsDeposit?: any
|
||||
priceDisbursement?: any
|
||||
sellerPaymentAccountName?: string
|
||||
sellerPaymentPayee?: string
|
||||
sellerPaymentMethod?: string
|
||||
sellerPaymentDate?: string
|
||||
sellerPaymentAmount?: string
|
||||
sellerPaymentAccountNumber?: string
|
||||
isInvoice?: string
|
||||
isPaying?: string
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: number
|
||||
productMeasurement?: IQuotationProductMeasurement[]
|
||||
quotationDetail?: IQuotationDetail[]
|
||||
customer?: IQuotationCustomer
|
||||
seller?: any
|
||||
discount?: any
|
||||
}
|
||||
|
||||
export interface IQuotationCustomer {
|
||||
id?: number
|
||||
code?: any
|
||||
prefix?: string
|
||||
gender?: string
|
||||
firstName?: string
|
||||
lastName?: string
|
||||
phone?: string
|
||||
idCard?: string
|
||||
idCardImage?: string
|
||||
address?: string
|
||||
isAddress?: boolean
|
||||
deliveryAddress?: string
|
||||
email?: string
|
||||
line?: string
|
||||
lineShop?: any
|
||||
facebook?: string
|
||||
occupation?: string
|
||||
ig?: string
|
||||
status?: any
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: any
|
||||
}
|
||||
|
||||
export interface IQuotationProductMeasurement {
|
||||
id?: number
|
||||
productId?: any
|
||||
masterProductMeasurementId?: any
|
||||
quotationId?: number
|
||||
code?: any
|
||||
name?: string
|
||||
size?: string
|
||||
unitId?: number
|
||||
status?: any
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: any
|
||||
}
|
||||
|
||||
export interface IQuotationDetail {
|
||||
id?: number
|
||||
quotationId?: number
|
||||
installment?: number
|
||||
dueDate?: string
|
||||
principle?: string
|
||||
interestTotal?: string
|
||||
fee?: string
|
||||
totalPayment?: string
|
||||
principleTotal?: string
|
||||
status?: string
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: any
|
||||
}
|
||||
|
||||
export interface IQuotationPayment {
|
||||
id?: number
|
||||
quotationId?: number
|
||||
quotationNo?: string
|
||||
productNo?: string
|
||||
productName?: string
|
||||
customerPrefix?: string
|
||||
customerFirstName?: string
|
||||
customerLastName?: string
|
||||
customerPhone?: string
|
||||
price?: string
|
||||
sellerDeposit?: string
|
||||
deposit?: string
|
||||
paymentDate?: string
|
||||
paymentType?: string
|
||||
paymentAmount?: string
|
||||
paymentAmountAll?: string
|
||||
paymentMethod?: string
|
||||
status?: string
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: any
|
||||
quotation?: IQuotation
|
||||
}
|
||||
|
||||
199
src/app/@common/utils/CurrencyInputMask.ts
Normal file
199
src/app/@common/utils/CurrencyInputMask.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
import { OnInit, Directive, HostListener, ElementRef, forwardRef } from "@angular/core";
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
|
||||
import { DecimalPipe } from "@angular/common";
|
||||
|
||||
export const CURRENCY_INPUT_MASK_DIRECTIVE_VALUE_ACCESSOR: any = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => CurrencyInputMaskDirective),
|
||||
multi: true
|
||||
};
|
||||
|
||||
@Directive({
|
||||
selector: "[appCurrencyInputMask]",
|
||||
providers: [
|
||||
CURRENCY_INPUT_MASK_DIRECTIVE_VALUE_ACCESSOR,
|
||||
DecimalPipe
|
||||
]
|
||||
})
|
||||
export class CurrencyInputMaskDirective implements ControlValueAccessor, OnInit {
|
||||
private el: HTMLInputElement | any;
|
||||
private onModelChange: Function | any;
|
||||
private onModelTouched: Function | any;
|
||||
private lastNumVal: number | any;
|
||||
private DECIMAL_MARK = ".";
|
||||
|
||||
constructor(
|
||||
private elementRef: ElementRef,
|
||||
private decimalPipe: DecimalPipe
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.el = this.elementRef.nativeElement;
|
||||
}
|
||||
|
||||
@HostListener("focus", ["$event"])
|
||||
handleFocus(event: any) {
|
||||
const strVal: string = this.getInputValue();
|
||||
const unmaskedStr: string = this.getUnmaskedValue(strVal);
|
||||
this.updateInputValue(unmaskedStr);
|
||||
}
|
||||
|
||||
@HostListener("cut", ["$event"])
|
||||
handleCut(event: any) {
|
||||
setTimeout(() => {
|
||||
this.inputUpdated();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@HostListener("keypress", ["$event"])
|
||||
handleKeypress(event: any) {
|
||||
// Restrict characters
|
||||
const newChar: string = String.fromCharCode(event.which);
|
||||
const allowedChars: RegExp = /^[\d.]+$/;
|
||||
if (!allowedChars.test(newChar)) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
// Handle decimal mark input
|
||||
const currentValue: string = event.target.value;
|
||||
const separatorIdx: number = currentValue.indexOf(this.DECIMAL_MARK);
|
||||
const hasFractionalPart: boolean = (separatorIdx >= 0);
|
||||
if (!hasFractionalPart || newChar !== this.DECIMAL_MARK) {
|
||||
return;
|
||||
}
|
||||
const isOutsideSelection = !this.isIdxBetweenSelection(separatorIdx);
|
||||
if (isOutsideSelection) {
|
||||
const positionAfterMark = separatorIdx + 1;
|
||||
this.setCursorPosition(positionAfterMark);
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener("input", ["$event"])
|
||||
handleInput(event: any) {
|
||||
this.inputUpdated();
|
||||
}
|
||||
|
||||
@HostListener("paste", ["$event"])
|
||||
handlePaste(event: any) {
|
||||
setTimeout(() => {
|
||||
this.inputUpdated();
|
||||
}, 1);
|
||||
}
|
||||
|
||||
@HostListener("blur", ["$event"])
|
||||
handleBlur(event: any) {
|
||||
const strVal: string = this.getInputValue();
|
||||
const numVal: any = this.convertStrToDecimal(strVal);
|
||||
this.maskInput(numVal);
|
||||
|
||||
this.onModelTouched.apply(event);
|
||||
}
|
||||
|
||||
registerOnChange(callbackFunction: Function): void {
|
||||
this.onModelChange = callbackFunction;
|
||||
}
|
||||
|
||||
registerOnTouched(callbackFunction: Function): void {
|
||||
this.onModelTouched = callbackFunction;
|
||||
}
|
||||
|
||||
setDisabledState(value: boolean): void {
|
||||
|
||||
this.el.disabled = value;
|
||||
}
|
||||
|
||||
writeValue(numValue: number): void {
|
||||
this.maskInput(numValue);
|
||||
}
|
||||
|
||||
private maskInput(numVal: number): void {
|
||||
if (!this.isNumeric(numVal)) {
|
||||
this.updateInputValue("");
|
||||
return;
|
||||
}
|
||||
const strVal: string = this.convertDecimalToStr(numVal);
|
||||
const newVal: any = this.transformWithPipe(strVal);
|
||||
this.updateInputValue(newVal);
|
||||
}
|
||||
|
||||
private inputUpdated() {
|
||||
this.restrictDecimalValue();
|
||||
const strVal: string = this.getInputValue();
|
||||
const unmaskedVal: string = this.getUnmaskedValue(strVal);
|
||||
const numVal: any = this.convertStrToDecimal(unmaskedVal);
|
||||
if (numVal !== this.lastNumVal) {
|
||||
this.lastNumVal = numVal;
|
||||
|
||||
this.onModelChange(numVal);
|
||||
}
|
||||
}
|
||||
|
||||
private restrictDecimalValue(): void {
|
||||
const strVal: string = this.getInputValue();
|
||||
const dotIdx: number = strVal.indexOf(this.DECIMAL_MARK);
|
||||
const hasFractionalPart: boolean = (dotIdx >= 0);
|
||||
if (hasFractionalPart) {
|
||||
const fractionalPart: string = strVal.substring(dotIdx + 1);
|
||||
if (fractionalPart.length > 2) {
|
||||
const choppedVal: string = strVal.substring(0, dotIdx + 3);
|
||||
this.updateInputValue(choppedVal, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private transformWithPipe(str: any) {
|
||||
return this.decimalPipe.transform(str, "1.2-2");
|
||||
}
|
||||
|
||||
private getUnmaskedValue(value: string): string {
|
||||
return value.replace(/[^-\d\\.]/g, "");
|
||||
}
|
||||
|
||||
private updateInputValue(value: string, savePosition = false) {
|
||||
if (savePosition) {
|
||||
this.saveCursorPosition();
|
||||
}
|
||||
this.el.value = value;
|
||||
}
|
||||
|
||||
private getInputValue(): string {
|
||||
return this.el.value;
|
||||
}
|
||||
|
||||
private convertStrToDecimal(str: any) {
|
||||
return (this.isNumeric(str)) ? parseFloat(str) : null;
|
||||
}
|
||||
|
||||
private convertDecimalToStr(n: number): string {
|
||||
return (this.isNumeric(n)) ? n + "" : "";
|
||||
}
|
||||
|
||||
private isNumeric(n: any): boolean {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
}
|
||||
|
||||
private saveCursorPosition() {
|
||||
|
||||
const position: number = this.el.selectionStart;
|
||||
setTimeout(() => {
|
||||
this.setCursorPosition(position);
|
||||
}, 1);
|
||||
}
|
||||
|
||||
private setCursorPosition(position: number) {
|
||||
this.el.selectionStart = position;
|
||||
this.el.selectionEnd = position;
|
||||
}
|
||||
|
||||
private isIdxBetweenSelection(idx: number) {
|
||||
if (this.el.selectionStart === this.el.selectionEnd) {
|
||||
return false;
|
||||
}
|
||||
return (idx >= this.el.selectionStart && idx < this.el.selectionEnd);
|
||||
}
|
||||
|
||||
}
|
||||
4
src/app/@common/utils/DeepCopy.ts
Normal file
4
src/app/@common/utils/DeepCopy.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export default function deepCopy(data: any) {
|
||||
if (!data) return {};
|
||||
return JSON.parse(JSON.stringify(data));
|
||||
}
|
||||
16
src/app/@common/utils/Empty.ts
Normal file
16
src/app/@common/utils/Empty.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export default function isEmpty(value: any) {
|
||||
switch (value) {
|
||||
case '':
|
||||
case 0:
|
||||
case '0':
|
||||
case null:
|
||||
case false:
|
||||
case 'null':
|
||||
case 'undefined':
|
||||
case undefined:
|
||||
case typeof value === 'undefined':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
134
src/app/@common/utils/FilterPipe.ts
Normal file
134
src/app/@common/utils/FilterPipe.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import {Pipe, PipeTransform} from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'filterBy',
|
||||
pure: false
|
||||
})
|
||||
export class FilterPipe implements PipeTransform {
|
||||
static isFoundOnWalking(value, key) {
|
||||
let walker = value;
|
||||
let found = false;
|
||||
do {
|
||||
if (
|
||||
walker.hasOwnProperty(key) ||
|
||||
Object.getOwnPropertyDescriptor(walker, key)
|
||||
) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
// tslint:disable-next-line:no-conditional-assignment
|
||||
} while ((walker = Object.getPrototypeOf(walker)));
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static isNumber(value) {
|
||||
return !isNaN(parseInt(value, 10)) && isFinite(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks function's value if type is function otherwise same value
|
||||
*/
|
||||
static getValue(value: any): any {
|
||||
return typeof value === 'function' ? value() : value;
|
||||
}
|
||||
|
||||
private filterByString(filter) {
|
||||
if (filter) {
|
||||
filter = filter.toLowerCase();
|
||||
}
|
||||
return value =>
|
||||
!filter ||
|
||||
(value ? ('' + value).toLowerCase().indexOf(filter) !== -1 : false);
|
||||
}
|
||||
|
||||
private filterByBoolean(filter) {
|
||||
return value => Boolean(value) === filter;
|
||||
}
|
||||
|
||||
private filterByObject(filter) {
|
||||
return value => {
|
||||
for (const key in filter) {
|
||||
if (key === '$or') {
|
||||
if (!this.filterByOr(filter.$or)(FilterPipe.getValue(value))) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!value || !FilterPipe.isFoundOnWalking(value, key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.isMatching(filter[key], FilterPipe.getValue(value[key]))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
private isMatching(filter, val) {
|
||||
switch (typeof filter) {
|
||||
case 'boolean':
|
||||
return this.filterByBoolean(filter)(val);
|
||||
case 'string':
|
||||
return this.filterByString(filter)(val);
|
||||
case 'object':
|
||||
return this.filterByObject(filter)(val);
|
||||
}
|
||||
return this.filterDefault(filter)(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter value by $or
|
||||
*/
|
||||
private filterByOr(filter: any[]): (value: any) => boolean {
|
||||
return (value: any) => {
|
||||
const length = filter.length;
|
||||
|
||||
const arrayComparison = i => value.indexOf(filter[i]) !== -1;
|
||||
const otherComparison = i => this.isMatching(filter[i], value);
|
||||
const comparison = Array.isArray(value)
|
||||
? arrayComparison
|
||||
: otherComparison;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (comparison(i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Default filterDefault function
|
||||
*/
|
||||
private filterDefault(filter: any): (value: any) => boolean {
|
||||
return (value: any) => filter === undefined || filter === value;
|
||||
}
|
||||
|
||||
transform(array: any[], filter: any): any {
|
||||
if (!array) {
|
||||
return array;
|
||||
}
|
||||
|
||||
switch (typeof filter) {
|
||||
case 'boolean':
|
||||
return array.filter(this.filterByBoolean(filter));
|
||||
case 'string':
|
||||
if (FilterPipe.isNumber(filter)) {
|
||||
return array.filter(this.filterDefault(filter));
|
||||
}
|
||||
return array.filter(this.filterByString(filter));
|
||||
case 'object':
|
||||
return array.filter(this.filterByObject(filter));
|
||||
case 'function':
|
||||
return array.filter(filter);
|
||||
}
|
||||
return array.filter(this.filterDefault(filter));
|
||||
}
|
||||
}
|
||||
10
src/app/@common/utils/GenerateParamsValue.ts
Normal file
10
src/app/@common/utils/GenerateParamsValue.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export default function generateParamsValue(jsonValue: any) {
|
||||
let params = '';
|
||||
Object.keys(jsonValue).forEach((key) => {
|
||||
if (jsonValue[key]) {
|
||||
params += key + '=' + jsonValue[key] + '&';
|
||||
}
|
||||
});
|
||||
params = params.substring(0, params.length - 1);
|
||||
return params;
|
||||
}
|
||||
41
src/app/@common/utils/NumberOnlyDirective.ts
Normal file
41
src/app/@common/utils/NumberOnlyDirective.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import {Directive, ElementRef, EventEmitter, HostListener, Output} from '@angular/core';
|
||||
|
||||
@Directive({
|
||||
selector: '[appNumberOnly]'
|
||||
})
|
||||
export class NumberOnlyDirective {
|
||||
// Emit the parsed number value
|
||||
@Output() numberValue: EventEmitter<number> = new EventEmitter<number>();
|
||||
// Allow key codes for special events. Reflect :
|
||||
// Allow decimal numbers with 2 decimal places and negative values
|
||||
private regex: RegExp = new RegExp(/^\d*\.?\d{0,2}$/g);
|
||||
// Backspace, tab, end, home
|
||||
private specialKeys: Array<string> = ['Backspace', 'Tab', 'End', 'Home', '-', 'ArrowLeft', 'ArrowRight', 'Del', 'Delete'];
|
||||
|
||||
constructor(private el: ElementRef) {
|
||||
}
|
||||
|
||||
@HostListener('keydown', ['$event'])
|
||||
onKeyDown(event: KeyboardEvent) {
|
||||
if (this.specialKeys.indexOf(event.key) !== -1) {
|
||||
return;
|
||||
}
|
||||
const current: string = this.el.nativeElement.value;
|
||||
const position = this.el.nativeElement.selectionStart;
|
||||
const next: string = [current.slice(0, position), event.key === 'Decimal' ? '.' : event.key, current.slice(position)].join('');
|
||||
if (next && !String(next).match(this.regex)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('input', ['$event'])
|
||||
onInput(event: KeyboardEvent) {
|
||||
// Get the parsed number value
|
||||
const parsedValue = Number(this.el.nativeElement.value);
|
||||
|
||||
// Emit the parsed value only if it's a number
|
||||
if (!isNaN(parsedValue)) {
|
||||
this.numberValue.emit(parsedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/app/@common/utils/OrderBy.ts
Normal file
22
src/app/@common/utils/OrderBy.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export function orderByArray(data: any, key: string) {
|
||||
if (!data) return;
|
||||
if (data.length === 0) return;
|
||||
return data.sort((a: any, b: any) => a[key].localeCompare(b[key], 'en', {numeric: true}));
|
||||
}
|
||||
|
||||
export function sortByProperty<T>(array: T[], propName: keyof T, order: 'ASC' | 'DESC') {
|
||||
array.sort((a, b) => {
|
||||
if (a[propName] < b[propName]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a[propName] > b[propName]) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
if (order === 'DESC') {
|
||||
array.reverse();
|
||||
}
|
||||
}
|
||||
22
src/app/@common/utils/generateUUID.ts
Normal file
22
src/app/@common/utils/generateUUID.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export function generateUUID() {
|
||||
// Public Domain/MIT
|
||||
let d = new Date().getTime(); // Timestamp
|
||||
let d2 =
|
||||
(typeof performance !== 'undefined' &&
|
||||
performance.now &&
|
||||
performance.now() * 1000) ||
|
||||
0; // Time in microseconds since page-load or 0 if unsupported
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
let r = Math.random() * 16; // random number between 0 and 16
|
||||
if (d > 0) {
|
||||
// Use timestamp until depleted
|
||||
r = (d + r) % 16 | 0;
|
||||
d = Math.floor(d / 16);
|
||||
} else {
|
||||
// Use microseconds since page-load if supported
|
||||
r = (d2 + r) % 16 | 0;
|
||||
d2 = Math.floor(d2 / 16);
|
||||
}
|
||||
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
|
||||
});
|
||||
}
|
||||
104
src/app/@config/app.ts
Normal file
104
src/app/@config/app.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import {environment} from "../../environments/environment";
|
||||
|
||||
const ENV = {
|
||||
url : environment.API_URL,
|
||||
reportUrl : environment.API_REPORT_URL,
|
||||
}
|
||||
|
||||
export const API = {
|
||||
url : `${ENV.url}` ,
|
||||
login : `${ENV.url}/auth/login` ,
|
||||
users : `${ENV.url}/users` ,
|
||||
userGroup : `${ENV.url}/userGroup` ,
|
||||
customer : `${ENV.url}/customer` ,
|
||||
seller : `${ENV.url}/seller` ,
|
||||
quotation : `${ENV.url}/quotation` ,
|
||||
quotationDetail : `${ENV.url}/quotationDetail` ,
|
||||
quotationPayment : `${ENV.url}/quotationPayment` ,
|
||||
products : `${ENV.url}/products` ,
|
||||
masterProductBrand : `${ENV.url}/masterProductBrand` ,
|
||||
masterProductCategory : `${ENV.url}/masterProductCategory` ,
|
||||
masterProductUnit : `${ENV.url}/masterProductUnit` ,
|
||||
masterProductMeasurement : `${ENV.url}/masterProductMeasurement` ,
|
||||
masterArea : `${ENV.url}/masterArea` ,
|
||||
masterStorageBox : `${ENV.url}/masterStorageBox` ,
|
||||
attachments : `${ENV.url}/attachments` ,
|
||||
settings : `${ENV.url}/settings` ,
|
||||
packet : `${ENV.url}/packet` ,
|
||||
promotion : `${ENV.url}/promotion` ,
|
||||
|
||||
quotationReport : `${ENV.reportUrl}/reports/quotation_report` ,
|
||||
receiptReport : `${ENV.reportUrl}/reports/receipt_report` ,
|
||||
installmentContractReport : `${ENV.reportUrl}/reports/installment_contract_report` ,
|
||||
receiveInventory : `${ENV.reportUrl}/reports/receive_inventory` ,
|
||||
receiveSendInventory : `${ENV.reportUrl}/reports/receive_send_inventory` ,
|
||||
receivePickUp : `${ENV.reportUrl}/reports/pick_up` ,
|
||||
reportOutstandingAccountsReceivable : `${ENV.reportUrl}/reports/outstanding_accounts_receivable` ,
|
||||
|
||||
paymentReport : `${ENV.reportUrl}/reports/payment_report` ,
|
||||
paymentVoucher : `${ENV.reportUrl}/reports/payment_voucher` ,
|
||||
|
||||
}
|
||||
|
||||
export const STORAGE = {
|
||||
products : `${ENV.url}/storage/products` ,
|
||||
images : `${ENV.url}/storage/images` ,
|
||||
}
|
||||
|
||||
export const GENDER = ['ชาย', 'หญิง', 'อื่นๆ'];
|
||||
|
||||
export const PREFIX = ['นาย', 'นาง', 'นางสาว', 'อื่นๆ'];
|
||||
export const TYPE_CODE = ['A', 'C', 'H', 'W'];
|
||||
export const CONDITIONS = ['new', 'like new', 'used'];
|
||||
export const SOURCES = ['แม่ค้าแนะนำ', 'ลูกค้าเก่า', 'ลูกค้าใหม่', 'แม่ค้าซื้อ'];
|
||||
|
||||
|
||||
export enum EAction {
|
||||
CREATE = 'create',
|
||||
UPDATE = 'update',
|
||||
DELETE = 'delete',
|
||||
GET = 'get',
|
||||
POPUP = 'popup',
|
||||
SEND = 'send',
|
||||
ERROR = 'error',
|
||||
INFO = 'info',
|
||||
SUCCESS = 'success',
|
||||
BACK = 'back',
|
||||
COPY = 'copy',
|
||||
RELOAD = 'reload',
|
||||
REFINANCE = 'refinance',
|
||||
}
|
||||
export type TAction = `${EAction}`;
|
||||
|
||||
export enum EText {
|
||||
CREATE = 'เพิ่มข้อมูลสำเร็จ',
|
||||
UPDATE = 'บันทึกสำเร็จ',
|
||||
DELETE = 'ลบข้อมูลสำเร็จ',
|
||||
NO_DATA = 'ไม่พบข้อมูล',
|
||||
ERROR = 'เกิดข้อผิดพลาด',
|
||||
COPY = 'เพิ่มข้อมูลสำเร็จ',
|
||||
MAIL = 'ส่งเมลสำเร็จ',
|
||||
}
|
||||
|
||||
|
||||
export enum EStatusQuotation {
|
||||
PENDING = 'pending',
|
||||
PAID = 'paid',
|
||||
WAIT = 'wait',
|
||||
DUE = 'due',
|
||||
EVALUATED = 'evaluated',
|
||||
COMPLETE = 'complete',
|
||||
}
|
||||
|
||||
export enum EStatusContract {
|
||||
WAIT = 'wait',
|
||||
PENDING = 'pending',
|
||||
APPROVED = 'approved',
|
||||
CANCEL = 'cancel',
|
||||
}
|
||||
|
||||
export enum EStatusWarehouse {
|
||||
WAREHOUSE = 'warehouse',
|
||||
DISBURSEMENT = 'disbursement',
|
||||
|
||||
}
|
||||
205
src/app/@config/menus.ts
Normal file
205
src/app/@config/menus.ts
Normal file
@@ -0,0 +1,205 @@
|
||||
|
||||
export interface MENU {
|
||||
link?: string;
|
||||
type: | 'link' | 'heading' | 'collapsable';
|
||||
icon?: string;
|
||||
name?: string;
|
||||
params?: any[];
|
||||
badge?: string;
|
||||
roles?: any[];
|
||||
children?: any[];
|
||||
permission?: string;
|
||||
collapsed?: boolean;
|
||||
notShowing?: boolean;
|
||||
isChecked?: boolean;
|
||||
}
|
||||
|
||||
export const MENU: MENU[] = [
|
||||
// {
|
||||
// name: 'ประเมินราคา/ค่ามัดจำ',
|
||||
// link: 'appraisal',
|
||||
// permission: 'appraisal',
|
||||
// icon: 'bi bi-ui-checks',
|
||||
// params: [],
|
||||
// badge: '',
|
||||
// type: 'collapsable',
|
||||
// children: [
|
||||
// {
|
||||
// name: 'ประเมินราคาครั้งที่ 1',
|
||||
// link: 'appraisal/1st-time',
|
||||
// permission: 'appraisal-1st-time',
|
||||
// type: 'link',
|
||||
// icon: '',
|
||||
// params: [],
|
||||
// badge: '',
|
||||
// children: [
|
||||
// {
|
||||
// name: 'ประวัติการสร้างใบเสนอราคา',
|
||||
// link: 'appraisal/1st-time/history',
|
||||
// permission: 'appraisal-1st-time-history',
|
||||
// notShowing: true,
|
||||
// children: [
|
||||
// {
|
||||
// name: 'ใบเสนอราคา',
|
||||
// link: 'appraisal/1st-time/history/pdf',
|
||||
// permission: 'appraisal-1st-time-pdf',
|
||||
// notShowing: true,
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// name: 'ประเมินราคาครั้งที่ 2',
|
||||
// link: 'appraisal/2nd-time',
|
||||
// permission: 'appraisal-2nd-time',
|
||||
// type: 'link',
|
||||
// icon: '',
|
||||
// params: [],
|
||||
// badge: '',
|
||||
// },
|
||||
// {
|
||||
// name: 'ประเมินราคาครั้งที่ 3',
|
||||
// link: 'appraisal/3rd-time',
|
||||
// permission: 'appraisal-3rd-time',
|
||||
// type: 'link',
|
||||
// icon: '',
|
||||
// params: [],
|
||||
// badge: '',
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// name: 'การเงิน',
|
||||
// link: 'finance',
|
||||
// permission: 'finance',
|
||||
// icon: 'bi bi-coin',
|
||||
// params: [],
|
||||
// badge: '',
|
||||
// type: 'collapsable',
|
||||
// children: [
|
||||
// {
|
||||
// name: 'รับชำระเงิน/ใบเสร็จรับเงิน',
|
||||
// link: 'finance/payment',
|
||||
// permission: 'payment',
|
||||
// type: 'link',
|
||||
// icon: '',
|
||||
// params: [],
|
||||
// badge: '',
|
||||
// children: [
|
||||
// {
|
||||
// name: 'ใบเสร็จรับเงิน',
|
||||
// link: 'finance/payment/paid/pdf',
|
||||
// permission: 'finance-payment-pdf',
|
||||
// notShowing: true,
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// name: 'การแจ้งหนี้/ตั้งเจ้าหนี้',
|
||||
// link: 'finance/invoice',
|
||||
// permission: 'invoice',
|
||||
// type: 'link',
|
||||
// icon: '',
|
||||
// params: [],
|
||||
// badge: '',
|
||||
// },
|
||||
// {
|
||||
// name: 'การจ่ายชำระเงิน',
|
||||
// link: 'finance/paying',
|
||||
// permission: 'paying',
|
||||
// type: 'link',
|
||||
// icon: '',
|
||||
// params: [],
|
||||
// badge: '',
|
||||
// },
|
||||
|
||||
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// name: 'สัญญา',
|
||||
// link: 'contract',
|
||||
// permission: 'contract',
|
||||
// icon: 'bi bi-file-earmark-text-fill',
|
||||
// params: [],
|
||||
// badge: '',
|
||||
// type: 'collapsable',
|
||||
// children: [
|
||||
// {
|
||||
// name: 'ทำสัญญา',
|
||||
// link: 'contract/make',
|
||||
// permission: 'contract-make',
|
||||
// type: 'link',
|
||||
// icon: '',
|
||||
// params: [],
|
||||
// badge: '',
|
||||
// },
|
||||
// {
|
||||
// name: 'อนุมัติสัญญา',
|
||||
// link: 'contract/approved',
|
||||
// permission: 'contract-approved',
|
||||
// type: 'link',
|
||||
// icon: '',
|
||||
// params: [],
|
||||
// badge: '',
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
name: 'Manage',
|
||||
link: 'manage',
|
||||
permission: 'manage',
|
||||
icon: 'bi bi-card-checklist',
|
||||
params: [],
|
||||
badge: '',
|
||||
type: 'collapsable',
|
||||
children: [
|
||||
{
|
||||
name: 'Manage KYC',
|
||||
link: 'manage/kyc',
|
||||
permission: 'manage-kyc',
|
||||
type: 'link',
|
||||
icon: '',
|
||||
params: [],
|
||||
badge: '',
|
||||
// children: [
|
||||
// {
|
||||
// name: 'ประวัติการสร้างใบเสนอราคา',
|
||||
// link: 'appraisal/1st-time/history',
|
||||
// permission: 'appraisal-1st-time-history',
|
||||
// notShowing: true,
|
||||
// children: [
|
||||
// {
|
||||
// name: 'ใบเสนอราคา',
|
||||
// link: 'appraisal/1st-time/history/pdf',
|
||||
// permission: 'appraisal-1st-time-pdf',
|
||||
// notShowing: true,
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
|
||||
// ]
|
||||
},
|
||||
// {
|
||||
// name: 'ประเมินราคาครั้งที่ 2',
|
||||
// link: 'appraisal/2nd-time',
|
||||
// permission: 'appraisal-2nd-time',
|
||||
// type: 'link',
|
||||
// icon: '',
|
||||
// params: [],
|
||||
// badge: '',
|
||||
// },
|
||||
// {
|
||||
// name: 'ประเมินราคาครั้งที่ 3',
|
||||
// link: 'appraisal/3rd-time',
|
||||
// permission: 'appraisal-3rd-time',
|
||||
// type: 'link',
|
||||
// icon: '',
|
||||
// params: [],
|
||||
// badge: '',
|
||||
// },
|
||||
]
|
||||
},
|
||||
];
|
||||
185
src/app/app-routing.module.ts
Normal file
185
src/app/app-routing.module.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { PagesLayoutsComponent } from "./pages/@layouts/layouts.component";
|
||||
import { ComingsoonComponent } from "./pages/@comingsoon/comingsoon.component";
|
||||
import { AppGuard } from "./app.guard";
|
||||
import { PageBlankModule } from "./pages/page-blank/page-blank.module";
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'pages',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
{
|
||||
path: 'auth',
|
||||
loadChildren: () => import('./auth/auth.module').then(m => m.AuthModule)
|
||||
},
|
||||
{
|
||||
path: 'pages',
|
||||
component: PagesLayoutsComponent,
|
||||
canActivate: [AppGuard],
|
||||
canActivateChild: [AppGuard],
|
||||
children: [
|
||||
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
|
||||
{
|
||||
path: 'dashboard',
|
||||
loadChildren: () => import('./pages/dashboard/dashboard.module').then(m => m.DashboardModule)
|
||||
},
|
||||
{
|
||||
path: 'users',
|
||||
loadChildren: () => import('./pages/users/users.module').then(m => m.UsersModule)
|
||||
},
|
||||
{
|
||||
path: 'manage',
|
||||
children: [
|
||||
{
|
||||
path: 'kyc',
|
||||
loadChildren: () => import('./pages/appraisal/1st-time/appraisal-1st-time.module').then(m => m.Appraisal1stTimeModule)
|
||||
},
|
||||
// {
|
||||
// path: '2nd-time',
|
||||
// loadChildren: () => import('./pages/appraisal/2nd-time/appraisal-2nd-time.module').then(m => m.Appraisal2ndTimeModule)
|
||||
// },
|
||||
// {
|
||||
// path: '3rd-time',
|
||||
// loadChildren: () => import('./pages/appraisal/3rd-time/appraisal-3rd-time.module').then(m => m.Appraisal3rdTimeModule)
|
||||
// },
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'finance',
|
||||
children: [
|
||||
{
|
||||
path: 'payment',
|
||||
loadChildren: () => import('./pages/finance/payment/finance-payment.module').then(m => m.FinancePaymentModule)
|
||||
},
|
||||
{
|
||||
path: 'refund',
|
||||
loadChildren: () => import('./pages/page-blank/page-blank.module').then(m => m.PageBlankModule)
|
||||
},
|
||||
{
|
||||
path: 'invoice',
|
||||
loadChildren: () => import('./pages/finance/invoice/finance-invoice.module').then(m => m.FinanceInvoiceModule)
|
||||
},
|
||||
{
|
||||
path: 'paying',
|
||||
loadChildren: () => import('./pages/finance/paying/finance-paying.module').then(m => m.FinancePayingModule)
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'contract',
|
||||
children: [
|
||||
{
|
||||
path: 'make',
|
||||
loadChildren: () => import('./pages/contract/make/contract-make.module').then(m => m.ContractMakeModule)
|
||||
},
|
||||
{
|
||||
path: 'approved',
|
||||
loadChildren: () => import('./pages/contract/approved/contract-approved.module').then(m => m.ContractApprovedModule)
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// path: 'warehouse',
|
||||
// children: [
|
||||
// {
|
||||
// path: 'received',
|
||||
// loadChildren: () => import('./pages/warehouse/received/warehouse-received.module').then(m => m.WarehouseReceivedModule)
|
||||
// },
|
||||
// {
|
||||
// path: 'inspection',
|
||||
// loadChildren: () => import('./pages/warehouse/inspection/warehouse-inspection.module').then(m => m.WarehouseInspectionModule)
|
||||
// },
|
||||
// {
|
||||
// path: 'disbursement',
|
||||
// loadChildren: () => import('./pages/warehouse/disbursement/warehouse-disbursement.module').then(m => m.WarehouseDisbursementModule)
|
||||
// },
|
||||
// {
|
||||
// path: 'area',
|
||||
// loadChildren: () => import('./pages/setting/master-area/master-area.module').then(m => m.MasterAreaModule)
|
||||
// },
|
||||
// {
|
||||
// path: 'storage-box',
|
||||
// loadChildren: () => import('./pages/setting/master-storage-box/master-storage-box.module').then(m => m.MasterStorageBoxModule)
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path: 'setting',
|
||||
// children: [
|
||||
// {
|
||||
// path: 'products',
|
||||
// loadChildren: () => import('./pages/setting/products/products.module').then(m => m.ProductsModule)
|
||||
// },
|
||||
// {
|
||||
// path: 'deviation',
|
||||
// loadChildren: () => import('./pages/setting/setting-deviation/setting-deviation.module').then(m => m.SettingDeviationModule)
|
||||
// },
|
||||
// {
|
||||
// path: 'product-brand',
|
||||
// loadChildren: () => import('./pages/setting/master-product-brand/master-product-brand.module').then(m => m.MasterProductBrandModule)
|
||||
// },
|
||||
// {
|
||||
// path: 'product-category',
|
||||
// loadChildren: () => import('./pages/setting/master-product-category/master-product-category.module').then(m => m.MasterProductCategoryModule)
|
||||
// },
|
||||
// {
|
||||
// path: 'product-unit',
|
||||
// loadChildren: () => import('./pages/setting/master-product-unit/master-product-unit.module').then(m => m.MasterProductUnitModule)
|
||||
// },
|
||||
// {
|
||||
// path: 'product-measurement',
|
||||
// loadChildren: () => import('./pages/setting/master-product-measurement/master-product-measurement.module').then(m => m.MasterProductMeasurementModule)
|
||||
// },
|
||||
// {
|
||||
// path: 'installment',
|
||||
// loadChildren: () => import('./pages/setting/setting-installment/setting-installment.module').then(m => m.SettingInstallmentModule)
|
||||
// },
|
||||
// {
|
||||
// path: 'packet',
|
||||
// loadChildren: () => import('./pages/setting/packet/packet.module').then(m => m.PacketModule)
|
||||
// },
|
||||
// {
|
||||
// path: 'promotion',
|
||||
// loadChildren: () => import('./pages/setting/promotion/promotion.module').then(m => m.PromotionModule)
|
||||
// },
|
||||
|
||||
// {
|
||||
// path: 'customer',
|
||||
// loadChildren: () => import('./pages/setting/customer/customer.module').then(m => m.CustomerModule)
|
||||
// },
|
||||
// {
|
||||
// path: 'seller',
|
||||
// loadChildren: () => import('./pages/setting/seller/seller.module').then(m => m.SellerModule)
|
||||
// },
|
||||
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path: 'report',
|
||||
// loadChildren: () => import('./pages/report/report.module').then(m => m.ReportModule)
|
||||
// },
|
||||
{
|
||||
path: 'not-found',
|
||||
loadChildren: () => import('./pages/errors/errors.module').then(m => m.ErrorsModule)
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{ path: '**', redirectTo: 'pages/not-found' }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, { useHash: true })],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule {
|
||||
}
|
||||
|
||||
export const AppRoutingComponents = [
|
||||
ComingsoonComponent,
|
||||
PagesLayoutsComponent
|
||||
];
|
||||
1
src/app/app.component.html
Normal file
1
src/app/app.component.html
Normal file
@@ -0,0 +1 @@
|
||||
<router-outlet></router-outlet>
|
||||
8
src/app/app.component.ts
Normal file
8
src/app/app.component.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: []
|
||||
})
|
||||
export class AppComponent {}
|
||||
29
src/app/app.guard.ts
Normal file
29
src/app/app.guard.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class AppGuard implements CanActivate, CanActivateChild {
|
||||
constructor(private router: Router, private app: AppService) {
|
||||
}
|
||||
|
||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
return this.isLogin();
|
||||
}
|
||||
|
||||
canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
return this.isLogin();
|
||||
}
|
||||
|
||||
isLogin() {
|
||||
return true;
|
||||
// const user = this.app.auth();
|
||||
// if (!user) {
|
||||
// this.router.navigate(['/auth/login']);
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
}
|
||||
}
|
||||
|
||||
91
src/app/app.interface.ts
Normal file
91
src/app/app.interface.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
export interface IProduct {
|
||||
id?: number
|
||||
code?: any
|
||||
name?: string
|
||||
desc?: string
|
||||
brandId?: number
|
||||
size?: string
|
||||
weight?: string
|
||||
color?: string
|
||||
year?: string
|
||||
price?: string
|
||||
latestPrice?: string
|
||||
coverImage?: any
|
||||
images?: string
|
||||
status?: any
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: any
|
||||
category?: any
|
||||
condition?: any
|
||||
model?: any
|
||||
material?: any
|
||||
index?: any
|
||||
productCategory?: IProductCategory[]
|
||||
productMeasurement?: IProductMeasurement[]
|
||||
masterProductBrand?: IMasterProductBrand
|
||||
}
|
||||
|
||||
export interface IProductCategory {
|
||||
productId?: number
|
||||
categoryId?: number
|
||||
masterProductCategory?: IMasterProductCategory
|
||||
}
|
||||
|
||||
export interface IMasterProductCategory {
|
||||
id?: number
|
||||
code?: string
|
||||
name?: string
|
||||
status?: boolean
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: any
|
||||
|
||||
}
|
||||
|
||||
export interface IProductMeasurement {
|
||||
id: number
|
||||
productId: number
|
||||
code: any
|
||||
name: string
|
||||
size: string
|
||||
unitId: number
|
||||
status: any
|
||||
createdDate: string
|
||||
createdBy: any
|
||||
updatedDate: string
|
||||
updatedBy: any
|
||||
}
|
||||
|
||||
export interface IMasterProductBrand {
|
||||
id?: number
|
||||
code?: string
|
||||
name?: string
|
||||
status?: boolean
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: any
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export interface IAttachments {
|
||||
ref?: string
|
||||
fileOriginalName?: string
|
||||
encoding?: string
|
||||
mimetype?: string
|
||||
fileName?: string
|
||||
filePath?: string
|
||||
fileSize?: number
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: any
|
||||
deletedDate?: any
|
||||
deletedBy?: any
|
||||
id?: number
|
||||
}
|
||||
41
src/app/app.module.ts
Normal file
41
src/app/app.module.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {AppRoutingComponents, AppRoutingModule} from './app-routing.module';
|
||||
import {AppComponent} from './app.component';
|
||||
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
||||
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
|
||||
import {HTTP_INTERCEPTORS, HttpClientModule} from "@angular/common/http";
|
||||
import {AppService} from "./app.service";
|
||||
import {AppGuard} from "./app.guard";
|
||||
import {AppRequestInterceptor} from "./app.request.interceptor";
|
||||
import {AppSharedModule} from "./app.shared";
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
...AppRoutingComponents
|
||||
],
|
||||
imports: [
|
||||
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
BrowserAnimationsModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
HttpClientModule,
|
||||
AppSharedModule
|
||||
],
|
||||
providers: [
|
||||
AppService,
|
||||
AppGuard,
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: AppRequestInterceptor,
|
||||
multi: true
|
||||
},
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
||||
31
src/app/app.request.interceptor.ts
Normal file
31
src/app/app.request.interceptor.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
|
||||
import {Router} from '@angular/router';
|
||||
import {AppService} from './app.service';
|
||||
import {catchError, Observable, throwError} from 'rxjs';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class AppRequestInterceptor implements HttpInterceptor {
|
||||
constructor(private router: Router,private appService: AppService) {}
|
||||
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
const token = this.appService.token();
|
||||
|
||||
if (token) {
|
||||
request = request.clone({
|
||||
setHeaders: {Authorization: `Bearer ${token}`}
|
||||
});
|
||||
}
|
||||
|
||||
return next.handle(request).pipe(
|
||||
catchError((err) => {
|
||||
if (err instanceof HttpErrorResponse) {
|
||||
if (err.status === 401) {
|
||||
this.router.navigate(['/auth']);
|
||||
}
|
||||
}
|
||||
return throwError(err);
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
122
src/app/app.service.ts
Normal file
122
src/app/app.service.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import {Inject, Injectable} from '@angular/core';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {DOCUMENT, Location} from '@angular/common';
|
||||
import {from, Observable} from 'rxjs';
|
||||
import Swal, {SweetAlertResult} from 'sweetalert2'
|
||||
import {EAction} from "./@config/app";
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
|
||||
constructor(
|
||||
@Inject(DOCUMENT) private document: Document,
|
||||
@Inject(Location) private location: Location,
|
||||
protected httpClient: HttpClient,
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
setToken(data: any): void {
|
||||
localStorage.setItem('token', (data));
|
||||
}
|
||||
|
||||
setAuth(data: any): void {
|
||||
localStorage.setItem('user', JSON.stringify(data));
|
||||
}
|
||||
|
||||
token() {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) return null;
|
||||
return token;
|
||||
}
|
||||
|
||||
auth() {
|
||||
const user = localStorage.getItem('user');
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
return JSON.parse(user);
|
||||
}
|
||||
|
||||
async logout() {
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('user');
|
||||
localStorage.clear();
|
||||
// await lastValueFrom( this.get(this.LOGOUT_API) )
|
||||
}
|
||||
|
||||
|
||||
get(url: string): Observable<any> {
|
||||
return this.httpClient.get<any>(url);
|
||||
}
|
||||
|
||||
post(url: string, value: any, options? : any): Observable<any> {
|
||||
return this.httpClient.post<any>(url, value, options);
|
||||
}
|
||||
|
||||
delete(url: string, id: string): Observable<any> {
|
||||
return this.httpClient.delete<any>(`${url}/${id}`);
|
||||
}
|
||||
|
||||
message(action: any = 'info', msg: string = 'กรุณาตรวจสอบข้อมูล') {
|
||||
Swal.fire({icon: action, text: msg, heightAuto: false});
|
||||
}
|
||||
|
||||
html(action: any = 'info', msg: string = 'กรุณาตรวจสอบข้อมูล') {
|
||||
Swal.fire({icon: action, html: msg, heightAuto: false});
|
||||
}
|
||||
|
||||
confirm(action: string = '', confirmButtonText: string = 'ตกลง', cancelButtonText: string = 'ยกเลิก'): Observable<SweetAlertResult<boolean>> {
|
||||
let msg = '';
|
||||
if (action === EAction.CREATE) msg = 'ต้องการบันทึกข้อมูลนี้ไหม?';
|
||||
if (action === EAction.UPDATE) msg = 'ต้องการบันทึกข้อมูลนี้ไหม?';
|
||||
if (action === EAction.DELETE) msg = 'ต้องการจะลบข้อมูลนี้ไหม?';
|
||||
if (action === EAction.BACK) msg = 'ต้องการจะออกจากหน้านี้ไหม?';
|
||||
if (action === EAction.COPY) msg = 'ต้องการคัดลอกข้อมูลนี้ไหม?';
|
||||
if (action === EAction.REFINANCE) msg = 'ต้องการรีไฟแนนซ์?';
|
||||
if (action === EAction.RELOAD) msg = 'บันทึกสำเร็จ ต้องการรีเฟรชหน้าจอ?';
|
||||
|
||||
const dialog = Swal.fire({
|
||||
icon: 'warning',
|
||||
title: `${msg}`,
|
||||
heightAuto: false,
|
||||
showCancelButton: true,
|
||||
confirmButtonText: `${confirmButtonText}`,
|
||||
cancelButtonText: `${cancelButtonText}`,
|
||||
});
|
||||
return from(dialog);
|
||||
}
|
||||
|
||||
|
||||
generateParamsValue(jsonValue: any) {
|
||||
let params = '';
|
||||
Object.keys(jsonValue).forEach(key => {
|
||||
if (jsonValue[key]) {
|
||||
params += key + '=' + jsonValue[key] + '&';
|
||||
}
|
||||
});
|
||||
params = params.substring(0, params.length - 1);
|
||||
return params;
|
||||
}
|
||||
|
||||
isEmpty(data: any) {
|
||||
switch (data) {
|
||||
case '':
|
||||
case 0:
|
||||
case '0':
|
||||
case null:
|
||||
case false:
|
||||
case 'null':
|
||||
case 'undefined':
|
||||
case undefined:
|
||||
case typeof data === 'undefined':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
125
src/app/app.shared.ts
Normal file
125
src/app/app.shared.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
// ANGULAR
|
||||
import { LOCALE_ID, NgModule } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
|
||||
// MATERIAL
|
||||
import { MatTableModule } from "@angular/material/table";
|
||||
import { MatPaginatorModule } from "@angular/material/paginator";
|
||||
import { MatSortModule } from "@angular/material/sort";
|
||||
import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
|
||||
import { MatCardModule } from "@angular/material/card";
|
||||
import { MatDatepickerModule } from "@angular/material/datepicker";
|
||||
import { MatNativeDateModule, MatRippleModule } from "@angular/material/core";
|
||||
import { MatProgressBarModule } from "@angular/material/progress-bar";
|
||||
import { MatButtonToggleModule } from "@angular/material/button-toggle";
|
||||
import { MatGridListModule } from "@angular/material/grid-list";
|
||||
import { MatExpansionModule } from "@angular/material/expansion";
|
||||
import { MatAutocompleteModule } from "@angular/material/autocomplete";
|
||||
import { MatButtonModule } from "@angular/material/button";
|
||||
import { MatInputModule } from "@angular/material/input";
|
||||
import { MAT_FORM_FIELD_DEFAULT_OPTIONS, MatFormFieldDefaultOptions, MatFormFieldModule } from "@angular/material/form-field";
|
||||
import { MatTooltipModule } from "@angular/material/tooltip";
|
||||
import { MatCheckboxModule } from "@angular/material/checkbox";
|
||||
import { MatSelectModule } from "@angular/material/select";
|
||||
import { MatIconModule } from "@angular/material/icon";
|
||||
import { MatMenuModule } from "@angular/material/menu";
|
||||
import { MatTabsModule } from "@angular/material/tabs";
|
||||
import { MatRadioModule } from "@angular/material/radio";
|
||||
import { MatDialogModule } from "@angular/material/dialog";
|
||||
import { MatDividerModule } from "@angular/material/divider";
|
||||
import { MatListModule } from "@angular/material/list";
|
||||
import { MatSlideToggleModule } from "@angular/material/slide-toggle";
|
||||
|
||||
// Module
|
||||
import { NgSelectModule } from "@ng-select/ng-select";
|
||||
|
||||
// UTIL
|
||||
import { DateDiff, DateFormat, ToDateObjPipe } from "./utils/pipe";
|
||||
import { CanDirective } from "./utils/can.directive";
|
||||
import { AllowRoleDirective } from "./utils/allow-role.directives";
|
||||
import { CurrencyInputMaskDirective } from "./@common/utils/CurrencyInputMask";
|
||||
import { NumberOnlyDirective } from "./@common/utils/NumberOnlyDirective";
|
||||
|
||||
|
||||
const MAT = [
|
||||
MatAutocompleteModule,
|
||||
MatButtonModule,
|
||||
MatInputModule,
|
||||
MatRippleModule,
|
||||
MatFormFieldModule,
|
||||
MatTooltipModule,
|
||||
MatSelectModule,
|
||||
MatCheckboxModule,
|
||||
MatIconModule,
|
||||
MatMenuModule,
|
||||
MatTabsModule,
|
||||
MatRadioModule,
|
||||
MatDialogModule,
|
||||
MatInputModule,
|
||||
MatTableModule,
|
||||
MatPaginatorModule,
|
||||
MatSortModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatCardModule,
|
||||
MatDatepickerModule,
|
||||
MatNativeDateModule,
|
||||
MatRippleModule,
|
||||
MatProgressBarModule,
|
||||
MatRadioModule,
|
||||
MatButtonToggleModule,
|
||||
MatGridListModule,
|
||||
MatExpansionModule,
|
||||
MatDialogModule,
|
||||
MatIconModule,
|
||||
MatListModule,
|
||||
MatDividerModule,
|
||||
MatSlideToggleModule,
|
||||
];
|
||||
|
||||
const appearance: MatFormFieldDefaultOptions = {
|
||||
appearance: 'outline'
|
||||
};
|
||||
|
||||
const BASE_MODULES = [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule
|
||||
];
|
||||
|
||||
const MODULES = [
|
||||
MatAutocompleteModule,
|
||||
NgSelectModule,
|
||||
...MAT
|
||||
];
|
||||
|
||||
|
||||
const COMPONENTS = [
|
||||
AllowRoleDirective,
|
||||
CanDirective,
|
||||
];
|
||||
|
||||
const PIPES = [
|
||||
ToDateObjPipe,
|
||||
DateFormat,
|
||||
DateDiff,
|
||||
CurrencyInputMaskDirective,
|
||||
NumberOnlyDirective
|
||||
];
|
||||
|
||||
const PROVIDERS: any = [
|
||||
{
|
||||
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
|
||||
useValue: appearance
|
||||
},
|
||||
{ provide: LOCALE_ID, useValue: "en-GB" }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [...BASE_MODULES, ...MODULES],
|
||||
exports: [...BASE_MODULES, ...MODULES, ...COMPONENTS, ...PIPES],
|
||||
declarations: [...COMPONENTS, ...PIPES],
|
||||
providers: [...PROVIDERS],
|
||||
})
|
||||
export class AppSharedModule {
|
||||
}
|
||||
31
src/app/auth/auth-routing.module.ts
Normal file
31
src/app/auth/auth-routing.module.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {Routes, RouterModule} from '@angular/router';
|
||||
import {LoginComponent} from './login/login.component';
|
||||
|
||||
|
||||
import {AuthComponent} from './auth.component';
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: AuthComponent,
|
||||
children: [
|
||||
{path: '', redirectTo: 'login', pathMatch: 'full'},
|
||||
{path: 'login', component: LoginComponent},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AuthRoutingModule {
|
||||
}
|
||||
|
||||
|
||||
export const AuthRoutingComponents = [
|
||||
AuthComponent,
|
||||
LoginComponent,
|
||||
];
|
||||
3
src/app/auth/auth.component.html
Normal file
3
src/app/auth/auth.component.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
|
||||
15
src/app/auth/auth.component.ts
Normal file
15
src/app/auth/auth.component.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-auth',
|
||||
templateUrl: './auth.component.html',
|
||||
styles: []
|
||||
})
|
||||
export class AuthComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
15
src/app/auth/auth.module.ts
Normal file
15
src/app/auth/auth.module.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import {AppSharedModule} from '../app.shared';
|
||||
import {AuthRoutingModule, AuthRoutingComponents} from './auth-routing.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
...AuthRoutingComponents,
|
||||
],
|
||||
imports: [
|
||||
AppSharedModule,
|
||||
AuthRoutingModule
|
||||
]
|
||||
})
|
||||
export class AuthModule { }
|
||||
37
src/app/auth/login/login.component.html
Normal file
37
src/app/auth/login/login.component.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<div class="auth">
|
||||
<div class="auth-wrap">
|
||||
<div class="auth-logo">
|
||||
<img src="./assets/images/logo-b.png" />
|
||||
</div>
|
||||
|
||||
<div class="auth-card">
|
||||
<div class="auth-heading">Sign in for Admin</div>
|
||||
<form #ngf="ngForm" (ngSubmit)="onSubmit(ngf)">
|
||||
<div class="auth-card-body">
|
||||
<mat-form-field>
|
||||
<input matInput type="text" name="username" [(ngModel)]="dataForm.username" #username="ngModel"
|
||||
placeholder="Username" required>
|
||||
<i matSuffix class="bi bi-person-circle"></i>
|
||||
<mat-error *ngIf="isFieldValid(ngf, username)">กรุณากรอกข้อมูล</mat-error>
|
||||
</mat-form-field>
|
||||
<div style="height: 10px;"></div>
|
||||
<mat-form-field>
|
||||
<input matInput type="password" name="password" [(ngModel)]="dataForm.password"
|
||||
#password="ngModel" placeholder="Password" required>
|
||||
<i matSuffix class="bi bi-key"></i>
|
||||
<mat-error *ngIf="isFieldValid(ngf, password)">กรุณากรอกข้อมูล</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="auth-card-footer">
|
||||
<button type="submit" class="btn btn-primary w-full"> เข้าสู่ระบบ</button>
|
||||
</div>
|
||||
<div class="auth-card-action flex items-center">
|
||||
<div class="ml-auto mt-1">
|
||||
<mat-checkbox name="remember" [(ngModel)]="dataForm.remember">บันทึกรหัสผ่าน</mat-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
61
src/app/auth/login/login.component.ts
Normal file
61
src/app/auth/login/login.component.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {AppService} from '../../app.service';
|
||||
import {lastValueFrom} from "rxjs";
|
||||
import {API, EAction, EText} from "../../@config/app";
|
||||
import { environment } from "../../../environments/environment";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.component.html',
|
||||
styles: []
|
||||
})
|
||||
export class LoginComponent implements OnInit {
|
||||
apiUrl: string = API.login;
|
||||
dataForm: any = {};
|
||||
isLoading = false;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private appService: AppService,
|
||||
private route: ActivatedRoute
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
if (!environment.production) {
|
||||
this.dataForm = {
|
||||
username : 'admin',
|
||||
password : 'password@1',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onSubmit(form: any) {
|
||||
if (!form.valid) return false;
|
||||
const dataForm = {
|
||||
username: this.dataForm.username,
|
||||
password: this.dataForm.password,
|
||||
userType: 'ADMIN'
|
||||
};
|
||||
|
||||
|
||||
try {
|
||||
console.log(this.apiUrl)
|
||||
const result = await lastValueFrom(this.appService.post(this.apiUrl, dataForm));
|
||||
this.appService.setAuth(result.data);
|
||||
this.appService.setToken(result.accessToken);
|
||||
return this.router.navigate(['/pages']);
|
||||
} catch (err) {
|
||||
return this.appService.message(EAction.ERROR, EText.NO_DATA);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public isFieldValid(form: any, field: any) {
|
||||
return field.errors && (field.dirty || field.touched || form.submitted);
|
||||
}
|
||||
}
|
||||
11
src/app/pages/@comingsoon/comingsoon.component.html
Normal file
11
src/app/pages/@comingsoon/comingsoon.component.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="panel-header">
|
||||
PAGE
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="card">
|
||||
<div class="card-body"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
15
src/app/pages/@comingsoon/comingsoon.component.ts
Normal file
15
src/app/pages/@comingsoon/comingsoon.component.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-comingsoon',
|
||||
templateUrl: './comingsoon.component.html',
|
||||
styles: []
|
||||
})
|
||||
export class ComingsoonComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
144
src/app/pages/@layouts/layouts.component.html
Normal file
144
src/app/pages/@layouts/layouts.component.html
Normal file
@@ -0,0 +1,144 @@
|
||||
<div class="layouts" [class.active-sidebar]="isToggleSidebar">
|
||||
<div class="main-sidebar">
|
||||
<div class="main-sidebar-container">
|
||||
<div class="main-menu">
|
||||
|
||||
<section class="main-menu-heading">
|
||||
<div class="sm:hidden btn-toggle ">
|
||||
<button type="button" class="btn-icon" (click)="toggleSidebar()">
|
||||
<i class="bi bi-justify"></i>
|
||||
</button>
|
||||
</div>
|
||||
<img class="logo-main" src="./assets/images/logo.png" />
|
||||
<img class="logo-icon" src="./assets/images/logo-icon.png" />
|
||||
</section>
|
||||
|
||||
<nav class="main-menu-nav">
|
||||
<ng-template #menuTemplate let-menus>
|
||||
<div *ngFor="let item of menus; let i = index">
|
||||
<ng-container *ngIf="roleCheck(item.permission)">
|
||||
<ng-container [ngSwitch]="item.type">
|
||||
<ng-container *ngSwitchCase="'heading'">
|
||||
<div class="menu-heading">{{ item.name }}</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'link'">
|
||||
<a class="menu-item" [routerLink]="[item.link]">
|
||||
<div routerLinkActive="active" matRipple
|
||||
class="menu-item-wrap flex items-center">
|
||||
<div class="menu-item-icon"><i
|
||||
class="{{ item.icon || 'icon-sm bi bi-circle-fill' }}"></i>
|
||||
</div>
|
||||
<div class="menu-item-text">{{ item.name }}</div>
|
||||
</div>
|
||||
</a>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'collapsable'">
|
||||
<a class="menu-item menu-main-item" (click)="item.collapsed = !item.collapsed">
|
||||
<div matRipple class="menu-item-wrap flex items-center">
|
||||
<div class="menu-item-icon"><i
|
||||
class="{{ item.icon || 'icon-sm bi bi-circle-fill' }}"></i>
|
||||
</div>
|
||||
<div class="menu-item-text">{{ item.name }}</div>
|
||||
<div class="menu-item-action ml-auto">
|
||||
<i *ngIf="item.collapsed" class="bi bi-chevron-down"></i>
|
||||
<i *ngIf="!item.collapsed" class="bi bi-chevron-up"></i>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div *ngIf="item.children && item.collapsed" class="menu-item-children">
|
||||
<ng-container
|
||||
*ngTemplateOutlet="menuTemplate; context:{ $implicit: item.children }"></ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-container *ngTemplateOutlet="menuTemplate; context:{ $implicit: menus }"></ng-container>
|
||||
|
||||
<a class="menu-item menu-main-item" (click)="logout()">
|
||||
<div matRipple class="menu-item-wrap flex items-center">
|
||||
<div class="menu-item-icon"><i class="bi bi-power"></i></div>
|
||||
<div class="menu-item-text">ออกจากระบบ</div>
|
||||
</div>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main-content ">
|
||||
|
||||
<header class="main-content-header flex items-center">
|
||||
<div class="sm:block hidden btn-toggle">
|
||||
<button type="button" class="btn-icon" (click)="toggleSidebar()">
|
||||
<i class="bi bi-justify"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="sm:hidden font-bold flex flex-col">
|
||||
<span class="text-sm">CATHAY INTERNATIONAL</span>
|
||||
<span class="text-xs">Shopping Center</span>
|
||||
</div>
|
||||
<div class="title-mobile">
|
||||
<div class="text"></div>
|
||||
<div class="img">
|
||||
<img src="./assets/images/logo.png" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto flex items-center ">
|
||||
<div class="top-bar-user flex items-center" [matMenuTriggerFor]="menu">
|
||||
<div class="top-bar-user-icon">
|
||||
<i class="bi bi-person-circle"></i>
|
||||
</div>
|
||||
<div class="top-bar-user-text md:hidden">
|
||||
<div class="name">{{auth?.name || '-'}}</div>
|
||||
<div class="role"> {{auth?.email || '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</header>
|
||||
<div class="main-content-toolbar flex items-center">
|
||||
<div *ngFor="let item of breadcrumb; let i = index">
|
||||
<ng-container *ngIf="i === 0"> {{item.name}}</ng-container>
|
||||
<ng-container *ngIf="i > 0 && i +1 !== breadcrumb.length">
|
||||
<span>></span>
|
||||
<a [routerLink]="[item.link]"> {{item.name}} </a>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="i +1 === breadcrumb.length">
|
||||
<span>></span>
|
||||
<a> {{item.name}} </a>
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-content-container">
|
||||
<div id="main-top"></div>
|
||||
|
||||
<router-outlet (deactivate)="onDeactivate()"></router-outlet>
|
||||
</div>
|
||||
<div class="main-overlay">
|
||||
<div class="overlay-wrap" (click)="closeSidebar()"></div>
|
||||
<button type="button" class="btn-icon close-icon" (click)="closeSidebar()"><i
|
||||
class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<mat-menu #menu="matMenu">
|
||||
<!-- <a mat-menu-item [routerLink]="['/pages', 'account','change-password' ]" style="color: #83A5B9">-->
|
||||
<!-- <i class="bi bi-key"></i>-->
|
||||
<!-- เปลี่ยนรหัสผ่าน-->
|
||||
<!-- </a>-->
|
||||
<a mat-menu-item (click)="logout()">
|
||||
<i class="bi bi-power"></i>
|
||||
ออกจากระบบ
|
||||
</a>
|
||||
</mat-menu>
|
||||
127
src/app/pages/@layouts/layouts.component.ts
Normal file
127
src/app/pages/@layouts/layouts.component.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { AppService } from '../../app.service';
|
||||
import { MENU } from "../../@config/menus";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { API } from "../../@config/app";
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pages-layouts',
|
||||
templateUrl: './layouts.component.html',
|
||||
styles: [],
|
||||
})
|
||||
export class PagesLayoutsComponent implements OnInit {
|
||||
|
||||
menus = MENU;
|
||||
isToggleSidebar = false;
|
||||
innerWidth: any;
|
||||
auth: any = {};
|
||||
isCollapsed: any = [];
|
||||
breadcrumb: any = [];
|
||||
permissionCheck = false;
|
||||
permission: any = [];
|
||||
|
||||
constructor(
|
||||
private app: AppService,
|
||||
private router: Router,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
public changeDetectorRef: ChangeDetectorRef,
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.onCollapsed();
|
||||
this.getBreadcrumb();
|
||||
await this.initAuth();
|
||||
this.changeDetectorRef.markForCheck()
|
||||
}
|
||||
async initAuth() {
|
||||
this.auth = this.app.auth();
|
||||
|
||||
if (!this.permissionCheck) {
|
||||
const users = await lastValueFrom(this.app.get(`${API.users}/getById/${this.auth.id}`));
|
||||
this.permission = users.permission;
|
||||
this.permissionCheck = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
roleCheck(perm: string){
|
||||
if(!environment.production) return true
|
||||
return this.permission.includes(perm)
|
||||
}
|
||||
|
||||
getBreadcrumb() {
|
||||
this.breadcrumb = [];
|
||||
let router: any = this.router.url;
|
||||
router = router.split('/');
|
||||
this.mapBreadcrumb(router, this.menus)
|
||||
this.changeDetectorRef.markForCheck()
|
||||
|
||||
}
|
||||
|
||||
mapBreadcrumb(router: any, items: any) {
|
||||
items.map((item: any) => {
|
||||
this.addItemBreadcrumb(router, item);
|
||||
if (item.children) this.mapBreadcrumb(router, item.children);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
addItemBreadcrumb(router: any, item: any) {
|
||||
|
||||
const data = {
|
||||
name: item.name,
|
||||
link: item.link,
|
||||
}
|
||||
if (router[2]) {
|
||||
if (item.link === router[2]) this.breadcrumb.push(data);
|
||||
}
|
||||
if (router[3]) {
|
||||
if (item.link === `${router[2]}/${router[3]}`) this.breadcrumb.push(data);
|
||||
}
|
||||
if (router[4]) {
|
||||
if (item.link === `${router[2]}/${router[3]}/${router[4]}`) this.breadcrumb.push(data);
|
||||
}
|
||||
if (router[5]) {
|
||||
if (item.link === `${router[2]}/${router[3]}/${router[4]}/${router[5]}`) this.breadcrumb.push(data);
|
||||
}
|
||||
if (router[6]) {
|
||||
if (item.link === `${router[2]}/${router[3]}/${router[4]}/${router[5]}/${router[6]}`) this.breadcrumb.push(data);
|
||||
}
|
||||
}
|
||||
|
||||
onCollapsed() {
|
||||
let router: any = this.router.url;
|
||||
router = router.split('/');
|
||||
this.menus.forEach((item: any, i: number) => {
|
||||
// item.collapsed = false;
|
||||
if (item.type === 'collapsable') {
|
||||
if (router.includes(item.link)) {
|
||||
item.collapsed = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.app.logout();
|
||||
return this.router.navigate(['/auth']);
|
||||
}
|
||||
|
||||
|
||||
toggleSidebar() {
|
||||
this.isToggleSidebar = !this.isToggleSidebar;
|
||||
}
|
||||
|
||||
closeSidebar() {
|
||||
this.isToggleSidebar = false;
|
||||
}
|
||||
|
||||
onDeactivate() {
|
||||
this.ngOnInit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<div class="dialog-main">
|
||||
<div class="dialog-header">
|
||||
<h2>{{title}}</h2>
|
||||
</div>
|
||||
<div class="dialog-body">
|
||||
|
||||
<ng-container *ngIf="viewType === 'images' ">
|
||||
<div class="tac">
|
||||
<img src="{{viewPath}}/{{dialog.images}}" style="max-width: 100%" alt="">
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="viewType === 'vdo' ">
|
||||
<div class="video">
|
||||
<video controls #videoPlayer>
|
||||
<source src="{{viewPath}}/{{dialog.images}}" type="video/mp4" />
|
||||
Browser not supported
|
||||
</video>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
<div class="dialog-footer">
|
||||
|
||||
<button type="button" (click)="onClose()" class="btn btn-dialog-close">ปิด</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,63 @@
|
||||
import { ChangeDetectorRef, Component, Inject, OnInit } from "@angular/core";
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog";
|
||||
import { BasePopupComponent } from "../../../@common/base/base-popup.component";
|
||||
import { API, EAction, STORAGE } from "../../../@config/app";
|
||||
import { AppService } from "../../../app.service";
|
||||
import { Router } from "@angular/router";
|
||||
import { NgIf } from "@angular/common";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-attachments-view",
|
||||
templateUrl: "./attachments-view.component.html",
|
||||
styleUrls: [],
|
||||
imports: [
|
||||
NgIf
|
||||
],
|
||||
standalone: true
|
||||
})
|
||||
export class AttachmentsViewComponent extends BasePopupComponent implements OnInit {
|
||||
|
||||
title = "รายละเอียด";
|
||||
api = API;
|
||||
dataFile: any;
|
||||
storage: any = STORAGE;
|
||||
viewType = 'images';
|
||||
viewPath = STORAGE.images;
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<AttachmentsViewComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public dialog: any,
|
||||
public changeDetectorRef: ChangeDetectorRef,
|
||||
public appService: AppService,
|
||||
public router: Router
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
if (this.dialog.title) this.title = this.dialog.title;
|
||||
this.onAttachmentsType(this.dialog.images);
|
||||
if (this.dialog.storage === 'products') this.viewPath = STORAGE.products;
|
||||
|
||||
|
||||
}
|
||||
|
||||
onAttachmentsType(image?: any) {
|
||||
if (!image) return;
|
||||
const ext = image.substring(image.lastIndexOf('.'), image.length);
|
||||
|
||||
if (['.png','.jpg', '.JPEG'].includes(ext)) this.viewType = 'images' ;
|
||||
if (['.mp4'].includes(ext)) this.viewType = 'vdo' ;
|
||||
|
||||
|
||||
}
|
||||
|
||||
async onClose() {
|
||||
this.dialogRef.close(EAction.GET);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
97
src/app/pages/@popup/packet-view/packet-view.component.html
Normal file
97
src/app/pages/@popup/packet-view/packet-view.component.html
Normal file
@@ -0,0 +1,97 @@
|
||||
<div class="dialog-main">
|
||||
<div class="dialog-header">
|
||||
<h2>{{title}}</h2>
|
||||
</div>
|
||||
<div class="dialog-body">
|
||||
|
||||
<div class="card card-form-panel mt-2">
|
||||
<div class="card-header ">
|
||||
<div class="">ข้อมูล Packet</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ng-container *ngFor="let item of packetDetail; let i = index">
|
||||
<div class="form-list">
|
||||
<div class="form-list-item grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-2 md:col-span-4">
|
||||
<label *ngIf="i === 0">รหัส</label>
|
||||
<mat-form-field>
|
||||
<input matInput name="code-{{i}}" #code="ngModel" [(ngModel)]="item.code" required disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-6 md:col-span-8">
|
||||
<label *ngIf="i === 0">รายการจัดผ่อน</label>
|
||||
<mat-form-field>
|
||||
<input appNumberOnly matInput name="name-{{i}}" #name="ngModel" [(ngModel)]="item.name" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-6">
|
||||
<label *ngIf="i === 0">จำนวน</label>
|
||||
<mat-form-field>
|
||||
<input appNumberOnly matInput name="value-{{i}}" #value="ngModel" [(ngModel)]="item.value" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-6">
|
||||
<label *ngIf="i === 0">หน่วยนับ</label>
|
||||
<ng-select placeholder="เลือกหน่วยนับ" name="unitId-{{i}}" #unit="ngModel" [(ngModel)]="item.unit" appendTo="body" disabled>
|
||||
<ng-option *ngFor="let item of settingInstallmentUnit" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel mt-6">
|
||||
<div class="card-header ">
|
||||
<div class="">โปรโมชั่น</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div style="height: 10px;"></div>
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 items-center mb-1">
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<ng-select placeholder="" name="promotionId" #promotionId="ngModel" [(ngModel)]="dataView.promotionId" appendTo="body" disabled>
|
||||
<ng-option *ngFor="let item of promotionData" [value]="item.id">{{item.name}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
</div>
|
||||
<ng-container *ngIf="promotionDetail">
|
||||
<ng-container *ngFor="let item of promotionDetail; let i = index">
|
||||
<ng-container *ngIf="item.status">
|
||||
|
||||
<div class="form-list">
|
||||
<div class="form-list-item grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-8 md:col-span-10 ">
|
||||
<div *ngIf="i === 0" style="height: 25px;"></div>
|
||||
<mat-form-field>
|
||||
<input appNumberOnly matInput name="promotionName-{{i}}" #promotionName="ngModel" [(ngModel)]="item.name" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<!-- <div class="col-span-2 md:col-span-6">-->
|
||||
<!-- <label *ngIf="i === 0">จำนวน</label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <input appNumberOnly matInput name="promotionValue-{{i}}" #promotionValue="ngModel" [(ngModel)]="item.value" disabled>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-span-2 md:col-span-6">-->
|
||||
<!-- <label *ngIf="i === 0">หน่วยนับ</label>-->
|
||||
<!-- <ng-select placeholder="เลือกหน่วยนับ" name="promotionUnitId-{{i}}" #promotionUnit="ngModel" [(ngModel)]="item.unit" appendTo="body" disabled>-->
|
||||
<!-- <ng-option *ngFor="let item of unitData" [value]="item">{{item}}</ng-option>-->
|
||||
<!-- </ng-select>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<div style="height: 20px;"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="dialog-footer">
|
||||
<button type="button" (click)="onClose()" class="btn btn-dialog-close">ปิด</button>
|
||||
</div>
|
||||
</div>
|
||||
75
src/app/pages/@popup/packet-view/packet-view.component.ts
Normal file
75
src/app/pages/@popup/packet-view/packet-view.component.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { ChangeDetectorRef, Component, Inject, OnInit } from "@angular/core";
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog";
|
||||
import { BasePopupComponent } from "../../../@common/base/base-popup.component";
|
||||
import { API, EAction, STORAGE } from "../../../@config/app";
|
||||
import { AppService } from "../../../app.service";
|
||||
import { Router } from "@angular/router";
|
||||
import { NgForOf, NgIf } from "@angular/common";
|
||||
import { AppSharedModule } from "../../../app.shared";
|
||||
import { FormsModule } from "@angular/forms";
|
||||
import { MatFormFieldModule } from "@angular/material/form-field";
|
||||
import { MatInputModule } from "@angular/material/input";
|
||||
import { NgSelectModule } from "@ng-select/ng-select";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import deepCopy from "../../../@common/utils/DeepCopy";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-packet-view",
|
||||
templateUrl: "./packet-view.component.html",
|
||||
styleUrls: [],
|
||||
imports: [
|
||||
NgIf,
|
||||
AppSharedModule,
|
||||
FormsModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
NgForOf,
|
||||
NgSelectModule
|
||||
],
|
||||
standalone: true
|
||||
})
|
||||
export class PacketViewComponent extends BasePopupComponent implements OnInit {
|
||||
|
||||
title = "รายละเอียด Packet";
|
||||
api : any = API;
|
||||
dataView: any = {};
|
||||
storage: any = STORAGE;
|
||||
|
||||
|
||||
settingInstallmentUnit: any = ["บาท", "%"];
|
||||
packetDetail: any = [];
|
||||
promotionDetail: any = [];
|
||||
promotionData: any = [];
|
||||
unitData: any = ["%"];
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<PacketViewComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public dialog: any,
|
||||
public changeDetectorRef: ChangeDetectorRef,
|
||||
public appService: AppService,
|
||||
public router: Router
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
if (this.dialog.title) this.title = this.dialog.title;
|
||||
this.promotionData = await lastValueFrom(this.appService.get(`${this.api.promotion}?showAll=true&status=true`));
|
||||
const data = deepCopy(this.dialog.data);
|
||||
this.dataView = data;
|
||||
this.packetDetail = data.packetDetail;
|
||||
this.promotionDetail = data.promotion?.promotionDetail;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
async onClose() {
|
||||
this.dialogRef.close(EAction.GET);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {Routes, RouterModule} from '@angular/router';
|
||||
import {Appraisal1stTimeIndexComponent} from './index/appraisal-1st-time-index.component';
|
||||
import {Appraisal1stTimeDoComponent} from "./do/appraisal-1st-time-do.component";
|
||||
import { Appraisal1stTimeHistoryComponent } from "./history/appraisal-1st-time-history.component";
|
||||
import { Appraisal1stTimePdfComponent } from "./pdf/appraisal-1st-time-pdf.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '', component: Appraisal1stTimeIndexComponent},
|
||||
{path: 'do/:action', component: Appraisal1stTimeDoComponent},
|
||||
{path: 'do/:action/:id', component: Appraisal1stTimeDoComponent},
|
||||
{path: 'history', component: Appraisal1stTimeHistoryComponent},
|
||||
{path: 'history/pdf/:id', component: Appraisal1stTimePdfComponent},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class RoutingModule {
|
||||
}
|
||||
|
||||
export const RoutingComponents = [
|
||||
Appraisal1stTimeIndexComponent,
|
||||
Appraisal1stTimeDoComponent,
|
||||
Appraisal1stTimeHistoryComponent,
|
||||
Appraisal1stTimePdfComponent,
|
||||
];
|
||||
@@ -0,0 +1,16 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import {RoutingComponents, RoutingModule} from './appraisal-1st-time-routing.module';
|
||||
import {AppSharedModule} from "../../../app.shared";
|
||||
import { NgOptimizedImage } from "@angular/common";
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
...RoutingComponents,
|
||||
],
|
||||
imports: [
|
||||
AppSharedModule,
|
||||
RoutingModule,
|
||||
NgOptimizedImage
|
||||
]
|
||||
})
|
||||
export class Appraisal1stTimeModule {}
|
||||
@@ -0,0 +1,391 @@
|
||||
<form class="main-form" #ngf="ngForm" (ngSubmit)="onSubmit(ngf)">
|
||||
<form #ngfCalculate="ngForm" (ngSubmit)="onCalculate(ngfCalculate)">
|
||||
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 h-full">
|
||||
<div class="col-span-6 md:col-span-12">
|
||||
<div class="card card-form-panel card-form-panel-blue h-full">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> กรอกข้อมูลการจัดผ่อน <span class="color-red">(ราคาล่าสุด {{dataView.latestPrice | number : '1.2-2'}} บาท)</span></div>
|
||||
</div>
|
||||
<div class="card-body form-input-list">
|
||||
<div style="height: 20px;"></div>
|
||||
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> เลือก Packet</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<ng-select placeholder="เลือก Packet" name="packetId" #packetId="ngModel" [(ngModel)]="dataForm.packetId" (ngModelChange)="onChangePacket($event)" appendTo="body" required>
|
||||
<ng-option *ngFor="let item of packets" [value]="item.id">{{item.name}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit" *ngIf="dataForm.packetId">
|
||||
<i (click)="onPacketView()" class="bi bi-search color-main cursor-pointer"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> วันที่เริ่มจัดผ่อน</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
name="startDate"
|
||||
#startDate="ngModel"
|
||||
(click)="dpkName.open()"
|
||||
[(ngModel)]="dataForm.startDate"
|
||||
[matDatepicker]="dpkName"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
<mat-datepicker-toggle [for]="dpkName" matSuffix></mat-datepicker-toggle>
|
||||
<mat-datepicker #dpkName></mat-datepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> ราคา (Price)</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="price" #price="ngModel" [(ngModel)]="dataForm.price" (ngModelChange)="onChange($event, 'price')" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> มัดจำแม่ค้า</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="sellerDeposit" #sellerDeposit="ngModel" [(ngModel)]="dataForm.sellerDeposit" (ngModelChange)="onChange($event, 'sellerDeposit')" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> มัดจำ CMFS</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="deposit" #deposit="ngModel" [(ngModel)]="dataForm.deposit" (ngModelChange)="onChange($event, 'deposit')" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> เงินต้นคงเหลือ (Total)</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="principalBalanceTotal" #principalBalanceTotal="ngModel" [(ngModel)]="dataForm.principalBalanceTotal" required disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> ต้องการผ่อน (Term)</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput type="number" name="wantToInstallmentTerm" #wantToInstallmentTerm="ngModel" [(ngModel)]="dataForm.wantToInstallmentTerm" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">งวด</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action">
|
||||
<button type="button" class="btn btn-back" (click)="onCalculateReset()">ล้างข้อมูล</button>
|
||||
<button type="submit" class="btn btn-submit">คำนวน</button>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-6 md:col-span-12 ">
|
||||
<div class="card card-form-panel card-form-panel-blue h-full">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> รายละเอียดค่าใช้จ่ายในการโอนเงิน</div>
|
||||
</div>
|
||||
<div class="card-body form-input-list">
|
||||
<div style="height: 20px;"></div>
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> มัดจำ CMFS Deposit</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="cmfsDeposit" #cmfsDeposit="ngModel" [(ngModel)]="dataForm.cmfsDeposit" (ngModelChange)="onChange($event, 'cmfsDeposit')" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> หัก เงินมัดจำแม่ค้า </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="lessSellerDeposit" #lessSellerDeposit="ngModel" [(ngModel)]="dataForm.lessSellerDeposit" (ngModelChange)="onChange($event, 'lessSellerDeposit')">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> บวก Packing </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="plusPacking" #plusPacking="ngModel" [(ngModel)]="dataForm.plusPacking" (ngModelChange)="onChange($event, 'plusPacking')" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> บวก Luxury handbag </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="plusLuxuryHandbag" #plusLuxuryHandbag="ngModel" [(ngModel)]="dataForm.plusLuxuryHandbag" (ngModelChange)="onChange($event, 'plusLuxuryHandbag')" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> บวก Bank fee, Insurance , Storage</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="plusBankFee" #plusBankFee="ngModel" [(ngModel)]="dataForm.plusBankFee" (ngModelChange)="onChange($event, 'plusBankFee')" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> ส่วนลด </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="discount" #discount="ngModel" [(ngModel)]="dataForm.discount" (ngModelChange)="onChange($event, 'discount')" >
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> สรุปยอดโอน </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="transferSummary" #transferSummary="ngModel" [(ngModel)]="dataForm.transferSummary" disabled >
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
<div style="height: 20px;"></div>
|
||||
<div class="card card-table mb-6">
|
||||
<div class="card-body">
|
||||
<div *ngIf="!dataForm.quotationDetail?.[0]" class="no-data color-red font-bold"> กรุณากรอกข้อมูลการจัดผ่อนเพื่อแสดงตารางผ่อนชำระ</div>
|
||||
<div class="table-wrap" *ngIf="dataForm.quotationDetail?.[0]">
|
||||
<table class="tables">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>งวดที่</th>
|
||||
<th>กำหนดจ่ายวันที่ <br>Due date</th>
|
||||
<th>เงินต้น <br>Principle</th>
|
||||
<th>ดอกเบี้ย(บาท) <br>Interest Total</th>
|
||||
<th>Bank fee, <br>Insurance ,Storage</th>
|
||||
<th>รวมยอดจ่ายต่อเดือน <br>Total payment</th>
|
||||
<th>เงินต้นคงเหลือ <br>Principle Total</th>
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
<tbody>
|
||||
<ng-container *ngFor="let item of dataForm.quotationDetail; let i = index">
|
||||
<tr>
|
||||
<td class="text-center">{{item.installment }}</td>
|
||||
<td class="text-center">{{item.dueDate | date : 'dd/MM/YYYY'}}</td>
|
||||
<td class="text-center">{{item.principle | number: '1.0-0'}}</td>
|
||||
<td class="text-center">{{item.interestTotal | number: '1.0-0'}}</td>
|
||||
<td class="text-center">{{item.fee | number: '1.0-0'}}</td>
|
||||
<td class="text-center"><span class="b-color-green">{{item.totalPayment | number: '1.0-0'}}</span></td>
|
||||
<td class="text-center"><span class="b-color-orange" *ngIf="item.principleTotal">{{item.principleTotal | number: '1.0-0'}}</span></td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
<tr>
|
||||
<td colspan="2" class="text-right"><b>รวม</b></td>
|
||||
<td class="text-center">{{dataForm.principleSum | number: '1.0-0'}}</td>
|
||||
<td class="text-center">{{dataForm.interestTotalSum | number: '1.0-0'}}</td>
|
||||
<td class="text-center">{{dataForm.feeSum | number: '1.0-0'}}</td>
|
||||
<td class="text-center"><span class="b-color-green">{{dataForm.totalPaymentSum | number: '1.0-0'}}</span></td>
|
||||
<td class="text-center"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> ข้อมูลลูกค้า</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 mt-4 mb-4">
|
||||
<div class="col-span-3 md:col-span-12 ">
|
||||
<mat-label>คำนำหน้า</mat-label>
|
||||
<ng-select placeholder="เลือกคำนำหน้า" name="prefix" #prefix="ngModel" [(ngModel)]="dataForm.customerPrefix" appendTo="body" >
|
||||
<ng-option *ngFor="let item of prefixData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-3 md:col-span-12 ">
|
||||
<mat-label>ชื่อลูกค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="customerFirstName" #customerFirstName="ngModel" [(ngModel)]="dataForm.customerFirstName" >
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-3 md:col-span-12 ">
|
||||
<mat-label>นามสกุล</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="customerLastName" #customerLastName="ngModel" [(ngModel)]="dataForm.customerLastName">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-3 md:col-span-12 ">
|
||||
<mat-label>เบอร์โทร</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="customerPhone" #customerPhone="ngModel" [(ngModel)]="dataForm.customerPhone">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- <div class="col-span-3 md:col-span-12 ">-->
|
||||
<!-- <mat-label>BOM</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <input matInput name="productNo" #productNo="ngModel" [(ngModel)]="dataForm.productNo" required>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
<div class="col-span-3 md:col-span-12 ">
|
||||
<mat-label>ประเภทรหัส</mat-label>
|
||||
<ng-select placeholder="ประเภทรหัส" name="typeCode" #typeCode="ngModel" [(ngModel)]="dataForm.typeCode" appendTo="body" required>
|
||||
<ng-option *ngFor="let item of typeCodeData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<!-- <div class="col-span-3 md:col-span-12 ">-->
|
||||
<!-- <mat-label>เลขที่ใบเสนอราคา</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <input matInput name="quotationNo" #quotationNo="ngModel" [(ngModel)]="dataForm.quotationNo" required>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-span-9 md:hidden"></div>-->
|
||||
|
||||
<div class="col-span-3 md:col-span-12 ">
|
||||
<mat-label>ชื่อพนักงาน</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="userFullName" #userFullName="ngModel" [(ngModel)]="dataForm.userFullName" required disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title flex items-center">
|
||||
<div class="">รูปสินค้าจากลูกค้า</div>
|
||||
|
||||
<div class="ml-4">
|
||||
<input hidden type="file" accept="image/*" #productImages (change)="onAttachments($event, 'products')" />
|
||||
<button type="button" class="btn btn-sm btn-success-o" (click)="productImages.click()">เพิ่มรูปภาพสินค้า</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="list-images">
|
||||
<div class=" grid grid-cols-12 gap-2 md:gap-2 items-center">
|
||||
<ng-container *ngFor="let item of attachments; let i = index">
|
||||
<div class="col-span-2 md:col-span-4">
|
||||
<div class="flex justify-center items-center list-images-item">
|
||||
<div class="list-images-action">
|
||||
<i *ngIf="dataForm.coverImage !== item" (click)="dataForm.coverImage = item"
|
||||
matTooltip="ใช้ทำเอกสาร" class="bi bi-star color-main cursor-pointer select-none"></i>
|
||||
<i *ngIf="dataForm.coverImage === item" class="bi bi bi-star-fill color-main cursor-pointer select-none"></i>
|
||||
<i (click)="onRemoveAttachments(i, item)" class="bi bi-x-circle color-red cursor-pointer select-none"></i>
|
||||
</div>
|
||||
<img src="{{storage.products}}/{{item}}" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main-form-action text-right">
|
||||
<button type="submit" class="btn btn-submit">บันทึก</button>
|
||||
<button type="button" class="btn btn-back" (click)="onAction('back')">ยกเลิก</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@@ -0,0 +1,309 @@
|
||||
import {ChangeDetectorRef, Component, OnInit} from "@angular/core";
|
||||
import {API, EAction, EText, PREFIX, STORAGE, TYPE_CODE} from "../../../../@config/app";
|
||||
import {AppService} from "../../../../app.service";
|
||||
import {lastValueFrom} from "rxjs";
|
||||
import {BaseFormComponent} from "../../../../@common/base/base-form.component";
|
||||
import {ActivatedRoute, Router} from "@angular/router";
|
||||
import {IProduct} from "../../../../app.interface";
|
||||
import {addMonths, differenceInDays} from "date-fns";
|
||||
import deepCopy from "../../../../@common/utils/DeepCopy";
|
||||
import {PacketViewComponent} from "../../../@popup/packet-view/packet-view.component";
|
||||
import {MatDialog} from "@angular/material/dialog";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-1st-time-do",
|
||||
templateUrl: "./appraisal-1st-time-do.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class Appraisal1stTimeDoComponent extends BaseFormComponent implements OnInit {
|
||||
|
||||
override dataForm: any = {};
|
||||
dataView: IProduct = {};
|
||||
auth: any = {};
|
||||
title = "";
|
||||
api: any = API;
|
||||
storage: any = STORAGE;
|
||||
addItemNumber: number = 1;
|
||||
attachments: any = [];
|
||||
settings: any = [];
|
||||
packets: any = [];
|
||||
packetData: any = {};
|
||||
promotionDetail: any = [];
|
||||
IN01: any = {};
|
||||
IN05: any = {};
|
||||
prefixData = PREFIX;
|
||||
typeCodeData = TYPE_CODE;
|
||||
|
||||
|
||||
|
||||
constructor(
|
||||
public activatedRoute: ActivatedRoute,
|
||||
public router: Router,
|
||||
public changeDetectorRef: ChangeDetectorRef,
|
||||
public appService: AppService,
|
||||
private packetDialog: MatDialog,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.activatedRoute.params.subscribe(async params => {
|
||||
this.ids = params["id"];
|
||||
this.action = params["action"];
|
||||
this.auth = this.appService.auth();
|
||||
this.settings = await lastValueFrom(this.appService.get(`${this.api.settings}?showAll=true&status=true&orderBy=code&sort=asc&codeIn=IN01,IN02,IN03,IN04,IN05`));
|
||||
this.packets = await lastValueFrom(this.appService.get(`${API.packet}?showAll=true&status=true`));
|
||||
if (this.ids) await this.getData();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
async onAction(action: string) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.BACK));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
if (action === "back") return this.router.navigate(["/pages/appraisal/1st-time"]);
|
||||
return;
|
||||
}
|
||||
|
||||
async getData() {
|
||||
if (!this.ids) this.appService.message(EAction.INFO, EText.NO_DATA);
|
||||
try {
|
||||
this.dataForm = {};
|
||||
this.dataView = await lastValueFrom(this.appService.get(`${this.api.products}/getById/${this.ids}`));
|
||||
this.attachments = this.dataView.images ? this.dataView.images?.split(",") : [];
|
||||
|
||||
this.dataForm.startDate = new Date();
|
||||
|
||||
|
||||
this.dataForm.cmfsDeposit = 0;
|
||||
this.dataForm.deposit = 0;
|
||||
this.dataForm.plusPacking = 0;
|
||||
this.dataForm.plusLuxuryHandbag = 0;
|
||||
this.dataForm.plusBankFee = 0;
|
||||
this.dataForm.settingCmfsDeposit = 0;
|
||||
this.dataForm.settingInterestRate = 0;
|
||||
this.dataForm.discount = 0;
|
||||
this.dataForm.sellerDeposit = 0;
|
||||
this.dataForm.lessSellerDeposit = 0;
|
||||
|
||||
// this.dataForm.productNo = this.dataView.code;
|
||||
this.dataForm.productName = this.dataView.name;
|
||||
this.dataForm.coverImage = this.dataView.coverImage;
|
||||
this.dataForm.productId = this.dataView.id;
|
||||
this.dataForm.productSize = this.dataView.size;
|
||||
this.dataForm.productWeight = this.dataView.weight;
|
||||
this.dataForm.productColor = this.dataView.color;
|
||||
this.dataForm.productYear = this.dataView.year;
|
||||
this.dataForm.productPrice = this.dataView.price;
|
||||
this.dataForm.productLatestPrice = this.dataView.latestPrice;
|
||||
this.dataForm.productBrandName = this.dataView.masterProductBrand?.name;
|
||||
this.dataForm.productMeasurement = this.dataView.productMeasurement;
|
||||
this.dataForm.userFullName = this.auth.name;
|
||||
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
async onChangePacket(value: string) {
|
||||
this.dataForm.plusPacking = 0;
|
||||
this.dataForm.plusLuxuryHandbag = 0;
|
||||
this.dataForm.plusBankFee = 0;
|
||||
this.dataForm.settingCmfsDeposit = 0;
|
||||
this.dataForm.settingInterestRate = 0;
|
||||
|
||||
if (!value) return;
|
||||
|
||||
this.packetData = await lastValueFrom(this.appService.get(`${API.packet}/getById/${value}`));
|
||||
if (!this.packetData.packetDetail) return;
|
||||
this.dataForm.plusPacking = this.packetData.packetDetail.find((f: { code: string; }) => f.code === "IN02").value;
|
||||
this.dataForm.plusLuxuryHandbag = this.packetData.packetDetail.find((f: { code: string; }) => f.code === "IN03").value;
|
||||
this.dataForm.plusBankFee = this.packetData.packetDetail.find((f: { code: string; }) => f.code === "IN04").value;
|
||||
this.dataForm.settingCmfsDeposit = this.packetData.packetDetail.find((f: { code: string; }) => f.code === "IN01").value;
|
||||
this.dataForm.settingInterestRate = this.packetData.packetDetail.find((f: { code: string; }) => f.code === "IN05").value;
|
||||
|
||||
this.promotionDetail = this.packetData?.promotion?.promotionDetail;
|
||||
|
||||
this.onChange(this.dataForm.price, 'price');
|
||||
this.dataForm.quotationDetail = [];
|
||||
}
|
||||
|
||||
onChange($event: any, key?: string) {
|
||||
if (key) this.dataForm[key] = $event;
|
||||
this.changeDetectorRef.detectChanges();
|
||||
|
||||
if (key === "price") {
|
||||
const IN01 = Number(this.dataForm.settingCmfsDeposit) / 100;
|
||||
this.dataForm.price = this.dataForm.price ? this.dataForm.price : 0;
|
||||
this.dataForm.deposit = IN01 * this.dataForm.price;
|
||||
this.dataForm.cmfsDeposit = IN01 * this.dataForm.price;
|
||||
}
|
||||
this.dataForm.sellerDeposit = this.dataForm.sellerDeposit ? this.dataForm.sellerDeposit : 0;
|
||||
this.dataForm.deposit = this.dataForm.deposit ? this.dataForm.deposit : 0;
|
||||
|
||||
if (key === "sellerDeposit") {
|
||||
this.dataForm.lessSellerDeposit = this.dataForm.sellerDeposit;
|
||||
}
|
||||
if (key === "deposit") {
|
||||
this.dataForm.cmfsDeposit = this.dataForm.deposit;
|
||||
}
|
||||
if (key === "cmfsDeposit") {
|
||||
this.dataForm.deposit = this.dataForm.cmfsDeposit;
|
||||
}
|
||||
|
||||
|
||||
this.dataForm.principalBalanceTotal = this.dataForm.price - this.dataForm.deposit;
|
||||
|
||||
|
||||
this.dataForm.transferSummary = Number(this.dataForm.cmfsDeposit) +
|
||||
Number(this.dataForm.plusPacking) +
|
||||
Number(this.dataForm.plusLuxuryHandbag) +
|
||||
Number(this.dataForm.plusBankFee) -
|
||||
Number(this.dataForm.lessSellerDeposit) -
|
||||
Number(this.dataForm.discount);
|
||||
this.changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
async onCalculate(form: any) {
|
||||
if (!form.valid) return false;
|
||||
|
||||
|
||||
this.dataForm.quotationDetail = [];
|
||||
const principle = this.dataForm.principalBalanceTotal / this.dataForm.wantToInstallmentTerm;
|
||||
|
||||
let principleTotalBefore = Number(this.dataForm.principalBalanceTotal);
|
||||
|
||||
let startDate = this.dataForm.startDate;
|
||||
|
||||
const IN05 = Number(this.dataForm.settingInterestRate) / 100;
|
||||
for (let i = 0; i < this.dataForm.wantToInstallmentTerm; i++) {
|
||||
|
||||
let item = {
|
||||
installment: i + 1,
|
||||
dueDate: addMonths(this.dataForm.startDate, i + 1),
|
||||
principle: Number(principle),
|
||||
interestTotal: 0,
|
||||
interestRate: this.promotionDetail?.[i].value,
|
||||
isInterest: this.promotionDetail?.[i].status,
|
||||
fee: Number(this.dataForm.plusBankFee),
|
||||
totalPayment: 0,
|
||||
principleTotal: 0,
|
||||
interestPerDays: 0
|
||||
};
|
||||
|
||||
const interestPerDays = differenceInDays(item.dueDate, startDate) + 1;
|
||||
item.interestTotal = principleTotalBefore * IN05 * interestPerDays / 365;
|
||||
item.interestPerDays = interestPerDays;
|
||||
if (item.isInterest) item.interestTotal = 0;
|
||||
item.totalPayment = item.principle + item.interestTotal + item.fee;
|
||||
item.principleTotal = principleTotalBefore - item.principle;
|
||||
|
||||
|
||||
startDate = item.dueDate;
|
||||
|
||||
principleTotalBefore = item.principleTotal;
|
||||
|
||||
console.log(item)
|
||||
this.dataForm.quotationDetail.push(item);
|
||||
|
||||
this.dataForm.principleSum = 0;
|
||||
this.dataForm.interestTotalSum = 0;
|
||||
this.dataForm.feeSum = 0;
|
||||
this.dataForm.feeSum = 0;
|
||||
this.dataForm.totalPaymentSum = 0;
|
||||
|
||||
this.dataForm.quotationDetail.map((item: any) => {
|
||||
this.dataForm.principleSum += Number(item.principle);
|
||||
this.dataForm.interestTotalSum += Number(item.interestTotal);
|
||||
this.dataForm.feeSum += Number(item.fee);
|
||||
this.dataForm.totalPaymentSum += Number(item.totalPayment);
|
||||
});
|
||||
this.dataForm.principleSum = Math.round(this.dataForm.principleSum);
|
||||
|
||||
}
|
||||
console.log("quotationDetail", this.dataForm.quotationDetail);
|
||||
return;
|
||||
}
|
||||
|
||||
async onCalculateReset() {
|
||||
return await this.getData();
|
||||
}
|
||||
|
||||
async onSubmit(form: any) {
|
||||
if (!form.valid) return false;
|
||||
if (!this.dataForm.quotationDetail?.[0]) return this.appService.message(EAction.ERROR, "กรุณากรอกข้อมูลการจัดผ่อนเพื่อแสดงตารางผ่อนชำระ");
|
||||
this.dataForm.images = this.attachments?.[0] ? this.attachments.join(",") : null;
|
||||
|
||||
if (this.action === EAction.CREATE) return await this.onCreate();
|
||||
if (this.action === EAction.UPDATE) return await this.onUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
async onCreate() {
|
||||
try {
|
||||
await lastValueFrom(this.appService.post(this.api.quotation, this.dataForm));
|
||||
await this.appService.message(EAction.SUCCESS, EText.CREATE);
|
||||
await this.router.navigate(["/pages/appraisal/1st-time"]);
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
async onUpdate() {
|
||||
try {
|
||||
await lastValueFrom(this.appService.post(`${this.api.quotation}/update/${this.ids}`, this.dataForm));
|
||||
await this.appService.message(EAction.SUCCESS, EText.UPDATE);
|
||||
await this.router.navigate(["/pages/setting/products"]);
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async onAttachments($event: any, type: any) {
|
||||
const file = $event.target.files[0];
|
||||
if (!file) return;
|
||||
const formData = new FormData();
|
||||
formData.append("ref", type);
|
||||
formData.append("file", file);
|
||||
try {
|
||||
const res = await lastValueFrom(this.appService.post(`${this.api.attachments}/products`, formData));
|
||||
if (!this.attachments[0]) {
|
||||
this.dataForm.coverImage = res.fileName;
|
||||
}
|
||||
this.attachments.push(res.fileName);
|
||||
console.log(this.attachments, res);
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} catch (e) {
|
||||
this.appService.message(EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
async onRemoveAttachments(i: number, fileName: string) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.DELETE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
// await lastValueFrom(this.appService.delete(`${this.api.attachments}/deleteByName`, fileName));
|
||||
this.attachments?.splice(i, 1);
|
||||
if (!this.attachments[0]) {
|
||||
this.dataForm.coverImage = null;
|
||||
}
|
||||
this.changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
async onPacketView() {
|
||||
const dialogConfig = deepCopy(this.dialogConfig);
|
||||
dialogConfig.data.action = EAction.POPUP;
|
||||
dialogConfig.data.title = 'รายละเอียด Packet';
|
||||
dialogConfig.data.data = this.packetData;
|
||||
|
||||
const dialogRef = this.packetDialog.open(PacketViewComponent, dialogConfig);
|
||||
const afterClosed = await lastValueFrom(dialogRef.afterClosed());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<div class="card card-table">
|
||||
|
||||
<div class="card-filter text-right">
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-5 md:col-span-12 md:order-2">
|
||||
<mat-form-field>
|
||||
<i matTextPrefix class="bi bi-search"></i>
|
||||
<input matInput name="keyword" #keyword="ngModel" [(ngModel)]="dataFilter.keyword" (ngModelChange)="onFilter($event)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-7 md:col-span-12 md:order-1">
|
||||
<div class="card-header-action">
|
||||
<button type="button" class="btn btn-export" (click)="onExport()">Export</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 items-center md:gap-2 ">
|
||||
<div class="col-span-3 md:col-span-6">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
name="startDate"
|
||||
#startDate="ngModel"
|
||||
(click)="dpkName.open()"
|
||||
[(ngModel)]="dataFilter.createdDate"
|
||||
[matDatepicker]="dpkName"
|
||||
readonly
|
||||
(ngModelChange)="getData()"
|
||||
|
||||
/>
|
||||
<!-- <mat-icon matSuffix (click)="clearDate($event)">clear</mat-icon>-->
|
||||
<mat-datepicker-toggle [for]="dpkName" matSuffix></mat-datepicker-toggle>
|
||||
<mat-datepicker #dpkName></mat-datepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-9 md:col-span-12 ">
|
||||
<div class="flex w-full ">
|
||||
<div class="">จำนวนทั้งหมด {{totalItem}} รายการ</div>
|
||||
<div class="pl-2 pr-2">|</div>
|
||||
<div class="">ค้นหาจำนวน {{totalOfElement}} รายการ</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-wrap">
|
||||
<table class="table table-main" mat-table [dataSource]="dataSource" matSort (matSortChange)="onSort($event)">
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
|
||||
<ng-container matColumnDef="quotationNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>เลขที่ใบเสนอราคา</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">{{item.quotationNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="customerFirstName">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>ชื่อลูกค้า</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">
|
||||
<ng-container *ngIf="item.customerId"> {{item.customer?.prefix}}{{item.customer?.firstName}} {{item.customer?.lastName}}</ng-container>
|
||||
<ng-container *ngIf="!item.customerId">{{item.customerFirstName}} {{item.customerLastName}}</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" mat-sort-header>BOM</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="tac">{{item.productNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productName">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Model</th>
|
||||
<td mat-cell *matCellDef="let item" class="" style="min-width: 200px;">{{item.productName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="price">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>จำนวนเงิน</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-green"> {{item.price | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="wantToInstallmentTerm">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ระยะเวลาผ่อน</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.wantToInstallmentTerm }} งวด</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="createdDate">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">วันที่บันทึก</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.createdDate | date : 'dd/MM/YYYY'}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">สถานะ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.status === 'paid' " class="status status-active">ชำระแล้ว</div>
|
||||
<div *ngIf="item.status === 'pending'" class="status status-disabled">รอชำระ</div>
|
||||
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="action">
|
||||
<th mat-header-cell *matHeaderCellDef width="80">Action</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="action flex justify-center">
|
||||
|
||||
<div class="item">
|
||||
<i class="bi bi-filetype-pdf color-main" (click)="onAction(item.id)"></i>
|
||||
</div>
|
||||
<div class="item" *ngIf="item.status === 'pending'">
|
||||
<i class="bi bi-trash3 color-red" (click)="onDelete(item.id)"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
</table>
|
||||
<div *ngIf="dataSourceCount === 0" class="no-data"></div>
|
||||
</div>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" showFirstLastButtons (page)="getData($event)"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,91 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { BaseListComponent } from "../../../../@common/base/base-list.component";
|
||||
import { debounceTime, distinctUntilChanged, lastValueFrom, Subject } from "rxjs";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { API, EAction, EText } from "../../../../@config/app";
|
||||
import { Router } from "@angular/router";
|
||||
import generateParamsValue from "../../../../@common/utils/GenerateParamsValue";
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-1st-time-index",
|
||||
templateUrl: "./appraisal-1st-time-history.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class Appraisal1stTimeHistoryComponent extends BaseListComponent implements OnInit {
|
||||
|
||||
pageTitle = "ประวัติการสร้างใบเสนอราคา";
|
||||
apiUrl: string = API.quotation;
|
||||
api: any = API;
|
||||
displayedColumns: string[] = ["action","price", "quotationNo", "customerFirstName", "productName", "wantToInstallmentTerm", "createdDate", "status"];
|
||||
masterProductCategory: any = [];
|
||||
masterProductBrand: any = [];
|
||||
filterKeyword: Subject<string> = new Subject<string>();
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
public appService: AppService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.filterKeyword.pipe(debounceTime(1000), distinctUntilChanged()).subscribe(model => {
|
||||
this.getData();
|
||||
});
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
|
||||
await this.getData();
|
||||
}
|
||||
|
||||
onAction(id?: any) {
|
||||
if (id) return this.router.navigate(["/pages/appraisal/1st-time/history/pdf", id]);
|
||||
return this.router.navigate(["/pages/appraisal/1st-time/do", "create"]);
|
||||
}
|
||||
|
||||
async getData($event?: any) {
|
||||
try {
|
||||
this.dataFilter.keywordColumn = "quotationNo,productNo,customerFirstName,customerLastName,price";
|
||||
const dataSource = await lastValueFrom(this.appService.get(this.setParams(this.apiUrl, $event)));
|
||||
this.dataSource = this.setDataSource<any>(dataSource);
|
||||
} catch (e) {
|
||||
this.dataSource = [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onFilter($event?: any) {
|
||||
this.filterKeyword.next($event);
|
||||
}
|
||||
clearDate($event?: any) {
|
||||
$event.stopPropagation();
|
||||
this.dataFilter.createdDate = null;
|
||||
}
|
||||
|
||||
async onSort($event: any) {
|
||||
this.dataFilter.orderBy = $event.active;
|
||||
this.dataFilter.sort = $event.direction;
|
||||
await this.getData();
|
||||
console.log($event);
|
||||
}
|
||||
|
||||
|
||||
async onDelete(ids: any) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.DELETE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
try {
|
||||
await lastValueFrom(this.appService.delete(this.apiUrl, ids));
|
||||
await this.appService.message(EAction.SUCCESS, EText.DELETE);
|
||||
await this.getData(this.getCurrentPage());
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
onExport() {
|
||||
const filter = generateParamsValue(this.dataFilter);
|
||||
const url = `${API.quotation}/export-history?${filter ? '&' + filter : '' }`;
|
||||
window.open(url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<div class="card card-table">
|
||||
|
||||
<div class="card-filter text-right">
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-5 md:col-span-12 md:order-2">
|
||||
<mat-form-field>
|
||||
<i matTextPrefix class="bi bi-search"></i>
|
||||
<input matInput name="keyword" #keyword="ngModel" [(ngModel)]="dataFilter.keyword" (ngModelChange)="onFilter($event)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-7 md:col-span-12 md:order-1">
|
||||
<div class="card-header-action">
|
||||
|
||||
<button type="button" class="btn btn-create" (click)="onAction()">
|
||||
<i class="bi bi-plus"></i>
|
||||
ประวัติการสร้างใบเสนอราคา
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 items-center md:gap-2 ">
|
||||
<div class="col-span-3 md:col-span-6">
|
||||
<ng-select name="categoryId" #categoryId="ngModel" [(ngModel)]="dataFilter.categoryId" (ngModelChange)="getData()" appendTo="body" required placeholder="เลือกหมวดหมู่">
|
||||
<ng-option *ngFor="let item of masterProductCategory" [value]="item.id">{{item.name}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-3 md:col-span-6">
|
||||
<ng-select placeholder="Choose Brand" name="brandId" #brandId="ngModel" [(ngModel)]="dataFilter.brandId" (ngModelChange)="getData()" appendTo="body" required>
|
||||
<ng-option *ngFor="let item of masterProductBrand" [value]="item.id">{{item.name}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-6 md:col-span-12 ">
|
||||
<div class="flex w-full justify-end md:justify-start">
|
||||
<div class="">จำนวนทั้งหมด {{totalItem}} รายการ</div>
|
||||
<div class="pl-2 pr-2">|</div>
|
||||
<div class="">ค้นหาจำนวน {{totalOfElement}} รายการ</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-wrap">
|
||||
<table class="table table-main" mat-table [dataSource]="dataSource" matSort (matSortChange)="onSort($event)">
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
|
||||
<ng-container matColumnDef="code">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" mat-sort-header>BOM</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="tac">{{item.code}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Model</th>
|
||||
<td mat-cell *matCellDef="let item" class="" style="min-width: 200px;">
|
||||
<!-- <div class="flex items-center">-->
|
||||
<!-- <div class="image-td"><img *ngIf="item.coverImage" src="{{storage.products}}/{{item.coverImage}}" alt=""></div>-->
|
||||
<!-- <div class="">{{item.name }}</div>-->
|
||||
<!-- </div>-->
|
||||
{{item.name }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="brandId">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" mat-sort-header>Brand</th>
|
||||
<td mat-cell *matCellDef="let item" class="">{{item?.masterProductBrand.name }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="size">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150">Main</th>
|
||||
<td mat-cell *matCellDef="let item" class="">{{item.size }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="weight">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150">น้ำหนัก</th>
|
||||
<td mat-cell *matCellDef="let item" class="">{{item.weight }}</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="color">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150">Color</th>
|
||||
<td mat-cell *matCellDef="let item" class="">{{item.color }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="year">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150">Year</th>
|
||||
<td mat-cell *matCellDef="let item" class="">{{item.year }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="price">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>ราคา</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-orange"> {{item.price | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="latestPrice">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>ราคาล่าสุด</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-green"> {{item.latestPrice | number : '1.2-2' }}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="action">
|
||||
<th mat-header-cell *matHeaderCellDef width="80">สร้างใบเสนอราคา</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="action flex justify-center">
|
||||
|
||||
<div class="item">
|
||||
<i class="bi bi-file-earmark-text icon-doc" (click)="onAction(item.id)"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
</table>
|
||||
</div>
|
||||
<div *ngIf="dataSourceCount === 0" class="no-data"></div>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" showFirstLastButtons (page)="getData($event)"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,71 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { BaseListComponent } from "../../../../@common/base/base-list.component";
|
||||
import { debounceTime, distinctUntilChanged, lastValueFrom, Subject } from "rxjs";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { API } from "../../../../@config/app";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-1st-time-index",
|
||||
templateUrl: "./appraisal-1st-time-index.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class Appraisal1stTimeIndexComponent extends BaseListComponent implements OnInit {
|
||||
|
||||
pageTitle = "สินค้า";
|
||||
apiUrl: string = API.products;
|
||||
api: any = API;
|
||||
displayedColumns: string[] = ["action", "price", "latestPrice","code", "name", "brandId", "size",'weight', "color", "year" ];
|
||||
masterProductCategory: any = [];
|
||||
masterProductBrand: any = [];
|
||||
filterKeyword: Subject<string> = new Subject<string>();
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
public appService: AppService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.filterKeyword.pipe(debounceTime(1000), distinctUntilChanged()).subscribe(model => {
|
||||
this.getData();
|
||||
});
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.masterProductCategory = await lastValueFrom(this.appService.get(`${this.api.masterProductCategory}?showAll=true&status=true`));
|
||||
this.masterProductBrand = await lastValueFrom(this.appService.get(`${this.api.masterProductBrand}?showAll=true&status=true`));
|
||||
await this.getData();
|
||||
}
|
||||
|
||||
onAction(id?: any) {
|
||||
if (id) return this.router.navigate(["/pages/appraisal/1st-time/do", "create", id]);
|
||||
return this.router.navigate(["/pages/appraisal/1st-time/history"]);
|
||||
}
|
||||
|
||||
async getData($event?: any) {
|
||||
try {
|
||||
this.dataFilter.keywordColumn = "name,price,latestPrice";
|
||||
const dataSource = await lastValueFrom(this.appService.get(this.setParams(this.apiUrl, $event)));
|
||||
this.dataSource = this.setDataSource<any>(dataSource);
|
||||
} catch (e) {
|
||||
this.dataSource = [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onFilter($event?: any) {
|
||||
this.filterKeyword.next($event);
|
||||
}
|
||||
|
||||
async onSort($event: any) {
|
||||
this.dataFilter.orderBy = $event.active;
|
||||
this.dataFilter.sort = $event.direction;
|
||||
await this.getData();
|
||||
console.log($event);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<mat-progress-bar *ngIf="!pdfView" mode="indeterminate"></mat-progress-bar>
|
||||
<iframe *ngIf="pdfView" [src]="pdfView"></iframe>
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import { ChangeDetectorRef, Component, OnInit } from "@angular/core";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { API, STORAGE } from "../../../../@config/app";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { DomSanitizer } from "@angular/platform-browser";
|
||||
import { BaseFormComponent } from "../../../../@common/base/base-form.component";
|
||||
import { IQuotation } from "../../../../@common/interface/Quotation";
|
||||
import { format, parseISO } from "date-fns";
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-1st-time-index",
|
||||
templateUrl: "./appraisal-1st-time-pdf.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class Appraisal1stTimePdfComponent extends BaseFormComponent implements OnInit {
|
||||
|
||||
pageTitle = "ใบเสนอราคา";
|
||||
apiUrl: string = API.quotation;
|
||||
api: any = API;
|
||||
dataView: any;
|
||||
pdfView: any;
|
||||
|
||||
|
||||
constructor(
|
||||
public activatedRoute: ActivatedRoute,
|
||||
public router: Router,
|
||||
public changeDetectorRef: ChangeDetectorRef,
|
||||
public appService: AppService,
|
||||
private sanitizer: DomSanitizer
|
||||
) {
|
||||
super();
|
||||
|
||||
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.activatedRoute.params.subscribe(async params => {
|
||||
this.ids = params["id"];
|
||||
await this.getData();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async getData() {
|
||||
try {
|
||||
const quotation : IQuotation = await lastValueFrom(this.appService.get(`${this.api.quotation}/getById/${this.ids}`));
|
||||
const startDate = quotation.startDate ? format(parseISO(quotation.startDate), "dd/MM/yyyy") : null;
|
||||
const customerPrefix = quotation.customerPrefix ? quotation.customerPrefix : '';
|
||||
const customerName = quotation.customerId ? `${quotation.customer?.prefix} ${quotation.customer?.firstName} ${quotation.customer?.lastName}` :
|
||||
`${customerPrefix} ${quotation.customerFirstName} ${quotation.customerLastName}`;
|
||||
|
||||
const data = {
|
||||
doc_no: quotation.quotationNo,
|
||||
product_code: quotation.productNo,
|
||||
type_code: quotation.typeCode,
|
||||
customer_name: customerName,
|
||||
phone_no: quotation.customerPhone,
|
||||
installment_start_date: startDate,
|
||||
picture: `${STORAGE.products}/${quotation.coverImage}`,
|
||||
price: Number(quotation.price),
|
||||
seller_deposit: Number(quotation.sellerDeposit),
|
||||
cmfs_deposit: Number(quotation.cmfsDeposit),
|
||||
total_balance: Number(quotation.principalBalanceTotal),
|
||||
installment: Number(quotation.wantToInstallmentTerm),
|
||||
packing: Number(quotation.plusPacking),
|
||||
luxury_handbag_authentication: Number(quotation.plusLuxuryHandbag),
|
||||
bankfee_insurance_storage: Number(quotation.plusBankFee),
|
||||
transfer_amount: Number(quotation.transferSummary),
|
||||
discount: Number(quotation.discount),
|
||||
data: [],
|
||||
total1: 0,
|
||||
total2: 0,
|
||||
total3: 0,
|
||||
total4: 0
|
||||
}
|
||||
const quotationDetail: any = [];
|
||||
quotation.quotationDetail?.map(item => {
|
||||
const dueDate = item.dueDate ? format(parseISO(item.dueDate), "dd/MM/yyyy") : null;
|
||||
const map = {
|
||||
due_date: dueDate,
|
||||
principle: Number(item.principle),
|
||||
interest_total: Number(item.interestTotal),
|
||||
bank_fee: Number(item.fee),
|
||||
total_payment: Number(item.totalPayment),
|
||||
principle_total: Number(item.principleTotal)
|
||||
}
|
||||
quotationDetail.push(map);
|
||||
})
|
||||
|
||||
data.data = quotationDetail;
|
||||
|
||||
const pdf = await lastValueFrom(this.appService.post(`${this.api.quotationReport}/pdf`, data, { responseType: "arraybuffer" }));
|
||||
const url = URL.createObjectURL(new Blob([pdf], { type: "application/pdf" }));
|
||||
this.pdfView = this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
||||
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {Routes, RouterModule} from '@angular/router';
|
||||
import {Appraisal2ndTimeIndexComponent} from './index/appraisal-2nd-time-index.component';
|
||||
import {Appraisal2ndTimeDoComponent} from "./do/appraisal-2nd-time-do.component";
|
||||
import { Appraisal2ndTimeHistoryComponent } from "./history/appraisal-2nd-time-history.component";
|
||||
import { Appraisal2ndTimePdfComponent } from "./pdf/appraisal-2nd-time-pdf.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '', component: Appraisal2ndTimeIndexComponent},
|
||||
{path: 'list', component: Appraisal2ndTimeIndexComponent},
|
||||
{path: 'list/:action', component: Appraisal2ndTimeIndexComponent},
|
||||
{path: 'do/:action', component: Appraisal2ndTimeDoComponent},
|
||||
{path: 'do/:action/:id', component: Appraisal2ndTimeDoComponent},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class RoutingModule {
|
||||
}
|
||||
|
||||
export const RoutingComponents = [
|
||||
Appraisal2ndTimeIndexComponent,
|
||||
Appraisal2ndTimeDoComponent,
|
||||
Appraisal2ndTimeHistoryComponent,
|
||||
Appraisal2ndTimePdfComponent,
|
||||
];
|
||||
@@ -0,0 +1,16 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import {RoutingComponents, RoutingModule} from './appraisal-2nd-time-routing.module';
|
||||
import {AppSharedModule} from "../../../app.shared";
|
||||
import { NgOptimizedImage } from "@angular/common";
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
...RoutingComponents,
|
||||
],
|
||||
imports: [
|
||||
AppSharedModule,
|
||||
RoutingModule,
|
||||
NgOptimizedImage
|
||||
]
|
||||
})
|
||||
export class Appraisal2ndTimeModule {}
|
||||
@@ -0,0 +1,262 @@
|
||||
<form class="main-form" #ngf="ngForm" (ngSubmit)="onSubmit(ngf)">
|
||||
|
||||
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> ข้อมูลลูกค้า</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 ">
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ค้นหาเลขบัตรประชาชน</mat-label>
|
||||
<ng-select placeholder="ค้นหาเลขบัตรประชาชน" name="filterIdCard" #filterIdCard="ngModel" [(ngModel)]="dataFilter.idCard" (ngModelChange)="onChangeFilter($event)" appendTo="body" >
|
||||
<ng-option *ngFor="let item of customer" [value]="item.idCard">{{item.idCard}} : {{item.prefix}} {{item.firstName}} {{item.lastName}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-8 md:hidden"></div>
|
||||
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>คำนำหน้า</mat-label>
|
||||
<ng-select placeholder="เลือกคำนำหน้า" name="prefix" #prefix="ngModel" [(ngModel)]="dataForm.customer.prefix" appendTo="body" required>
|
||||
<ng-option *ngFor="let item of prefixData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ชื่อลูกค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="firstName" #firstName="ngModel" [(ngModel)]="dataForm.customer.firstName" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>นามสกุล</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="lastName" #lastName="ngModel" [(ngModel)]="dataForm.customer.lastName" >
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>เพศ</mat-label>
|
||||
<ng-select placeholder="เลือกเพศ" name="gender" #gender="ngModel" [(ngModel)]="dataForm.customer.gender" appendTo="body" >
|
||||
<ng-option *ngFor="let item of genderData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เบอร์โทร</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="phone" #phone="ngModel" [(ngModel)]="dataForm.customer.phone" >
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เลขบัตรประชาชน</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="idCard" #idCard="ngModel" [(ngModel)]="dataForm.customer.idCard" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<div style="height: 20px;"></div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<div class="">
|
||||
<input hidden type="file" accept="image/*" #idCardImages (change)="onAttachmentsIdCard($event, 'idcard')" />
|
||||
<button type="button" class="btn btn-icon-upload color-main" (click)="idCardImages.click()">
|
||||
<ng-container *ngIf="!dataForm.customer.idCardImage"> <i class="bi bi-plus-circle "></i> สำเนาบัตรประชาชน</ng-container>
|
||||
<ng-container *ngIf="dataForm.customer.idCardImage"> <i class="bi bi-pencil" matTooltip="แก้ไขสำเนาบัตรประชาชน"></i> </ng-container>
|
||||
</button>
|
||||
</div>
|
||||
<div style="padding-top: 4px;">
|
||||
<ng-container *ngIf="dataForm.customer.idCardImage">
|
||||
<div class="cursor-pointer" (click)="onAttachmentsView('images')"><i class="bi bi-search"></i> ดูสำเนาบัตรประชาชน</div></ng-container>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col-span-8 md:hidden"></div>
|
||||
|
||||
<div class="col-span-12 md:col-span-12 ">
|
||||
<mat-label>ที่อยู่ตามบัตรประชาชน</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="address" #address="ngModel" [(ngModel)]="dataForm.customer.address" (ngModelChange)="onChangeAddress('address', $event)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-12 md:col-span-12 ">
|
||||
<mat-label>ที่อยู่ในการจัดส่ง</mat-label>
|
||||
<label class="inline-flex items-center cursor-pointer select-none ml-2">
|
||||
<input type="checkbox" name="isAddress" [(ngModel)]="dataForm.customer.isAddress" (ngModelChange)="onChangeAddress('isAddress', $event)">
|
||||
<span style="padding-left: 2px;">ใช้ที่อยู่ตามบัตรประชาชน</span>
|
||||
</label>
|
||||
|
||||
<mat-form-field>
|
||||
<input matInput name="deliveryAddress" #deliveryAddress="ngModel" [(ngModel)]="dataForm.customer.deliveryAddress" [disabled]="dataForm.customer.isAddress">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>E-mail</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="email" #email="ngModel" [(ngModel)]="dataForm.customer.email">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-8 md:col-span-12 ">
|
||||
<mat-label>อาชีพ</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="occupation" #occupation="ngModel" [(ngModel)]="dataForm.customer.occupation">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ID Line</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="line" #line="ngModel" [(ngModel)]="dataForm.customer.line">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>Facebook</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="facebook" #facebook="ngModel" [(ngModel)]="dataForm.customer.facebook">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>IG</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="ig" #ig="ngModel" [(ngModel)]="dataForm.customer.ig">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-right mt-4 ">
|
||||
<mat-checkbox name="depositChecked" #depositChecked="ngModel" [(ngModel)]="dataForm.depositChecked">ชำระเงินเพิ่ม</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="card card-table mb-6">
|
||||
<div class="card-body">
|
||||
<div class="table-wrap" >
|
||||
<table class="tables ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>BOM</th>
|
||||
<th>Brand</th>
|
||||
<th>Model</th>
|
||||
<th>ราคาสินค้า</th>
|
||||
<th>จำนวนเงินมัดจำ</th>
|
||||
<th>ค่ามัดจำเพิ่ม</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<mat-form-field>
|
||||
<input matInput name="productNo" #productNo="ngModel" [(ngModel)]="dataForm.productNo" required>
|
||||
</mat-form-field>
|
||||
</td>
|
||||
<td class="text-center">{{dataForm.productBrandName}}</td>
|
||||
<td class="text-center">{{dataForm.productName }}</td>
|
||||
<td class="text-center">{{dataForm.price | number : '1.2-2'}}</td>
|
||||
<td class="text-center">
|
||||
<div class="b-color-orange">{{dataForm.deposit | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
<td>
|
||||
<mat-form-field>
|
||||
<input matInput name="paymentAmount" #paymentAmount="ngModel" [(ngModel)]="dataForm.paymentAmount" [required]="dataForm.depositChecked" [disabled]="!dataForm.depositChecked">
|
||||
</mat-form-field>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title flex items-center">
|
||||
<div class="">รูปสินค้าจากลูกค้า</div>
|
||||
|
||||
<div class="ml-4">
|
||||
<input hidden type="file" accept="image/*" #productImages (change)="onAttachments($event, 'products')" />
|
||||
<button type="button" class="btn btn-sm btn-success-o" (click)="productImages.click()">เพิ่มรูปภาพสินค้า</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="list-images">
|
||||
<div class=" grid grid-cols-12 gap-2 md:gap-2 items-center">
|
||||
<ng-container *ngFor="let item of attachments; let i = index">
|
||||
<div class="col-span-2 md:col-span-4">
|
||||
<div class="flex justify-center items-center list-images-item">
|
||||
<div class="list-images-action">
|
||||
<i *ngIf="dataForm.coverImage !== item" (click)="dataForm.coverImage = item"
|
||||
matTooltip="ใช้ทำเอกสาร" class="bi bi-star color-main cursor-pointer select-none"></i>
|
||||
<i *ngIf="dataForm.coverImage === item" class="bi bi bi-star-fill color-main cursor-pointer select-none"></i>
|
||||
<i (click)="onRemoveAttachments(i, item)" class="bi bi-x-circle color-red cursor-pointer select-none"></i>
|
||||
</div>
|
||||
<img src="{{storage.products}}/{{item}}" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title flex items-center">
|
||||
<div class="">อุปกรณ์</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<ng-container *ngFor="let item of equipmentData; let i = index">
|
||||
<div class="form-list">
|
||||
<div class="form-list-item grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-1 md:col-span-2 text-right">
|
||||
<div *ngIf="i === 0" style="height: 25px;"></div>
|
||||
<input type="checkbox" name="isCheck-{{i}}" #isCheck="ngModel" [(ngModel)]="item.isCheck">
|
||||
</div>
|
||||
<div class="col-span-9 md:col-span-8 cursor-pointer select-none" (click)="item.isCheck = !item.isCheck">
|
||||
<div *ngIf="i === 0" style="height: 25px;"></div>
|
||||
{{item.name}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="isEquipmentOther()">
|
||||
<ng-container *ngFor="let item of equipmentOtherData; let i = index">
|
||||
<div class="form-list">
|
||||
<div class="form-list-item grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-1 md:col-span-2 text-right">
|
||||
|
||||
</div>
|
||||
<div class="col-span-9 md:col-span-8 cursor-pointer select-none" >
|
||||
<mat-form-field>
|
||||
<input matInput name="equipmentOtherItem-{{i}}" #equipmentOtherItem="ngModel" [(ngModel)]="item.value" >
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-2 " >
|
||||
<i (click)="onAddEquipmentOther()" class="bi bi-plus-circle color-green cursor-pointer select-none mr-2"></i>
|
||||
<i (click)="onRemoveEquipmentOther(i)" class="bi bi-x-circle color-red cursor-pointer select-none"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<div style="height: 40px;"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main-form-action text-right">
|
||||
<button type="submit" class="btn btn-submit">บันทึก</button>
|
||||
<button type="button" class="btn btn-back" (click)="onAction('back')">ยกเลิก</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@@ -0,0 +1,274 @@
|
||||
import { ChangeDetectorRef, Component, OnInit } from "@angular/core";
|
||||
import { API, EAction, EText, GENDER, PREFIX, STORAGE } from "../../../../@config/app";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { BaseFormComponent } from "../../../../@common/base/base-form.component";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { IProduct } from "../../../../app.interface";
|
||||
import deepCopy from "../../../../@common/utils/DeepCopy";
|
||||
import { AttachmentsViewComponent } from "../../../@popup/attachments-view/attachments-view.component";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-2nd-time-do",
|
||||
templateUrl: "./appraisal-2nd-time-do.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class Appraisal2ndTimeDoComponent extends BaseFormComponent implements OnInit {
|
||||
|
||||
override dataForm: any = {};
|
||||
dataView: IProduct = {};
|
||||
auth: any = {};
|
||||
title = "";
|
||||
api: any = API;
|
||||
storage: any = STORAGE;
|
||||
addItemNumber: number = 1;
|
||||
attachments: any = [];
|
||||
settings: any = [];
|
||||
IN01: any = {};
|
||||
IN05: any = {};
|
||||
prefixData = PREFIX;
|
||||
genderData = GENDER;
|
||||
customer : any = [];
|
||||
equipmentData : any = [];
|
||||
equipmentOtherData : any = [{value : ''}];
|
||||
|
||||
constructor(
|
||||
public activatedRoute: ActivatedRoute,
|
||||
public router: Router,
|
||||
public changeDetectorRef: ChangeDetectorRef,
|
||||
public appService: AppService,
|
||||
private attachmentsView: MatDialog,
|
||||
) {
|
||||
|
||||
super();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.activatedRoute.params.subscribe(async params => {
|
||||
this.ids = params["id"];
|
||||
this.action = params["action"];
|
||||
this.auth = this.appService.auth();
|
||||
this.dataForm.customer = {};
|
||||
this.dataForm.sellsr = {};
|
||||
this.defaultEquipmentData();
|
||||
this.customer = await lastValueFrom(this.appService.get(`${API.customer}?showAll=true`));
|
||||
if (this.ids) await this.getData();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
async onAction(action: string) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.BACK));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
if (action === "back") return this.router.navigate(["/pages/appraisal/2nd-time/list", this.action]);
|
||||
return;
|
||||
}
|
||||
|
||||
async getData() {
|
||||
if (!this.ids) this.appService.message(EAction.INFO, EText.NO_DATA);
|
||||
try {
|
||||
this.dataForm = await lastValueFrom(this.appService.get(`${this.api.quotation}/getById/${this.ids}`));
|
||||
this.attachments = this.dataForm.images ? this.dataForm.images?.split(",") : [];
|
||||
this.dataForm.paymentAmount = 0;
|
||||
this.dataForm.customer = {};
|
||||
this.dataForm.customer.prefix = this.dataForm.customerPrefix;
|
||||
this.dataForm.customer.firstName = this.dataForm.customerFirstName;
|
||||
this.dataForm.customer.lastName = this.dataForm.customerLastName;
|
||||
this.dataForm.customer.phone = this.dataForm.customerPhone;
|
||||
if (this.dataForm.customer.isAddress) this.dataForm.customer.deliveryAddress = this.dataForm.customer.address;
|
||||
|
||||
if (!this.dataForm.productNo) {
|
||||
const currentDate = new Date();
|
||||
|
||||
let currentMonth: any = new Date().getMonth() + 1;
|
||||
currentMonth = currentMonth.toString().padStart(2, '0');
|
||||
|
||||
let currentYear: any = currentDate.getFullYear() + 543;
|
||||
currentYear = currentYear.toString().substring(2);
|
||||
|
||||
const RUNNING = this.dataForm.id.toString().padStart(6, '0');
|
||||
this.dataForm.productNo = `${this.dataForm.typeCode}${currentYear}-${currentMonth}-${RUNNING}`;
|
||||
}
|
||||
|
||||
|
||||
const equipment : any[] = this.dataForm.equipment ? this.dataForm.equipment?.split(",") : [];
|
||||
const equipmentOther : any[] = this.dataForm.equipmentOther ? this.dataForm.equipmentOther?.split(",") : [];
|
||||
|
||||
if (equipment.length) {
|
||||
this.equipmentData.map((d: any) => {
|
||||
if (equipment.includes(d.name)) d.isCheck = true;
|
||||
})
|
||||
}
|
||||
|
||||
if (equipmentOther.length) {
|
||||
this.equipmentOtherData = [];
|
||||
equipmentOther.map((d : any) => {
|
||||
this.equipmentOtherData.push({ value : d});
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
async onChangeFilter(value : any) {
|
||||
if (!value) return await this.getData();
|
||||
this.dataForm.customer = this.customer.filter((f : any) => f.idCard === value)?.[0];
|
||||
|
||||
|
||||
}
|
||||
|
||||
onChangeAddress(key : string, value : any) {
|
||||
if (key === 'isAddress') this.dataForm.customer.deliveryAddress = value ? this.dataForm.customer.address : '';
|
||||
if (key === 'address') this.dataForm.customer.deliveryAddress = this.dataForm.customer.isAddress ? value : this.dataForm.customer.deliveryAddress;
|
||||
}
|
||||
|
||||
|
||||
async onSubmit(form: any) {
|
||||
if (!form.valid) return false;
|
||||
|
||||
if (!this.dataForm.customer.idCardImage) {
|
||||
return this.appService.message(EAction.ERROR, 'กรุณาอัพโหลดสำเนาบัตรประชาชน');
|
||||
}
|
||||
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.CREATE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
|
||||
const equipment : any[] = [];
|
||||
this.equipmentData.map((d : any) => {
|
||||
if (d.isCheck) equipment.push(d.name);
|
||||
})
|
||||
this.dataForm.equipment = equipment?.[0] ? equipment.join(",") : null;
|
||||
this.dataForm.equipmentOther = null;
|
||||
|
||||
if (equipment.includes('อื่นๆ')) {
|
||||
const equipmentOther : any[] = [];
|
||||
this.equipmentOtherData.map((d : any) => {
|
||||
equipmentOther.push(d.value);
|
||||
})
|
||||
this.dataForm.equipmentOther = equipmentOther?.[0] ? equipmentOther.join(",") : null;
|
||||
}
|
||||
|
||||
this.dataForm.images = this.attachments?.[0] ? this.attachments.join(",") : null;
|
||||
|
||||
return await this.onUpdate();
|
||||
|
||||
}
|
||||
|
||||
|
||||
async onUpdate() {
|
||||
try {
|
||||
await lastValueFrom(this.appService.post(`${this.api.quotation}/update/${this.ids}`, this.dataForm));
|
||||
await this.appService.message(EAction.SUCCESS, EText.UPDATE);
|
||||
await this.router.navigate(["/pages/appraisal/2nd-time/list", this.action]);
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async onAttachments($event: any, type: any) {
|
||||
const file = $event.target.files[0];
|
||||
if (!file) return;
|
||||
const formData = new FormData();
|
||||
formData.append("ref", type);
|
||||
formData.append("file", file);
|
||||
try {
|
||||
const res = await lastValueFrom(this.appService.post(`${this.api.attachments}/products`, formData));
|
||||
if (!this.attachments[0]) {
|
||||
this.dataForm.coverImage = res.fileName;
|
||||
}
|
||||
this.attachments.push(res.fileName);
|
||||
console.log(this.attachments, res);
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} catch (e) {
|
||||
this.appService.message(EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
async onRemoveAttachments(i: number, fileName: string) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.DELETE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
// await lastValueFrom(this.appService.delete(`${this.api.attachments}/deleteByName`, fileName));
|
||||
this.attachments?.splice(i, 1);
|
||||
if (!this.attachments[0]) {
|
||||
this.dataForm.coverImage = null;
|
||||
}
|
||||
this.changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
async onAttachmentsIdCard($event: any, type: any) {
|
||||
const file = $event.target.files[0];
|
||||
if (!file) return;
|
||||
const formData = new FormData();
|
||||
formData.append("ref", type);
|
||||
formData.append("file", file);
|
||||
try {
|
||||
const res = await lastValueFrom(this.appService.post(`${API.attachments}/images`, formData));
|
||||
|
||||
this.dataForm.customer.idCardImage = res.fileName;
|
||||
|
||||
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} catch (e) {
|
||||
this.appService.message(EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
async onAttachmentsView(type : any) {
|
||||
const dialogConfig = deepCopy(this.dialogConfig);
|
||||
dialogConfig.data.action = EAction.POPUP;
|
||||
dialogConfig.data.title = 'สำเนาบัตรประชาชน';
|
||||
dialogConfig.data.type = type;
|
||||
dialogConfig.data.images = this.dataForm.customer.idCardImage;
|
||||
const dialogRef = this.attachmentsView.open(AttachmentsViewComponent, dialogConfig);
|
||||
const afterClosed = await lastValueFrom(dialogRef.afterClosed());
|
||||
|
||||
}
|
||||
|
||||
defaultEquipmentData() {
|
||||
this.equipmentData = [
|
||||
{ name : 'ตัวเปล่า', isCheck : false},
|
||||
{ name : 'ถุงกระดาษ', isCheck : false},
|
||||
{ name : 'ถุงผ้า', isCheck : false},
|
||||
{ name : 'ใบเสร็จ', isCheck : false},
|
||||
{ name : 'บุ๊ค 1', isCheck : false},
|
||||
{ name : 'บุ๊ค 2', isCheck : false},
|
||||
{ name : 'ดอกคามิเลีย', isCheck : false},
|
||||
{ name : 'ริบบิ้น', isCheck : false},
|
||||
{ name : 'ถุงกันฝน', isCheck : false},
|
||||
{ name : 'การ์ด', isCheck : false},
|
||||
{ name : 'สายกระเป๋า', isCheck : false},
|
||||
{ name : 'ใบเซอร์', isCheck : false},
|
||||
{ name : 'พวงกุญแจแม่ และลูก', isCheck : false},
|
||||
{ name : 'กล่อง', isCheck : false},
|
||||
{ name : 'สายนาฬิกา', isCheck : false},
|
||||
{ name : 'ใบรับประกัน', isCheck : false},
|
||||
{ name : 'ใบตรวจ', isCheck : false},
|
||||
{ name : 'อื่นๆ', isCheck : false},
|
||||
]
|
||||
}
|
||||
|
||||
isEquipmentOther() {
|
||||
return this.equipmentData.find((f : any) => f.name === 'อื่นๆ' && f.isCheck === true)
|
||||
}
|
||||
onAddEquipmentOther() {
|
||||
this.equipmentOtherData.push({value : ''});
|
||||
}
|
||||
onRemoveEquipmentOther(i : number) {
|
||||
if (i === 0) return;
|
||||
|
||||
this.equipmentOtherData?.splice(i, 1);
|
||||
this.changeDetectorRef.detectChanges();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<div class="card card-table">
|
||||
|
||||
<div class="card-filter text-right">
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-5 md:col-span-12 md:order-2">
|
||||
<mat-form-field>
|
||||
<i matTextPrefix class="bi bi-search"></i>
|
||||
<input matInput name="keyword" #keyword="ngModel" [(ngModel)]="dataFilter.keyword" (ngModelChange)="onFilter($event)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 items-center md:gap-2 ">
|
||||
<div class="col-span-3 md:col-span-6">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
name="startDate"
|
||||
#startDate="ngModel"
|
||||
(click)="dpkName.open()"
|
||||
[(ngModel)]="dataFilter.createdDate"
|
||||
[matDatepicker]="dpkName"
|
||||
readonly
|
||||
(ngModelChange)="getData()"
|
||||
|
||||
/>
|
||||
<!-- <mat-icon matSuffix (click)="clearDate($event)">clear</mat-icon>-->
|
||||
<mat-datepicker-toggle [for]="dpkName" matSuffix></mat-datepicker-toggle>
|
||||
<mat-datepicker #dpkName></mat-datepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-9 md:col-span-12 ">
|
||||
<div class="flex w-full ">
|
||||
<div class="">จำนวนทั้งหมด {{totalItem}} รายการ</div>
|
||||
<div class="pl-2 pr-2">|</div>
|
||||
<div class="">ค้นหาจำนวน {{totalOfElement}} รายการ</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-wrap">
|
||||
<table class="table table-main" mat-table [dataSource]="dataSource" matSort (matSortChange)="onSort($event)">
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
|
||||
<ng-container matColumnDef="quotationNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>เลขที่ใบเสนอราคา</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">{{item.quotationNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="customerFirstName">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>ชื่อลูกค้า</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">
|
||||
<ng-container *ngIf="item.customerId"> {{item.customer?.prefix}}{{item.customer?.firstName}} {{item.customer?.lastName}}</ng-container>
|
||||
<ng-container *ngIf="!item.customerId">{{item.customerFirstName}} {{item.customerLastName}}</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" mat-sort-header>BOM</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="tac">{{item.productNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productName">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Model</th>
|
||||
<td mat-cell *matCellDef="let item" class="" style="min-width: 200px;">{{item.productName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="price">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>จำนวนเงิน</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-green"> {{item.price | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="wantToInstallmentTerm">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ระยะเวลาผ่อน</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.wantToInstallmentTerm }} งวด</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="createdDate">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">วันที่บันทึก</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.createdDate | date : 'dd/MM/YYYY'}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">สถานะ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.status === 'paid' " class="status status-active">ชำระแล้ว</div>
|
||||
<div *ngIf="item.status === 'pending'" class="status status-disabled">รอชำระ</div>
|
||||
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="action">
|
||||
<th mat-header-cell *matHeaderCellDef width="80">Action</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="action flex justify-center">
|
||||
|
||||
<div class="item">
|
||||
<i class="bi bi-filetype-pdf color-main" (click)="onAction(item.id)"></i>
|
||||
</div>
|
||||
<div class="item" *ngIf="item.status === 'pending'">
|
||||
<i class="bi bi-trash3 color-red" (click)="onDelete(item.id)"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
</table>
|
||||
<div *ngIf="dataSourceCount === 0" class="no-data"></div>
|
||||
</div>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" showFirstLastButtons (page)="getData($event)"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,86 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { BaseListComponent } from "../../../../@common/base/base-list.component";
|
||||
import { debounceTime, distinctUntilChanged, lastValueFrom, Subject } from "rxjs";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { API, EAction, EText } from "../../../../@config/app";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-1st-time-index",
|
||||
templateUrl: "./appraisal-2nd-time-history.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class Appraisal2ndTimeHistoryComponent extends BaseListComponent implements OnInit {
|
||||
|
||||
pageTitle = "ประวัติการสร้างใบเสนอราคา";
|
||||
apiUrl: string = API.quotation;
|
||||
api: any = API;
|
||||
displayedColumns: string[] = ["action", "quotationNo", "customerFirstName", "productNo", "productName", "price", "wantToInstallmentTerm", "createdDate", "status"];
|
||||
masterProductCategory: any = [];
|
||||
masterProductBrand: any = [];
|
||||
filterKeyword: Subject<string> = new Subject<string>();
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
public appService: AppService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.filterKeyword.pipe(debounceTime(1000), distinctUntilChanged()).subscribe(model => {
|
||||
this.getData();
|
||||
});
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
|
||||
await this.getData();
|
||||
}
|
||||
|
||||
onAction(id?: any) {
|
||||
if (id) return this.router.navigate(["/pages/appraisal/1st-time/history/pdf", id]);
|
||||
return this.router.navigate(["/pages/appraisal/1st-time/do", "create"]);
|
||||
}
|
||||
|
||||
async getData($event?: any) {
|
||||
try {
|
||||
this.dataFilter.keywordColumn = "quotationNo,productNo,customerFirstName,customerLastName";
|
||||
const dataSource = await lastValueFrom(this.appService.get(this.setParams(this.apiUrl, $event)));
|
||||
this.dataSource = this.setDataSource<any>(dataSource);
|
||||
} catch (e) {
|
||||
this.dataSource = [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onFilter($event?: any) {
|
||||
this.filterKeyword.next($event);
|
||||
}
|
||||
clearDate($event?: any) {
|
||||
$event.stopPropagation();
|
||||
this.dataFilter.createdDate = null;
|
||||
}
|
||||
|
||||
async onSort($event: any) {
|
||||
this.dataFilter.orderBy = $event.active;
|
||||
this.dataFilter.sort = $event.direction;
|
||||
await this.getData();
|
||||
console.log($event);
|
||||
}
|
||||
|
||||
|
||||
async onDelete(ids: any) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.DELETE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
try {
|
||||
await lastValueFrom(this.appService.delete(this.apiUrl, ids));
|
||||
await this.appService.message(EAction.SUCCESS, EText.DELETE);
|
||||
await this.getData(this.getCurrentPage());
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<div class="card card-table">
|
||||
|
||||
<div class="card-filter text-right">
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-5 md:col-span-12 md:order-2">
|
||||
<mat-form-field>
|
||||
<i matTextPrefix class="bi bi-search"></i>
|
||||
<input matInput name="keyword" #keyword="ngModel" [(ngModel)]="dataFilter.keyword" (ngModelChange)="onFilter($event)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-7 md:col-span-12 md:order-1">
|
||||
<button type="button" class="btn btn-export" (click)="onExport()">Export</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 items-center md:gap-2 ">
|
||||
<div class="col-span-6 md:col-span-12">
|
||||
<div class="tabs-btn">
|
||||
<button type="button" class="btn" [ngClass]="{ 'active' : action === 'wait'}" (click)="onTabs('wait')">รอประเมิน</button>
|
||||
<button type="button" class="btn" [ngClass]="{ 'active' : action === 'evaluated'}" (click)="onTabs('evaluated')">ประเมินแล้ว</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 md:col-span-12 ">
|
||||
<div class="flex w-full justify-end md:justify-start">
|
||||
<div class="">จำนวนทั้งหมด {{totalItem}} รายการ</div>
|
||||
<div class="pl-2 pr-2">|</div>
|
||||
<div class="">ค้นหาจำนวน {{totalOfElement}} รายการ</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-wrap">
|
||||
<table class="table table-main" mat-table [dataSource]="dataSource" matSort (matSortChange)="onSort($event)">
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
|
||||
<ng-container matColumnDef="quotationNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>เลขที่ใบเสนอราคา</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">{{item.quotationNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="customerFirstName">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>ชื่อลูกค้า</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">
|
||||
<ng-container *ngIf="item.customerId"> {{item.customer?.prefix}}{{item.customer?.firstName}} {{item.customer?.lastName}}</ng-container>
|
||||
<ng-container *ngIf="!item.customerId">{{item.customerFirstName}} {{item.customerLastName}}</ng-container>
|
||||
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" mat-sort-header>BOM</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">{{item.productNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productName">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Model</th>
|
||||
<td mat-cell *matCellDef="let item" class="" style="min-width: 220px;">{{item.productName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productBrandName">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Brand</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productBrandName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productSize">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Main</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productSize }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productWeight">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" >น้ำหนัก</th>
|
||||
<td mat-cell *matCellDef="let item" class="">{{item.productWeight }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productColor">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Color</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productColor }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productYear">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Year</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productYear }}</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="price">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>จำนวนเงิน</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-green"> {{item.price | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="deposit">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>จำนวนเงินมัดจำ</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-orange"> {{item.deposit | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="sellerDeposit2ndTime">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>เงินมัดจำเพิ่ม</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-red" *ngIf="item.sellerDeposit2ndTime"> {{item.sellerDeposit2ndTime | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="wantToInstallmentTerm">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ระยะเวลาผ่อน</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.wantToInstallmentTerm }} งวด</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="createdDate">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">วันที่บันทึก</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.createdDate | date : 'dd/MM/YYYY'}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">สถานะ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac" style="min-width: 100px;">
|
||||
<div *ngIf="item.status === 'paid' " class="status status-active">ชำระแล้ว</div>
|
||||
<div *ngIf="item.status === 'pending'" class="status status-disabled">รอชำระ</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ประเภทการชำระ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.type === 'deposit' " class="status-text status-deposit">ค่ามัดจำ</div>
|
||||
<div *ngIf="item.type === 'installment'" class="status-text status-installment">ผ่อนสินค้า</div>
|
||||
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="paymentType">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ประเภทการชำระ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.paymentType === 'deposit' " class="status-text status-deposit">ค่ามัดจำ</div>
|
||||
<div *ngIf="item.paymentType === 'installment'" class="status-text status-installment">ผ่อนสินค้า</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="paymentMethod">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>วิธีชำระ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.paymentMethod === 'transfer' " class="status-text status-transfer">โอนเงิน</div>
|
||||
<div *ngIf="item.paymentMethod === 'cash'" class="status-text status-cash">เงินสด</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="paymentAmountAll">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>จำนวนเงิน</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div class="b-color-green">{{item.paymentAmountAll | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
|
||||
<ng-container matColumnDef="action">
|
||||
<th mat-header-cell *matHeaderCellDef width="80">Action</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="action flex justify-center">
|
||||
|
||||
|
||||
<div class="item" *ngIf="item.status2ndTime === 'wait' " >
|
||||
<i class="bi bi-pencil-square icon-edit" (click)="onAction(item.id)"></i>
|
||||
</div>
|
||||
<!-- <div class="item" *ngIf="item.status === 'paid' ">-->
|
||||
<!-- <i class="bi bi-filetype-pdf color-main" (click)="onAction(item.id)"></i>-->
|
||||
<!-- </div>-->
|
||||
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
</table>
|
||||
<div *ngIf="dataSource?.length === 0" class="no-data"></div>
|
||||
</div>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" showFirstLastButtons (page)="getData($event)"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,121 @@
|
||||
import { ChangeDetectorRef, Component, OnInit } from "@angular/core";
|
||||
import { BaseListComponent } from "../../../../@common/base/base-list.component";
|
||||
import { debounceTime, distinctUntilChanged, lastValueFrom, Subject } from "rxjs";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { API, EAction, EStatusQuotation, EText } from "../../../../@config/app";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import generateParamsValue from "../../../../@common/utils/GenerateParamsValue";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-2nd-time-index",
|
||||
templateUrl: "./appraisal-2nd-time-index.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class Appraisal2ndTimeIndexComponent extends BaseListComponent implements OnInit {
|
||||
|
||||
pageTitle = "รับชำระเงิน/ออกใบเสร็จรับเงิน";
|
||||
action = "pending";
|
||||
apiUrl: string = API.quotation;
|
||||
api: any = API;
|
||||
|
||||
displayedColumns: string[] = [];
|
||||
masterProductCategory: any = [];
|
||||
masterProductBrand: any = [];
|
||||
filterKeyword: Subject<string> = new Subject<string>();
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
public appService: AppService,
|
||||
public activatedRoute: ActivatedRoute,
|
||||
public changeDetectorRef: ChangeDetectorRef
|
||||
) {
|
||||
super();
|
||||
|
||||
this.filterKeyword.pipe(debounceTime(1000), distinctUntilChanged()).subscribe(model => {
|
||||
this.getData();
|
||||
});
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.activatedRoute.params.subscribe(async params => {
|
||||
this.action = params["action"];
|
||||
this.dataFilter.step = 3;
|
||||
this.dataFilter.status2ndTime = this.action;
|
||||
if (!this.action) this.router.navigate(["/pages/appraisal/2nd-time/list", EStatusQuotation.WAIT]);
|
||||
await this.getData();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async onTabs(action?: any) {
|
||||
this.dataFilter = {};
|
||||
return this.router.navigate(["/pages/appraisal/2nd-time/list", action]);
|
||||
}
|
||||
|
||||
onAction(id?: any) {
|
||||
if (id) return this.router.navigate([`/pages/appraisal/2nd-time/do/${this.action}`, id]);
|
||||
return;
|
||||
}
|
||||
|
||||
async getData($event?: any) {
|
||||
try {
|
||||
this.dataFilter.keywordColumn = "productNo,productName,quotationNo,price,deposit,sellerDeposit2ndTime";
|
||||
this.dataSource = [];
|
||||
let url = API.quotation;
|
||||
if (this.action === EStatusQuotation.WAIT) {
|
||||
url = API.quotation;
|
||||
this.displayedColumns = ["action", "price", "deposit", "customerFirstName", "productNo", "productName", "productBrandName", "productSize", "productWeight", "productColor", "productYear"];
|
||||
}
|
||||
if (this.action === EStatusQuotation.EVALUATED) {
|
||||
url = API.quotation;
|
||||
delete this.dataFilter.step;
|
||||
this.displayedColumns = ["price", "deposit", "sellerDeposit2ndTime", "quotationNo", "customerFirstName", "productNo", "productName", "status"];
|
||||
|
||||
}
|
||||
|
||||
const dataSource = await lastValueFrom(this.appService.get(this.setParams(url, $event)));
|
||||
this.dataSource = this.setDataSource<any>(dataSource);
|
||||
} catch (e) {
|
||||
this.dataSource = [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onFilter($event?: any) {
|
||||
this.filterKeyword.next($event);
|
||||
}
|
||||
|
||||
clearDate($event?: any) {
|
||||
$event.stopPropagation();
|
||||
this.dataFilter.createdDate = null;
|
||||
}
|
||||
|
||||
async onSort($event: any) {
|
||||
this.dataFilter.orderBy = $event.active;
|
||||
this.dataFilter.sort = $event.direction;
|
||||
await this.getData();
|
||||
console.log($event);
|
||||
}
|
||||
|
||||
|
||||
async onDelete(ids: any) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.DELETE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
try {
|
||||
await lastValueFrom(this.appService.delete(this.apiUrl, ids));
|
||||
await this.appService.message(EAction.SUCCESS, EText.DELETE);
|
||||
await this.getData(this.getCurrentPage());
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
onExport() {
|
||||
const filter = generateParamsValue(this.dataFilter);
|
||||
const url = `${API.quotation}/export-2nd-time?${filter ? '&' + filter : '' }`;
|
||||
window.open(url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<mat-progress-bar *ngIf="!pdfView" mode="indeterminate"></mat-progress-bar>
|
||||
<iframe *ngIf="pdfView" [src]="pdfView"></iframe>
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { BaseListComponent } from "../../../../@common/base/base-list.component";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { API } from "../../../../@config/app";
|
||||
import { Router } from "@angular/router";
|
||||
import { DomSanitizer } from "@angular/platform-browser";
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-1st-time-index",
|
||||
templateUrl: "./appraisal-2nd-time-pdf.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class Appraisal2ndTimePdfComponent extends BaseListComponent implements OnInit {
|
||||
|
||||
pageTitle = "ใบเสนอราคา";
|
||||
apiUrl: string = API.quotation;
|
||||
api: any = API;
|
||||
dataView: any;
|
||||
pdfView: any;
|
||||
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
public appService: AppService,
|
||||
private sanitizer: DomSanitizer
|
||||
) {
|
||||
super();
|
||||
|
||||
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
await this.getData();
|
||||
}
|
||||
|
||||
onAction(id?: any) {
|
||||
if (id) return this.router.navigate(["/pages/appraisal/1st-time/do", "update", id]);
|
||||
return this.router.navigate(["/pages/appraisal/1st-time/do", "create"]);
|
||||
}
|
||||
|
||||
async getData($event?: any) {
|
||||
try {
|
||||
const data = {
|
||||
doc_no: "string",
|
||||
product_code: "string",
|
||||
customer_name: "string",
|
||||
phone_no: "string",
|
||||
installment_start_date: "string",
|
||||
picture: "string",
|
||||
price: 0,
|
||||
seller_deposit: 0,
|
||||
cmfs_deposit: 0,
|
||||
total_balance: 0,
|
||||
installment: 0,
|
||||
packing: 0,
|
||||
luxury_handbag_authentication: 0,
|
||||
bankfee_insurance_storage: 0,
|
||||
transfer_amount: 0,
|
||||
data: [
|
||||
{
|
||||
due_date: "string",
|
||||
principle: 0,
|
||||
interest_total: 0,
|
||||
bank_fee: 0,
|
||||
total_payment: 0,
|
||||
principle_total: 0
|
||||
}
|
||||
],
|
||||
total1: 0,
|
||||
total2: 0,
|
||||
total3: 0,
|
||||
total4: 0
|
||||
}
|
||||
this.dataView = await lastValueFrom(this.appService.post(`${this.api.quotationReport}/pdf`, data, { responseType: 'arraybuffer' }));
|
||||
|
||||
|
||||
const url = URL.createObjectURL(new Blob([this.dataView], { type: 'application/pdf' }));
|
||||
this.pdfView = this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
||||
|
||||
|
||||
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {Routes, RouterModule} from '@angular/router';
|
||||
import {Appraisal3rdTimeIndexComponent} from './index/appraisal-3rd-time-index.component';
|
||||
import {Appraisal3rdTimeDoComponent} from "./do/appraisal-3rd-time-do.component";
|
||||
import { Appraisal3rdTimeHistoryComponent } from "./history/appraisal-3rd-time-history.component";
|
||||
import { Appraisal3rdTimePdfComponent } from "./pdf/appraisal-3rd-time-pdf.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '', component: Appraisal3rdTimeIndexComponent},
|
||||
{path: 'list', component: Appraisal3rdTimeIndexComponent},
|
||||
{path: 'list/:action', component: Appraisal3rdTimeIndexComponent},
|
||||
{path: 'do/:action', component: Appraisal3rdTimeDoComponent},
|
||||
{path: 'do/:action/:id', component: Appraisal3rdTimeDoComponent},
|
||||
{path: 'history', component: Appraisal3rdTimeHistoryComponent},
|
||||
{path: 'history/pdf/:id', component: Appraisal3rdTimePdfComponent},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class RoutingModule {
|
||||
}
|
||||
|
||||
export const RoutingComponents = [
|
||||
Appraisal3rdTimeIndexComponent,
|
||||
Appraisal3rdTimeDoComponent,
|
||||
Appraisal3rdTimeHistoryComponent,
|
||||
Appraisal3rdTimePdfComponent,
|
||||
];
|
||||
@@ -0,0 +1,16 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import {RoutingComponents, RoutingModule} from './appraisal-3rd-time-routing.module';
|
||||
import {AppSharedModule} from "../../../app.shared";
|
||||
import { NgOptimizedImage } from "@angular/common";
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
...RoutingComponents,
|
||||
],
|
||||
imports: [
|
||||
AppSharedModule,
|
||||
RoutingModule,
|
||||
NgOptimizedImage
|
||||
]
|
||||
})
|
||||
export class Appraisal3rdTimeModule {}
|
||||
@@ -0,0 +1,401 @@
|
||||
<form class="main-form" #ngf="ngForm" (ngSubmit)="onSubmit(ngf)">
|
||||
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> ข้อมูลลูกค้า</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 ">
|
||||
<!-- <div class="col-span-4 md:col-span-12 ">-->
|
||||
<!-- <mat-label>ค้นหาเลขบัตรประชาชน</mat-label>-->
|
||||
<!-- <ng-select placeholder="ค้นหาเลขบัตรประชาชน" name="filterIdCard" #filterIdCard="ngModel" [(ngModel)]="dataFilter.idCard" (ngModelChange)="onChangeFilter($event)" appendTo="body" >-->
|
||||
<!-- <ng-option *ngFor="let item of customer" [value]="item.idCard">{{item.idCard}} : {{item.prefix}} {{item.firstName}} {{item.lastName}}</ng-option>-->
|
||||
<!-- </ng-select>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-span-8 md:hidden"></div>-->
|
||||
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>คำนำหน้า</mat-label>
|
||||
<ng-select placeholder="เลือกคำนำหน้า" name="prefix" #prefix="ngModel" [(ngModel)]="dataForm.customer.prefix" appendTo="body" required>
|
||||
<ng-option *ngFor="let item of prefixData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ชื่อลูกค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="firstName" #firstName="ngModel" [(ngModel)]="dataForm.customer.firstName" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>นามสกุล</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="lastName" #lastName="ngModel" [(ngModel)]="dataForm.customer.lastName" >
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>เพศ</mat-label>
|
||||
<ng-select placeholder="เลือกเพศ" name="gender" #gender="ngModel" [(ngModel)]="dataForm.customer.gender" appendTo="body" >
|
||||
<ng-option *ngFor="let item of genderData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เบอร์โทร</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="phone" #phone="ngModel" [(ngModel)]="dataForm.customer.phone" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เลขบัตรประชาชน</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="idCard" #idCard="ngModel" [(ngModel)]="dataForm.customer.idCard" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<div style="height: 20px;"></div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<div class="">
|
||||
<input hidden type="file" accept="image/*" #idCardImages (change)="onAttachmentsIdCard($event, 'idcard')" />
|
||||
<button type="button" class="btn btn-icon-upload color-main" (click)="idCardImages.click()">
|
||||
<ng-container *ngIf="!dataForm.customer.idCardImage"> <i class="bi bi-plus-circle "></i> สำเนาบัตรประชาชน</ng-container>
|
||||
<ng-container *ngIf="dataForm.customer.idCardImage"> <i class="bi bi-pencil" matTooltip="แก้ไขสำเนาบัตรประชาชน"></i> </ng-container>
|
||||
</button>
|
||||
</div>
|
||||
<div style="padding-top: 4px;">
|
||||
<ng-container *ngIf="dataForm.customer.idCardImage">
|
||||
<div class="cursor-pointer" (click)="onAttachmentsView('images')"><i class="bi bi-search"></i> ดูสำเนาบัตรประชาชน</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col-span-8 md:hidden"></div>
|
||||
|
||||
<div class="col-span-12 md:col-span-12 ">
|
||||
<mat-label>ที่อยู่ตามบัตรประชาชน</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="address" #address="ngModel" [(ngModel)]="dataForm.customer.address" (ngModelChange)="onChangeAddress('address', $event)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-12 md:col-span-12 ">
|
||||
<mat-label>ที่อยู่ในการจัดส่ง</mat-label>
|
||||
<label class="inline-flex items-center cursor-pointer select-none ml-2">
|
||||
<input type="checkbox" name="isAddress" [(ngModel)]="dataForm.customer.isAddress" (ngModelChange)="onChangeAddress('isAddress', $event)">
|
||||
<span style="padding-left: 2px;">ใช้ที่อยู่ตามบัตรประชาชน</span>
|
||||
</label>
|
||||
|
||||
<mat-form-field>
|
||||
<input matInput name="deliveryAddress" #deliveryAddress="ngModel" [(ngModel)]="dataForm.customer.deliveryAddress" [disabled]="dataForm.customer.isAddress">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>E-mail</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="email" #email="ngModel" [(ngModel)]="dataForm.customer.email">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-8 md:col-span-12 ">
|
||||
<mat-label>อาชีพ</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="occupation" #occupation="ngModel" [(ngModel)]="dataForm.customer.occupation">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ID Line</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="line" #line="ngModel" [(ngModel)]="dataForm.customer.line">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>Facebook</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="facebook" #facebook="ngModel" [(ngModel)]="dataForm.customer.facebook">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>IG</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="ig" #ig="ngModel" [(ngModel)]="dataForm.customer.ig">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> ข้อมูลคนขาย</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 mt-4 mb-4">
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ค้นหาเลขประจําตัวผู้เสียภาษี</mat-label>
|
||||
<ng-select placeholder="ค้นหาเลขประจําตัวผู้เสียภาษี" name="filterSeller" #filterSeller="ngModel" [(ngModel)]="dataFilter.filterSeller" (ngModelChange)="onChangeFilter($event)" appendTo="body" >
|
||||
<ng-option *ngFor="let item of seller" [value]="item.id"> {{item.idCard}} : {{item.prefix}} {{item.firstName}} {{item.lastName}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-8 md:hidden"></div>
|
||||
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>คำนำหน้า</mat-label>
|
||||
<ng-select placeholder="เลือกคำนำหน้า" name="sellerprefix" #sellerprefix="ngModel" [(ngModel)]="dataForm.seller.prefix" appendTo="body" required>
|
||||
<ng-option *ngFor="let item of prefixData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ชื่อลูกค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerfirstName" #sellerfirstName="ngModel" [(ngModel)]="dataForm.seller.firstName" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>นามสกุล</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerlastName" #sellerlastName="ngModel" [(ngModel)]="dataForm.seller.lastName" >
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>เพศ</mat-label>
|
||||
<ng-select placeholder="เลือกเพศ" name="sellergender" #sellergender="ngModel" [(ngModel)]="dataForm.seller.gender" appendTo="body" >
|
||||
<ng-option *ngFor="let item of genderData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เบอร์โทร</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerPhone" #sellerPhone="ngModel" [(ngModel)]="dataForm.seller.phone" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>Facebook</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerFacebook" #sellerFacebook="ngModel" [(ngModel)]="dataForm.seller.facebook">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ID Line</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerLine" #sellerLine="ngModel" [(ngModel)]="dataForm.seller.line">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ID LINE ร้านค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerLineShop" #sellerLineShop="ngModel" [(ngModel)]="dataForm.seller.lineShop">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>IG</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerIg" #sellerIg="ngModel" [(ngModel)]="dataForm.seller.ig">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>S/N สินค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerSnProduct" #sellerSnProduct="ngModel" [(ngModel)]="dataForm.seller.snProduct">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>แหล่งที่มา</mat-label>
|
||||
<ng-select placeholder="เลือกแหล่งที่มา" name="source" #source="ngModel" [(ngModel)]="dataForm.source" appendTo="body" >
|
||||
<ng-option *ngFor="let item of sourceData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<!-- <div class="col-span-4 md:col-span-12 ">-->
|
||||
<!-- <mat-label>ค่าขนส่ง</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <input matInput name="shippingCost" #shippingCost="ngModel" [(ngModel)]="dataForm.shippingCost">-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mt-6">
|
||||
<div class="card-header ">
|
||||
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-6 md:col-span-12">
|
||||
<div class="flex items-center w-full">
|
||||
<div class="">รูปแบบการวัด</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 md:col-span-12 ">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ng-container *ngFor="let item of dataForm.productMeasurement; let i = index">
|
||||
<div class="form-list">
|
||||
<div class="form-list-item grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-7 md:col-span-11">
|
||||
<label *ngIf="i === 0">รายการวัด</label>
|
||||
<mat-form-field>
|
||||
<input matInput name="productMeasurementName-{{i}}" #productMeasurementName="ngModel" [(ngModel)]="item.name" >
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-6">
|
||||
<label *ngIf="i === 0">ขนาด</label>
|
||||
<mat-form-field>
|
||||
<input appNumberOnly matInput name="productMeasurementSize-{{i}}" #productMeasurementSize="ngModel" [(ngModel)]="item.size" >
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-5">
|
||||
<label *ngIf="i === 0">หน่วยนับ</label>
|
||||
<ng-select placeholder="เลือกหน่วยนับ" name="productMeasurementUnit-{{i}}" #productMeasurementUnit="ngModel" [(ngModel)]="item.unitId" appendTo="body" >
|
||||
<ng-option *ngFor="let item of masterProductUnit" [value]="item.id">{{item.name}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-right mt-4 ">
|
||||
<mat-checkbox name="depositChecked" #depositChecked="ngModel" [(ngModel)]="dataForm.depositChecked">ชำระเงินเพิ่ม</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="card card-table mb-6">
|
||||
<div class="card-body">
|
||||
<div class="table-wrap">
|
||||
<table class="tables ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>BOM</th>
|
||||
<th>Brand</th>
|
||||
<th>Model</th>
|
||||
<th>ราคาสินค้า</th>
|
||||
<th>จำนวนเงินมัดจำ</th>
|
||||
<th>ค่ามัดจำเพิ่ม</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="text-center">{{dataForm.productNo}}</td>
|
||||
<td class="text-center">{{dataForm.productBrandName}}</td>
|
||||
<td class="text-center">{{dataForm.productName }}</td>
|
||||
<td class="text-center">{{dataForm.price | number : '1.2-2'}}</td>
|
||||
<td class="text-center">
|
||||
<div class="b-color-orange">{{dataForm.deposit | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
<td>
|
||||
<mat-form-field>
|
||||
<input matInput name="paymentAmount" #paymentAmount="ngModel" [(ngModel)]="dataForm.paymentAmount" [required]="dataForm.depositChecked" [disabled]="!dataForm.depositChecked">
|
||||
</mat-form-field>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title flex items-center">
|
||||
<div class="">รูปสินค้าจากลูกค้า</div>
|
||||
|
||||
<div class="ml-4">
|
||||
<input hidden type="file" accept="image/*" #productImages (change)="onAttachments($event, 'products')" />
|
||||
<button type="button" class="btn btn-sm btn-success-o" (click)="productImages.click()">เพิ่มรูปภาพสินค้า</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="list-images">
|
||||
<div class=" grid grid-cols-12 gap-2 md:gap-2 items-center">
|
||||
<ng-container *ngFor="let item of attachments; let i = index">
|
||||
<div class="col-span-2 md:col-span-4">
|
||||
<div class="flex justify-center items-center list-images-item">
|
||||
<div class="list-images-action">
|
||||
<i *ngIf="dataForm.coverImage !== item" (click)="dataForm.coverImage = item"
|
||||
matTooltip="ใช้ทำเอกสาร" class="bi bi-star color-main cursor-pointer select-none"></i>
|
||||
<i *ngIf="dataForm.coverImage === item" class="bi bi bi-star-fill color-main cursor-pointer select-none"></i>
|
||||
<i (click)="onRemoveAttachments(i, item)" class="bi bi-x-circle color-red cursor-pointer select-none"></i>
|
||||
</div>
|
||||
<img src="{{storage.products}}/{{item}}" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title flex items-center">
|
||||
<div class="">อุปกรณ์</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<ng-container *ngFor="let item of equipmentData; let i = index">
|
||||
<div class="form-list">
|
||||
<div class="form-list-item grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-1 md:col-span-2 text-right">
|
||||
<div *ngIf="i === 0" style="height: 25px;"></div>
|
||||
<input type="checkbox" name="isCheck-{{i}}" #isCheck="ngModel" [(ngModel)]="item.isCheck">
|
||||
</div>
|
||||
<div class="col-span-9 md:col-span-8 cursor-pointer select-none" (click)="item.isCheck = !item.isCheck">
|
||||
<div *ngIf="i === 0" style="height: 25px;"></div>
|
||||
{{item.name}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="isEquipmentOther()">
|
||||
<ng-container *ngFor="let item of equipmentOtherData; let i = index">
|
||||
<div class="form-list">
|
||||
<div class="form-list-item grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-1 md:col-span-2 text-right">
|
||||
|
||||
</div>
|
||||
<div class="col-span-9 md:col-span-8 cursor-pointer select-none" >
|
||||
<mat-form-field>
|
||||
<input matInput name="equipmentOtherItem-{{i}}" #equipmentOtherItem="ngModel" [(ngModel)]="item.value" >
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-2 " >
|
||||
<i (click)="onAddEquipmentOther()" class="bi bi-plus-circle color-green cursor-pointer select-none mr-2"></i>
|
||||
<i (click)="onRemoveEquipmentOther(i)" class="bi bi-x-circle color-red cursor-pointer select-none"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<div style="height: 40px;"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main-form-action text-right" *ngIf="dataForm.status3rdTime !== 'complete' ">
|
||||
<button type="submit" class="btn btn-submit">บันทึก</button>
|
||||
<button type="button" class="btn btn-back" (click)="onAction('back')">ยกเลิก</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@@ -0,0 +1,283 @@
|
||||
import { ChangeDetectorRef, Component, OnInit } from "@angular/core";
|
||||
import {API, EAction, EText, GENDER, PREFIX, SOURCES, STORAGE} from "../../../../@config/app";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { BaseFormComponent } from "../../../../@common/base/base-form.component";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { IProduct } from "../../../../app.interface";
|
||||
import deepCopy from "../../../../@common/utils/DeepCopy";
|
||||
import { AttachmentsViewComponent } from "../../../@popup/attachments-view/attachments-view.component";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-3rd-time-do",
|
||||
templateUrl: "./appraisal-3rd-time-do.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class Appraisal3rdTimeDoComponent extends BaseFormComponent implements OnInit {
|
||||
|
||||
override dataForm: any = {};
|
||||
dataView: IProduct = {};
|
||||
auth: any = {};
|
||||
title = "";
|
||||
api: any = API;
|
||||
storage: any = STORAGE;
|
||||
attachments: any = [];
|
||||
settings: any = [];
|
||||
masterProductUnit: any = [];
|
||||
deviation: any = 0;
|
||||
prefixData = PREFIX;
|
||||
genderData = GENDER;
|
||||
sourceData = SOURCES;
|
||||
customer : any = [];
|
||||
seller : any = [];
|
||||
equipmentData : any = [];
|
||||
equipmentOtherData : any = [{value : ''}];
|
||||
|
||||
constructor(
|
||||
public activatedRoute: ActivatedRoute,
|
||||
public router: Router,
|
||||
public changeDetectorRef: ChangeDetectorRef,
|
||||
public appService: AppService,
|
||||
private attachmentsView: MatDialog,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.activatedRoute.params.subscribe(async params => {
|
||||
this.ids = params["id"];
|
||||
this.action = params["action"];
|
||||
this.auth = this.appService.auth();
|
||||
this.dataForm.customer = {};
|
||||
this.dataForm.seller = {};
|
||||
this.defaultEquipmentData();
|
||||
this.settings = await lastValueFrom(this.appService.get(`${this.api.settings}/getByCode/DEVIATION`));
|
||||
this.masterProductUnit = await lastValueFrom(this.appService.get(`${this.api.masterProductUnit}?showAll=true&status=true&orderBy=name&sort=asc`));
|
||||
this.customer = await lastValueFrom(this.appService.get(`${API.customer}?showAll=true`));
|
||||
this.seller = await lastValueFrom(this.appService.get(`${API.customer}?showAll=true`));
|
||||
if (this.ids) await this.getData();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
async onAction(action: string) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.BACK));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
if (action === "back") return this.router.navigate(["/pages/appraisal/3rd-time/list", this.action]);
|
||||
return;
|
||||
}
|
||||
|
||||
async getData() {
|
||||
if (!this.ids) this.appService.message(EAction.INFO, EText.NO_DATA);
|
||||
try {
|
||||
this.dataForm = await lastValueFrom(this.appService.get(`${this.api.quotation}/getById/${this.ids}`));
|
||||
this.attachments = this.dataForm.images ? this.dataForm.images?.split(",") : [];
|
||||
|
||||
this.dataForm.productMeasurement.map((item : any) => {
|
||||
item.sizeOld = item.size;
|
||||
item.size = this.dataForm.status3rdTime === 'wait' ? null : item.size;
|
||||
})
|
||||
|
||||
this.dataForm.deposit = Number(this.dataForm.deposit) + Number(this.dataForm.sellerDeposit2ndTime)
|
||||
if (this.dataForm.customer.isAddress) this.dataForm.customer.deliveryAddress = this.dataForm.customer.address;
|
||||
|
||||
|
||||
if(!this.dataForm.sellerId) {
|
||||
this.dataForm.seller = {};
|
||||
this.dataForm.seller.name = this.dataForm.sellerName;
|
||||
this.dataForm.seller.phone = this.dataForm.sellerPhone;
|
||||
this.dataForm.seller.facebook = this.dataForm.sellerFacebook;
|
||||
this.dataForm.seller.line = this.dataForm.sellerLine;
|
||||
this.dataForm.seller.lineShop = this.dataForm.sellerLineShop;
|
||||
this.dataForm.seller.ig = this.dataForm.sellerIg;
|
||||
this.dataForm.seller.snProduct = this.dataForm.sellerSnProduct;
|
||||
}
|
||||
|
||||
const equipment : any[] = this.dataForm.equipment ? this.dataForm.equipment?.split(",") : [];
|
||||
const equipmentOther : any[] = this.dataForm.equipmentOther ? this.dataForm.equipmentOther?.split(",") : [];
|
||||
|
||||
if (equipment.length) {
|
||||
this.equipmentData.map((d: any) => {
|
||||
if (equipment.includes(d.name)) d.isCheck = true;
|
||||
})
|
||||
}
|
||||
|
||||
if (equipmentOther.length) {
|
||||
this.equipmentOtherData = [];
|
||||
equipmentOther.map((d : any) => {
|
||||
this.equipmentOtherData.push({ value : d});
|
||||
})
|
||||
}
|
||||
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
async onChangeFilter(value : any) {
|
||||
if (!value) return await this.getData();
|
||||
this.dataForm.seller = this.seller.filter((f : any) => f.id === value)?.[0];
|
||||
}
|
||||
|
||||
onChangeAddress(key : string, value : any) {
|
||||
if (key === 'isAddress') this.dataForm.customer.deliveryAddress = value ? this.dataForm.customer.address : '';
|
||||
if (key === 'address') this.dataForm.customer.deliveryAddress = this.dataForm.customer.isAddress ? value : this.dataForm.customer.deliveryAddress;
|
||||
}
|
||||
|
||||
|
||||
async onSubmit(form: any) {
|
||||
if (!form.valid) return false;
|
||||
const error : any[] = [];
|
||||
this.dataForm.productMeasurement.map((item : any) => {
|
||||
if (!item.size) return;
|
||||
const deviation = (Number(this.settings.value) / 100) * Number(item.sizeOld);
|
||||
const deviationSize = Number(item.sizeOld) + deviation;
|
||||
console.log(deviationSize);
|
||||
if (Number(item.size) > deviationSize) {
|
||||
const msg = `${item.name} ขนาดมากกว่าค่าเบี่ยงเบนการวัด (${deviationSize})`;
|
||||
error.push(msg)
|
||||
}
|
||||
})
|
||||
|
||||
if (error.length > 0) {
|
||||
const msg = error.join("<br>");
|
||||
return this.appService.html(EAction.INFO, msg);
|
||||
}
|
||||
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.CREATE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
|
||||
const equipment : any[] = [];
|
||||
this.equipmentData.map((d : any) => {
|
||||
if (d.isCheck) equipment.push(d.name);
|
||||
})
|
||||
this.dataForm.equipment = equipment?.[0] ? equipment.join(",") : null;
|
||||
this.dataForm.equipmentOther = null;
|
||||
|
||||
if (equipment.includes('อื่นๆ')) {
|
||||
const equipmentOther : any[] = [];
|
||||
this.equipmentOtherData.map((d : any) => {
|
||||
equipmentOther.push(d.value);
|
||||
})
|
||||
this.dataForm.equipmentOther = equipmentOther?.[0] ? equipmentOther.join(",") : null;
|
||||
}
|
||||
|
||||
this.dataForm.pageAction = '3rd-time';
|
||||
this.dataForm.images = this.attachments?.[0] ? this.attachments.join(",") : null;
|
||||
return await this.onUpdate();
|
||||
|
||||
}
|
||||
|
||||
|
||||
async onUpdate() {
|
||||
try {
|
||||
await lastValueFrom(this.appService.post(`${this.api.quotation}/update/${this.ids}`, this.dataForm));
|
||||
await this.appService.message(EAction.SUCCESS, EText.UPDATE);
|
||||
await this.router.navigate(["/pages/appraisal/3rd-time/list", this.action]);
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async onAttachments($event: any, type: any) {
|
||||
const file = $event.target.files[0];
|
||||
if (!file) return;
|
||||
const formData = new FormData();
|
||||
formData.append("ref", type);
|
||||
formData.append("file", file);
|
||||
try {
|
||||
const res = await lastValueFrom(this.appService.post(`${this.api.attachments}/products`, formData));
|
||||
if (!this.attachments[0]) {
|
||||
this.dataForm.coverImage = res.fileName;
|
||||
}
|
||||
this.attachments.push(res.fileName);
|
||||
console.log(this.attachments, res);
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} catch (e) {
|
||||
this.appService.message(EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
async onRemoveAttachments(i: number, fileName: string) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.DELETE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
// await lastValueFrom(this.appService.delete(`${this.api.attachments}/deleteByName`, fileName));
|
||||
this.attachments?.splice(i, 1);
|
||||
if (!this.attachments[0]) {
|
||||
this.dataForm.coverImage = null;
|
||||
}
|
||||
this.changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
async onAttachmentsIdCard($event: any, type: any) {
|
||||
const file = $event.target.files[0];
|
||||
if (!file) return;
|
||||
const formData = new FormData();
|
||||
formData.append("ref", type);
|
||||
formData.append("file", file);
|
||||
try {
|
||||
const res = await lastValueFrom(this.appService.post(`${API.attachments}/images`, formData));
|
||||
|
||||
this.dataForm.customer.idCardImage = res.fileName;
|
||||
|
||||
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} catch (e) {
|
||||
this.appService.message(EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
async onAttachmentsView(type : any) {
|
||||
const dialogConfig = deepCopy(this.dialogConfig);
|
||||
dialogConfig.data.action = EAction.POPUP;
|
||||
dialogConfig.data.title = 'สำเนาบัตรประชาชน';
|
||||
dialogConfig.data.type = type;
|
||||
dialogConfig.data.images = this.dataForm.customer.idCardImage;
|
||||
const dialogRef = this.attachmentsView.open(AttachmentsViewComponent, dialogConfig);
|
||||
const afterClosed = await lastValueFrom(dialogRef.afterClosed());
|
||||
|
||||
}
|
||||
|
||||
defaultEquipmentData() {
|
||||
this.equipmentData = [
|
||||
{ name : 'ตัวเปล่า', isCheck : false},
|
||||
{ name : 'ถุงกระดาษ', isCheck : false},
|
||||
{ name : 'ถุงผ้า', isCheck : false},
|
||||
{ name : 'ใบเสร็จ', isCheck : false},
|
||||
{ name : 'บุ๊ค 1', isCheck : false},
|
||||
{ name : 'บุ๊ค 2', isCheck : false},
|
||||
{ name : 'ดอกคามิเลีย', isCheck : false},
|
||||
{ name : 'ริบบิ้น', isCheck : false},
|
||||
{ name : 'ถุงกันฝน', isCheck : false},
|
||||
{ name : 'การ์ด', isCheck : false},
|
||||
{ name : 'สายกระเป๋า', isCheck : false},
|
||||
{ name : 'ใบเซอร์', isCheck : false},
|
||||
{ name : 'พวงกุญแจแม่ และลูก', isCheck : false},
|
||||
{ name : 'กล่อง', isCheck : false},
|
||||
{ name : 'สายนาฬิกา', isCheck : false},
|
||||
{ name : 'ใบรับประกัน', isCheck : false},
|
||||
{ name : 'ใบตรวจ', isCheck : false},
|
||||
{ name : 'อื่นๆ', isCheck : false},
|
||||
]
|
||||
}
|
||||
|
||||
isEquipmentOther() {
|
||||
return this.equipmentData.find((f : any) => f.name === 'อื่นๆ' && f.isCheck === true)
|
||||
}
|
||||
onAddEquipmentOther() {
|
||||
this.equipmentOtherData.push({value : ''});
|
||||
}
|
||||
onRemoveEquipmentOther(i : number) {
|
||||
if (i === 0) return;
|
||||
|
||||
this.equipmentOtherData?.splice(i, 1);
|
||||
this.changeDetectorRef.detectChanges();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<div class="card card-table">
|
||||
|
||||
<div class="card-filter text-right">
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-5 md:col-span-12 md:order-2">
|
||||
<mat-form-field>
|
||||
<i matTextPrefix class="bi bi-search"></i>
|
||||
<input matInput name="keyword" #keyword="ngModel" [(ngModel)]="dataFilter.keyword" (ngModelChange)="onFilter($event)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 items-center md:gap-2 ">
|
||||
<div class="col-span-3 md:col-span-6">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
name="startDate"
|
||||
#startDate="ngModel"
|
||||
(click)="dpkName.open()"
|
||||
[(ngModel)]="dataFilter.createdDate"
|
||||
[matDatepicker]="dpkName"
|
||||
readonly
|
||||
(ngModelChange)="getData()"
|
||||
|
||||
/>
|
||||
<!-- <mat-icon matSuffix (click)="clearDate($event)">clear</mat-icon>-->
|
||||
<mat-datepicker-toggle [for]="dpkName" matSuffix></mat-datepicker-toggle>
|
||||
<mat-datepicker #dpkName></mat-datepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-9 md:col-span-12 ">
|
||||
<div class="flex w-full ">
|
||||
<div class="">จำนวนทั้งหมด {{totalItem}} รายการ</div>
|
||||
<div class="pl-2 pr-2">|</div>
|
||||
<div class="">ค้นหาจำนวน {{totalOfElement}} รายการ</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-wrap">
|
||||
<table class="table table-main" mat-table [dataSource]="dataSource" matSort (matSortChange)="onSort($event)">
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
|
||||
<ng-container matColumnDef="quotationNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>เลขที่ใบเสนอราคา</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">{{item.quotationNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="customerFirstName">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>ชื่อลูกค้า</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">
|
||||
<ng-container *ngIf="item.customerId"> {{item.customer?.prefix}}{{item.customer?.firstName}} {{item.customer?.lastName}}</ng-container>
|
||||
<ng-container *ngIf="!item.customerId">{{item.customerFirstName}} {{item.customerLastName}}</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" mat-sort-header>BOM</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="tac">{{item.productNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productName">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Model</th>
|
||||
<td mat-cell *matCellDef="let item" class="" style="min-width: 200px;">{{item.productName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="price">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>จำนวนเงิน</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-green"> {{item.price | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="wantToInstallmentTerm">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ระยะเวลาผ่อน</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.wantToInstallmentTerm }} งวด</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="createdDate">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">วันที่บันทึก</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.createdDate | date : 'dd/MM/YYYY'}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">สถานะ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.status === 'paid' " class="status status-active">ชำระแล้ว</div>
|
||||
<div *ngIf="item.status === 'pending'" class="status status-disabled">รอชำระ</div>
|
||||
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="action">
|
||||
<th mat-header-cell *matHeaderCellDef width="80">Action</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="action flex justify-center">
|
||||
|
||||
<div class="item">
|
||||
<i class="bi bi-filetype-pdf color-main" (click)="onAction(item.id)"></i>
|
||||
</div>
|
||||
<div class="item" *ngIf="item.status === 'pending'">
|
||||
<i class="bi bi-trash3 color-red" (click)="onDelete(item.id)"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
</table>
|
||||
<div *ngIf="dataSourceCount === 0" class="no-data"></div>
|
||||
</div>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" showFirstLastButtons (page)="getData($event)"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,86 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { BaseListComponent } from "../../../../@common/base/base-list.component";
|
||||
import { debounceTime, distinctUntilChanged, lastValueFrom, Subject } from "rxjs";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { API, EAction, EText } from "../../../../@config/app";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-1st-time-index",
|
||||
templateUrl: "./appraisal-3rd-time-history.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class Appraisal3rdTimeHistoryComponent extends BaseListComponent implements OnInit {
|
||||
|
||||
pageTitle = "ประวัติการสร้างใบเสนอราคา";
|
||||
apiUrl: string = API.quotation;
|
||||
api: any = API;
|
||||
displayedColumns: string[] = ["action", "quotationNo", "customerFirstName", "productNo", "productName", "price", "wantToInstallmentTerm", "createdDate", "status"];
|
||||
masterProductCategory: any = [];
|
||||
masterProductBrand: any = [];
|
||||
filterKeyword: Subject<string> = new Subject<string>();
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
public appService: AppService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.filterKeyword.pipe(debounceTime(1000), distinctUntilChanged()).subscribe(model => {
|
||||
this.getData();
|
||||
});
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
|
||||
await this.getData();
|
||||
}
|
||||
|
||||
onAction(id?: any) {
|
||||
if (id) return this.router.navigate(["/pages/appraisal/1st-time/history/pdf", id]);
|
||||
return this.router.navigate(["/pages/appraisal/1st-time/do", "create"]);
|
||||
}
|
||||
|
||||
async getData($event?: any) {
|
||||
try {
|
||||
this.dataFilter.keywordColumn = "quotationNo,productNo,customerFirstName,customerLastName";
|
||||
const dataSource = await lastValueFrom(this.appService.get(this.setParams(this.apiUrl, $event)));
|
||||
this.dataSource = this.setDataSource<any>(dataSource);
|
||||
} catch (e) {
|
||||
this.dataSource = [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onFilter($event?: any) {
|
||||
this.filterKeyword.next($event);
|
||||
}
|
||||
clearDate($event?: any) {
|
||||
$event.stopPropagation();
|
||||
this.dataFilter.createdDate = null;
|
||||
}
|
||||
|
||||
async onSort($event: any) {
|
||||
this.dataFilter.orderBy = $event.active;
|
||||
this.dataFilter.sort = $event.direction;
|
||||
await this.getData();
|
||||
console.log($event);
|
||||
}
|
||||
|
||||
|
||||
async onDelete(ids: any) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.DELETE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
try {
|
||||
await lastValueFrom(this.appService.delete(this.apiUrl, ids));
|
||||
await this.appService.message(EAction.SUCCESS, EText.DELETE);
|
||||
await this.getData(this.getCurrentPage());
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
<div class="card card-table">
|
||||
|
||||
<div class="card-filter text-right">
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-5 md:col-span-12 md:order-2">
|
||||
<mat-form-field>
|
||||
<i matTextPrefix class="bi bi-search"></i>
|
||||
<input matInput name="keyword" #keyword="ngModel" [(ngModel)]="dataFilter.keyword" (ngModelChange)="onFilter($event)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-7 md:col-span-12 md:order-1">
|
||||
<button type="button" class="btn btn-export" (click)="onExport()">Export</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 items-center md:gap-2 ">
|
||||
<div class="col-span-6 md:col-span-12">
|
||||
<div class="tabs-btn">
|
||||
<button type="button" class="btn" [ngClass]="{ 'active' : action === 'wait'}" (click)="onTabs('wait')">รอประเมิน</button>
|
||||
<button type="button" class="btn" [ngClass]="{ 'active' : action === 'evaluated'}" (click)="onTabs('evaluated')">ประเมินแล้ว</button>
|
||||
<button type="button" class="btn" [ngClass]="{ 'active' : action === 'complete'}" (click)="onTabs('complete')">ข้อมูลครบถ้วน</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-6 md:col-span-12 ">
|
||||
<div class="flex w-full justify-end md:justify-start">
|
||||
<div class="">จำนวนทั้งหมด {{totalItem}} รายการ</div>
|
||||
<div class="pl-2 pr-2">|</div>
|
||||
<div class="">ค้นหาจำนวน {{totalOfElement}} รายการ</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-wrap">
|
||||
<table class="table table-main" mat-table [dataSource]="dataSource" matSort (matSortChange)="onSort($event)">
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
|
||||
<ng-container matColumnDef="quotationNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>เลขที่ใบเสนอราคา</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">{{item.quotationNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="customerFirstName">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>ชื่อลูกค้า</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">
|
||||
<ng-container *ngIf="item.customerId"> {{item.customer?.prefix}}{{item.customer?.firstName}} {{item.customer?.lastName}}</ng-container>
|
||||
<ng-container *ngIf="!item.customerId">{{item.customerFirstName}} {{item.customerLastName}}</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" mat-sort-header>BOM</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">{{item.productNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productName">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Model</th>
|
||||
<td mat-cell *matCellDef="let item" class="" style="min-width: 220px;">{{item.productName }}</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
|
||||
|
||||
<ng-container matColumnDef="productBrandName">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Brand</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productBrandName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productSize">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Main</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productSize }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productWeight">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150">น้ำหนัก</th>
|
||||
<td mat-cell *matCellDef="let item" class="">{{item.productWeight }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productColor">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Color</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productColor }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productYear">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Year</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productYear }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="price">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>จำนวนเงิน</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-green"> {{item.price | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="deposit">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>จำนวนมัดจำ</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-orange"> {{item.deposit | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="wantToInstallmentTerm">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ระยะเวลาผ่อน</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.wantToInstallmentTerm }} งวด</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="createdDate">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">วันที่บันทึก</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.createdDate | date : 'dd/MM/YYYY'}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">สถานะ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac" style="min-width: 100px;">
|
||||
<div *ngIf="item.status === 'paid' " class="status status-active">ชำระแล้ว</div>
|
||||
<div *ngIf="item.status === 'pending'" class="status status-disabled">รอชำระ</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ประเภทการชำระ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.type === 'deposit' " class="status-text status-deposit">ค่ามัดจำ</div>
|
||||
<div *ngIf="item.type === 'installment'" class="status-text status-installment">ผ่อนสินค้า</div>
|
||||
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="paymentType">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ประเภทการชำระ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.paymentType === 'deposit' " class="status-text status-deposit">ค่ามัดจำ</div>
|
||||
<div *ngIf="item.paymentType === 'installment'" class="status-text status-installment">ผ่อนสินค้า</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="paymentMethod">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>วิธีชำระ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.paymentMethod === 'transfer' " class="status-text status-transfer">โอนเงิน</div>
|
||||
<div *ngIf="item.paymentMethod === 'cash'" class="status-text status-cash">เงินสด</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="paymentAmountAll">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>จำนวนเงิน</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div class="b-color-green">{{item.paymentAmountAll | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="sellerDeposit3rdTime">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>เงินมัดจำเพิ่ม</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div class="b-color-red" *ngIf="item.sellerDeposit3rdTime">{{item.sellerDeposit3rdTime | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="action">
|
||||
<th mat-header-cell *matHeaderCellDef width="80">Action</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="action flex justify-center">
|
||||
|
||||
|
||||
<div class="item" *ngIf="['wait','evaluated'].includes(item.status3rdTime)" >
|
||||
<i class="bi bi-pencil-square icon-edit" (click)="onAction(item.id)"></i>
|
||||
</div>
|
||||
|
||||
<div class="item" *ngIf="['complete'].includes(item.status3rdTime)" >
|
||||
<i class="bi bi-eye color-green" (click)="onAction(item.id)"></i>
|
||||
</div>
|
||||
<!-- <div class="item" *ngIf="item.status === 'paid' ">-->
|
||||
<!-- <i class="bi bi-filetype-pdf color-main" (click)="onAction(item.id)"></i>-->
|
||||
<!-- </div>-->
|
||||
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
</table>
|
||||
<div *ngIf="dataSource?.length === 0" class="no-data"></div>
|
||||
</div>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" showFirstLastButtons (page)="getData($event)"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,132 @@
|
||||
import { ChangeDetectorRef, Component, OnInit } from "@angular/core";
|
||||
import { BaseListComponent } from "../../../../@common/base/base-list.component";
|
||||
import { debounceTime, distinctUntilChanged, lastValueFrom, Subject } from "rxjs";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { API, EAction, EStatusQuotation, EText } from "../../../../@config/app";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import generateParamsValue from "../../../../@common/utils/GenerateParamsValue";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-3rd-time-index",
|
||||
templateUrl: "./appraisal-3rd-time-index.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class Appraisal3rdTimeIndexComponent extends BaseListComponent implements OnInit {
|
||||
|
||||
pageTitle = "รับชำระเงิน/ออกใบเสร็จรับเงิน";
|
||||
action = "pending";
|
||||
apiUrl: string = API.quotation;
|
||||
api: any = API;
|
||||
|
||||
displayedColumns: string[] = [];
|
||||
masterProductCategory: any = [];
|
||||
masterProductBrand: any = [];
|
||||
filterKeyword: Subject<string> = new Subject<string>();
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
public appService: AppService,
|
||||
public activatedRoute: ActivatedRoute,
|
||||
public changeDetectorRef: ChangeDetectorRef
|
||||
) {
|
||||
super();
|
||||
|
||||
this.filterKeyword.pipe(debounceTime(1000), distinctUntilChanged()).subscribe(model => {
|
||||
this.getData();
|
||||
});
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.activatedRoute.params.subscribe(async params => {
|
||||
this.action = params["action"];
|
||||
this.dataFilter.step = 4;
|
||||
this.dataFilter.status3rdTime = this.action;
|
||||
if (!this.action) this.router.navigate(["/pages/appraisal/3rd-time/list", EStatusQuotation.WAIT]);
|
||||
await this.getData();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async onTabs(action?: any) {
|
||||
this.dataFilter = {};
|
||||
return this.router.navigate(["/pages/appraisal/3rd-time/list", action]);
|
||||
}
|
||||
|
||||
onAction(id?: any) {
|
||||
if (id) return this.router.navigate([`/pages/appraisal/3rd-time/do/${this.action}`, id]);
|
||||
return;
|
||||
}
|
||||
|
||||
async getData($event?: any) {
|
||||
try {
|
||||
this.dataFilter.keywordColumn = "productNo,productName,quotationNo,price,deposit,sellerDeposit3rdTime";
|
||||
this.dataSource = [];
|
||||
let url = API.quotation;
|
||||
if (this.action === EStatusQuotation.WAIT) {
|
||||
url = API.quotation;
|
||||
this.displayedColumns = ["action", "price", "deposit", "customerFirstName", "productNo", "productName", "productBrandName", "productSize", "productWeight", "productColor", "productYear"];
|
||||
}
|
||||
if (this.action === EStatusQuotation.EVALUATED) {
|
||||
url = API.quotation;
|
||||
delete this.dataFilter.step;
|
||||
this.displayedColumns = ["action", "price", "deposit", "sellerDeposit3rdTime", "quotationNo", "customerFirstName", "productNo", "productName", "status"];
|
||||
}
|
||||
if (this.action === EStatusQuotation.COMPLETE) {
|
||||
url = API.quotation;
|
||||
delete this.dataFilter.step;
|
||||
this.displayedColumns = ["action", "price", "deposit", "sellerDeposit3rdTime", "quotationNo", "customerFirstName", "productNo", "productName", "status"];
|
||||
}
|
||||
|
||||
const dataSource = await lastValueFrom(this.appService.get(this.setParams(url, $event)));
|
||||
this.dataSource = this.setDataSource<any>(dataSource);
|
||||
if (this.action === EStatusQuotation.WAIT) {
|
||||
this.dataSource.map((item: any) => {
|
||||
item.deposit = Number(item.deposit) + Number(item.sellerDeposit2ndTime)
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
this.dataSource = [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onFilter($event?: any) {
|
||||
this.filterKeyword.next($event);
|
||||
}
|
||||
|
||||
clearDate($event?: any) {
|
||||
$event.stopPropagation();
|
||||
this.dataFilter.createdDate = null;
|
||||
}
|
||||
|
||||
async onSort($event: any) {
|
||||
this.dataFilter.orderBy = $event.active;
|
||||
this.dataFilter.sort = $event.direction;
|
||||
await this.getData();
|
||||
console.log($event);
|
||||
}
|
||||
|
||||
|
||||
async onDelete(ids: any) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.DELETE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
try {
|
||||
await lastValueFrom(this.appService.delete(this.apiUrl, ids));
|
||||
await this.appService.message(EAction.SUCCESS, EText.DELETE);
|
||||
await this.getData(this.getCurrentPage());
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onExport() {
|
||||
const filter = generateParamsValue(this.dataFilter);
|
||||
const url = `${API.quotation}/export-3rd-time?${filter ? '&' + filter : '' }`;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<mat-progress-bar *ngIf="!pdfView" mode="indeterminate"></mat-progress-bar>
|
||||
<iframe *ngIf="pdfView" [src]="pdfView"></iframe>
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { BaseListComponent } from "../../../../@common/base/base-list.component";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { API } from "../../../../@config/app";
|
||||
import { Router } from "@angular/router";
|
||||
import { DomSanitizer } from "@angular/platform-browser";
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-1st-time-index",
|
||||
templateUrl: "./appraisal-3rd-time-pdf.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class Appraisal3rdTimePdfComponent extends BaseListComponent implements OnInit {
|
||||
|
||||
pageTitle = "ใบเสนอราคา";
|
||||
apiUrl: string = API.quotation;
|
||||
api: any = API;
|
||||
dataView: any;
|
||||
pdfView: any;
|
||||
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
public appService: AppService,
|
||||
private sanitizer: DomSanitizer
|
||||
) {
|
||||
super();
|
||||
|
||||
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
await this.getData();
|
||||
}
|
||||
|
||||
onAction(id?: any) {
|
||||
if (id) return this.router.navigate(["/pages/appraisal/1st-time/do", "update", id]);
|
||||
return this.router.navigate(["/pages/appraisal/1st-time/do", "create"]);
|
||||
}
|
||||
|
||||
async getData($event?: any) {
|
||||
try {
|
||||
const data = {
|
||||
doc_no: "string",
|
||||
product_code: "string",
|
||||
customer_name: "string",
|
||||
phone_no: "string",
|
||||
installment_start_date: "string",
|
||||
picture: "string",
|
||||
price: 0,
|
||||
seller_deposit: 0,
|
||||
cmfs_deposit: 0,
|
||||
total_balance: 0,
|
||||
installment: 0,
|
||||
packing: 0,
|
||||
luxury_handbag_authentication: 0,
|
||||
bankfee_insurance_storage: 0,
|
||||
transfer_amount: 0,
|
||||
data: [
|
||||
{
|
||||
due_date: "string",
|
||||
principle: 0,
|
||||
interest_total: 0,
|
||||
bank_fee: 0,
|
||||
total_payment: 0,
|
||||
principle_total: 0
|
||||
}
|
||||
],
|
||||
total1: 0,
|
||||
total2: 0,
|
||||
total3: 0,
|
||||
total4: 0
|
||||
}
|
||||
this.dataView = await lastValueFrom(this.appService.post(`${this.api.quotationReport}/pdf`, data, { responseType: 'arraybuffer' }));
|
||||
|
||||
|
||||
const url = URL.createObjectURL(new Blob([this.dataView], { type: 'application/pdf' }));
|
||||
this.pdfView = this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
||||
|
||||
|
||||
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
import { ContractApprovedIndexComponent } from "./index/contract-approved-index.component";
|
||||
import { ContractApprovedDoComponent } from "./do/contract-approved-do.component";
|
||||
import { ContractApprovedPdfComponent } from "./pdf/contract-approved-pdf.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: "", component: ContractApprovedIndexComponent },
|
||||
{ path: "list", component: ContractApprovedIndexComponent },
|
||||
{ path: "list/:action", component: ContractApprovedIndexComponent },
|
||||
{ path: "do/:action", component: ContractApprovedDoComponent },
|
||||
{ path: "do/:action/:id", component: ContractApprovedDoComponent },
|
||||
{ path: "pdf/:action/:id", component: ContractApprovedPdfComponent }
|
||||
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class RoutingModule {
|
||||
}
|
||||
|
||||
export const RoutingComponents = [
|
||||
ContractApprovedIndexComponent,
|
||||
ContractApprovedDoComponent,
|
||||
ContractApprovedPdfComponent
|
||||
];
|
||||
16
src/app/pages/contract/approved/contract-approved.module.ts
Normal file
16
src/app/pages/contract/approved/contract-approved.module.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import {RoutingComponents, RoutingModule} from './contract-approved-routing.module';
|
||||
import {AppSharedModule} from "../../../app.shared";
|
||||
import { NgOptimizedImage } from "@angular/common";
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
...RoutingComponents,
|
||||
],
|
||||
imports: [
|
||||
AppSharedModule,
|
||||
RoutingModule,
|
||||
NgOptimizedImage
|
||||
]
|
||||
})
|
||||
export class ContractApprovedModule {}
|
||||
@@ -0,0 +1,694 @@
|
||||
<ul class="progressbar">
|
||||
<li [ngClass]="{ 'active' : isTabs === 1}" (click)="isTabs = 1">รายละเอียดหลัก</li>
|
||||
<li [ngClass]="{ 'active' : isTabs === 2}" (click)="isTabs = 2">การจัดผ่อน</li>
|
||||
<li [ngClass]="{ 'active' : isTabs === 3}" (click)="isTabs = 3">ข้อมูลรับชำระเงิน</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<form class="main-form" #ngf="ngForm" (ngSubmit)="onSubmit(ngf)">
|
||||
|
||||
<ng-container *ngIf="isTabs === 1">
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> สัญญาเงินกู้ระหว่าง CM-FS. Co., Ltd. ("บริษัทฯ") กับ</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 mt-4 mb-4">
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เลขที่สัญญา/BOM</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="productNo" #productNo="ngModel" [(ngModel)]="dataForm.productNo" disabled >
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<!-- <div class="col-span-4 md:col-span-12 ">-->
|
||||
<!-- <mat-label>ชื่อลูกค้า</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <div class="flex">-->
|
||||
<!-- <input style="width: 75px; padding-right: 0 !important;" matInput name="customerPrefix" #customerPrefix="ngModel" [(ngModel)]="dataForm.customer.prefix" disabled>-->
|
||||
<!-- <input style="padding-left: 0 !important;" matInput name="customerFirstName" #customerFirstName="ngModel" [(ngModel)]="dataForm.customer.firstName" disabled>-->
|
||||
<!-- </div>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-span-4 md:col-span-12 ">-->
|
||||
<!-- <mat-label>นามสกุล</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <input matInput name="customerLastName" #customerLastName="ngModel" [(ngModel)]="dataForm.customer.lastName" disabled>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-span-4 md:col-span-12 ">-->
|
||||
<!-- <mat-label>เบอร์โทร</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <input matInput name="customerPhone" #customerPhone="ngModel" [(ngModel)]="dataForm.customer.phone" disabled>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- <div class="col-span-4 md:col-span-12 ">-->
|
||||
<!-- <mat-label>เลขบัตรประชาชน</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <input matInput name="customerIdCard" #customerIdCard="ngModel" [(ngModel)]="dataForm.customer.idCard" disabled>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>วันที่ทำสัญญา</mat-label>
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
name="contractDate"
|
||||
#contractDate="ngModel"
|
||||
(click)="dpkName.open()"
|
||||
[(ngModel)]="dataForm.contractDate"
|
||||
[matDatepicker]="dpkName"
|
||||
readonly
|
||||
disabled
|
||||
/>
|
||||
<mat-datepicker-toggle [for]="dpkName" matSuffix></mat-datepicker-toggle>
|
||||
<mat-datepicker #dpkName></mat-datepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:hidden"></div>
|
||||
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>คำนำหน้า</mat-label>
|
||||
<ng-select placeholder="เลือกคำนำหน้า" name="prefix" #prefix="ngModel" [(ngModel)]="dataForm.customer.prefix" appendTo="body" disabled>
|
||||
<ng-option *ngFor="let item of prefixData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ชื่อลูกค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="firstName" #firstName="ngModel" [(ngModel)]="dataForm.customer.firstName" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>นามสกุล</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="lastName" #lastName="ngModel" [(ngModel)]="dataForm.customer.lastName" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>เพศ</mat-label>
|
||||
<ng-select placeholder="" name="gender" #gender="ngModel" [(ngModel)]="dataForm.customer.gender" appendTo="body" disabled>
|
||||
<ng-option *ngFor="let item of genderData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เบอร์โทร</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="phone" #phone="ngModel" [(ngModel)]="dataForm.customer.phone" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เลขบัตรประชาชน</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="idCard" #idCard="ngModel" [(ngModel)]="dataForm.customer.idCard" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-span-12 md:col-span-12 ">
|
||||
<mat-label>ที่อยู่ตามบัตรประชาชน</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="address" #address="ngModel" [(ngModel)]="dataForm.customer.address" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-12 md:col-span-12 ">
|
||||
<mat-label>ที่อยู่ในการจัดส่ง</mat-label>
|
||||
<label class="inline-flex items-center cursor-pointer select-none ml-2">
|
||||
<input type="checkbox" name="isAddress" [(ngModel)]="dataForm.customer.isAddress" disabled>
|
||||
<span style="padding-left: 2px;">ใช้ที่อยู่ตามบัตรประชาชน</span>
|
||||
</label>
|
||||
|
||||
<mat-form-field>
|
||||
<input matInput name="deliveryAddress" #deliveryAddress="ngModel" [(ngModel)]="dataForm.customer.deliveryAddress" [disabled]="dataForm.customer.isAddress" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>E-mail</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="email" #email="ngModel" [(ngModel)]="dataForm.customer.email" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-8 md:col-span-12 ">
|
||||
<mat-label>อาชีพ</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="occupation" #occupation="ngModel" [(ngModel)]="dataForm.customer.occupation" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ID Line</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="line" #line="ngModel" [(ngModel)]="dataForm.customer.line" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>Facebook</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="facebook" #facebook="ngModel" [(ngModel)]="dataForm.customer.facebook" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>IG</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="ig" #ig="ngModel" [(ngModel)]="dataForm.customer.ig" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> ข้อมูลร้านค้า</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 mt-4 mb-4">
|
||||
|
||||
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>คำนำหน้า</mat-label>
|
||||
<ng-select placeholder="เลือกคำนำหน้า" name="sellerprefix" #sellerprefix="ngModel" [(ngModel)]="dataForm.seller.prefix" appendTo="body" disabled>
|
||||
<ng-option *ngFor="let item of prefixData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ชื่อลูกค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerfirstName" #sellerfirstName="ngModel" [(ngModel)]="dataForm.seller.firstName" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>นามสกุล</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerlastName" #sellerlastName="ngModel" [(ngModel)]="dataForm.seller.lastName" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>เพศ</mat-label>
|
||||
<ng-select placeholder="" name="sellergender" #sellergender="ngModel" [(ngModel)]="dataForm.seller.gender" appendTo="body" disabled>
|
||||
<ng-option *ngFor="let item of genderData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เบอร์โทร</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerPhone" #sellerPhone="ngModel" [(ngModel)]="dataForm.seller.phone" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>Facebook</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerFacebook" #sellerFacebook="ngModel" [(ngModel)]="dataForm.seller.facebook" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ID Line</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerLine" #sellerLine="ngModel" [(ngModel)]="dataForm.seller.line" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ID LINE ร้านค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerLineShop" #sellerLineShop="ngModel" [(ngModel)]="dataForm.seller.lineShop" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>IG</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerIg" #sellerIg="ngModel" [(ngModel)]="dataForm.seller.ig" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>S/N สินค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerSnProduct" #sellerSnProduct="ngModel" [(ngModel)]="dataForm.seller.snProduct" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>แหล่งที่มา</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="source" #source="ngModel" [(ngModel)]="dataForm.source" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<!-- <div class="col-span-4 md:col-span-12 ">-->
|
||||
<!-- <mat-label>ค่าขนส่ง</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <input matInput name="shippingCost" #shippingCost="ngModel" [(ngModel)]="dataForm.shippingCost" disabled>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-table card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> ข้อมูลสินค้า</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 mb-2">
|
||||
<div class="col-span-3 md:col-span-12 ">
|
||||
<mat-label>Condition</mat-label>
|
||||
<ng-select placeholder="Condition" name="condition" #condition="ngModel" [(ngModel)]="dataForm.productCondition" disabled>
|
||||
<ng-option *ngFor="let item of conditions" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
|
||||
<div class="col-span-3 md:col-span-12 ">
|
||||
<mat-label>Year</mat-label>
|
||||
<mat-form-field>
|
||||
<input appNumberOnly matInput name="year" #year="ngModel" [(ngModel)]="dataForm.productYear" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table class="tables ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>BOM</th>
|
||||
<th>Model</th>
|
||||
<th>Brand</th>
|
||||
<th>Main</th>
|
||||
<th>น้ำหนัก</th>
|
||||
<th>Color</th>
|
||||
<th>Year</th>
|
||||
<th>ราคาสินค้า</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="text-center">{{dataForm.productNo}}</td>
|
||||
<td class="text-center">{{dataForm.productName }}</td>
|
||||
<td class="text-center">{{dataForm.productBrandName}}</td>
|
||||
<td class="text-center">{{dataForm.productSize }}</td>
|
||||
<td class="text-center">{{dataForm.productWeight }}</td>
|
||||
<td class="text-center">{{dataForm.productColor }}</td>
|
||||
<td class="text-center">{{dataForm.productYear }}</td>
|
||||
<td class="text-center"> <div class="b-color-orange">{{dataForm.price | number : '1.2-2'}}</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title flex items-center">
|
||||
<div class="">รูปสินค้าจากลูกค้า</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="list-images">
|
||||
<div class=" grid grid-cols-12 gap-2 md:gap-2 items-center">
|
||||
<ng-container *ngFor="let item of attachments; let i = index">
|
||||
<div class="col-span-2 md:col-span-4">
|
||||
<div class="flex justify-center items-center list-images-item">
|
||||
<div class="list-images-action">
|
||||
<i *ngIf="dataForm.coverImage !== item" class="bi bi-star color-main cursor-pointer select-none"></i>
|
||||
<i *ngIf="dataForm.coverImage === item" class="bi bi bi-star-fill color-main cursor-pointer select-none"></i>
|
||||
</div>
|
||||
<img src="{{storage.products}}/{{item}}" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title flex items-center">
|
||||
<div class="">อุปกรณ์</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<ng-container *ngFor="let item of equipment; let i = index">
|
||||
<div class="form-list">
|
||||
<div class="form-list-item grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
|
||||
<div class="col-span-9 md:col-span-8 " >{{item}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="equipment.includes('อื่นๆ')">
|
||||
<ng-container *ngFor="let item of equipmentOther; let i = index">
|
||||
<div class="form-list">
|
||||
<div class="form-list-item grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
|
||||
<div class="col-span-9 md:col-span-8 " >{{item}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<div style="height: 20px;"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="isTabs === 2">
|
||||
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 ">
|
||||
<div class="col-span-6 md:col-span-12">
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> ข้อมูลการจัดผ่อน</div>
|
||||
</div>
|
||||
<div class="card-body form-input-list">
|
||||
<div style="height: 20px;"></div>
|
||||
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> วันที่เริ่มจัดผ่อน</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
name="startDate"
|
||||
#startDate="ngModel"
|
||||
(click)="dpkName.open()"
|
||||
[(ngModel)]="dataForm.startDate"
|
||||
[matDatepicker]="dpkName"
|
||||
readonly
|
||||
disabled
|
||||
/>
|
||||
<mat-datepicker-toggle [for]="dpkName" matSuffix></mat-datepicker-toggle>
|
||||
<mat-datepicker #dpkName></mat-datepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> ราคา (Price)</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="price" #price="ngModel" [(ngModel)]="dataForm.price" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> มัดจำแม่ค้า</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="sellerDeposit" #sellerDeposit="ngModel" [(ngModel)]="dataForm.sellerDeposit" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> มัดจำ CMFS</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="deposit" #deposit="ngModel" [(ngModel)]="dataForm.deposit" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> เงินต้นคงเหลือ (Total)</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="principalBalanceTotal" #principalBalanceTotal="ngModel" [(ngModel)]="dataForm.principalBalanceTotal" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> ต้องการผ่อน (Term)</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput type="number" name="wantToInstallmentTerm" #wantToInstallmentTerm="ngModel" [(ngModel)]="dataForm.wantToInstallmentTerm" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">งวด</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 20px;"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-6 md:col-span-12">
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> รายละเอียดค่าใช้จ่ายในการโอนเงิน</div>
|
||||
</div>
|
||||
<div class="card-body form-input-list">
|
||||
<div style="height: 20px;"></div>
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> มัดจำ CMFS Deposit</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="cmfsDeposit" #cmfsDeposit="ngModel" [(ngModel)]="dataForm.cmfsDeposit" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> หัก เงินมัดจำแม่ค้า </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="lessSellerDeposit" #lessSellerDeposit="ngModel" [(ngModel)]="dataForm.lessSellerDeposit" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> บวก Packing </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="plusPacking" #plusPacking="ngModel" [(ngModel)]="dataForm.plusPacking" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> บวก Luxury handbag </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="plusLuxuryHandbag" #plusLuxuryHandbag="ngModel" [(ngModel)]="dataForm.plusLuxuryHandbag" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> บวก Bank fee, Insurance , Storage</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="plusBankFee" #plusBankFee="ngModel" [(ngModel)]="dataForm.plusBankFee" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> ส่วนลด </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="discount" #discount="ngModel" [(ngModel)]="dataForm.discount" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> สรุปยอดโอน </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="transferSummary" #transferSummary="ngModel" [(ngModel)]="dataForm.transferSummary" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="height: 10px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="card card-table mb-6">
|
||||
<div class="card-body">
|
||||
<div class="table-wrap" *ngIf="dataForm.quotationDetail?.[0]">
|
||||
<table class="tables">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>งวดที่</th>
|
||||
<th>กำหนดจ่ายวันที่ <br>Due date</th>
|
||||
<th>เงินต้น <br>Principle</th>
|
||||
<th>ดอกเบี้ย(บาท) <br>Interest Total</th>
|
||||
<th>Bank fee, <br>Insurance ,Storage</th>
|
||||
<th>รวมยอดจ่ายต่อเดือน <br>Total payment</th>
|
||||
<th>เงินต้นคงเหลือ <br>Principle Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<ng-container *ngFor="let item of dataForm.quotationDetail; let i = index">
|
||||
<tr>
|
||||
<td class="text-center">{{item.installment }}</td>
|
||||
<td class="text-center">{{item.dueDate | date : 'dd/MM/YYYY'}}</td>
|
||||
<td class="text-center">{{item.principle | number : '1.0-0'}}</td>
|
||||
<td class="text-center">{{item.interestTotal | number : '1.0-0'}}</td>
|
||||
<td class="text-center">{{item.fee | number : '1.0-0'}}</td>
|
||||
<td class="text-center"><span class="b-color-green">{{item.totalPayment | number : '1.0-0'}}</span></td>
|
||||
<td class="text-center"><span class="b-color-orange" *ngIf="item.principleTotal">{{item.principleTotal | number : '1.0-0'}}</span></td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
<tr>
|
||||
<td colspan="2" class="text-right"><b>รวม</b></td>
|
||||
<td class="text-center">{{dataForm.principleSum | number : '1.0-0'}}</td>
|
||||
<td class="text-center">{{dataForm.interestTotalSum | number : '1.0-0'}}</td>
|
||||
<td class="text-center">{{dataForm.feeSum | number : '1.0-0'}}</td>
|
||||
<td class="text-center"><span class="b-color-green">{{dataForm.totalPaymentSum | number : '1.0-0'}}</span></td>
|
||||
<td class="text-center"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="isTabs === 3">
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> ข้อมูลธนาคารที่รับชำระเงิน</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 mt-4 mb-4">
|
||||
<div class="col-span-8 md:col-span-12 ">
|
||||
<mat-label>ชื่อธนาคาร</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="productNo" #productNo="ngModel" [(ngModel)]="dataForm.contractBankName" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:hidden"></div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ชื่อบัญชี</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="contractAccountName" #contractAccountName="ngModel" [(ngModel)]="dataForm.contractAccountName" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เลขที่บัญชี</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="contractAccountNumber" #contractAccountNumber="ngModel" [(ngModel)]="dataForm.contractAccountNumber" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> รายละเอียดท้ายสัญญา</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 mt-4 mb-4">
|
||||
<div class="col-span-12 md:col-span-12 ">
|
||||
<mat-form-field>
|
||||
<textarea matInput [(ngModel)]="dataForm.contractDetail" name="contractDetail" #contractDetail="ngModel" placeholder="" disabled></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ng-container>
|
||||
|
||||
<div class="main-form-action text-right">
|
||||
<ng-container *ngIf="dataForm.statusContract === 'pending' ">
|
||||
<button type="button" class="btn btn-red" (click)="onSubmitCancel(ngf)">ไม่อนุมัติ</button>
|
||||
<button type="submit" class="btn btn-submit">อนุมัติ</button>
|
||||
</ng-container>
|
||||
|
||||
<button type="button" class="btn btn-back" (click)="onAction('back')">ยกเลิก</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@@ -0,0 +1,187 @@
|
||||
import { ChangeDetectorRef, Component, OnInit } from "@angular/core";
|
||||
import {API, CONDITIONS, EAction, EText, GENDER, PREFIX, SOURCES, STORAGE} from "../../../../@config/app";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { BaseFormComponent } from "../../../../@common/base/base-form.component";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { IProduct } from "../../../../app.interface";
|
||||
import {sortByProperty} from "../../../../@common/utils/OrderBy";
|
||||
import {C} from "@angular/cdk/keycodes";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-3rd-time-do",
|
||||
templateUrl: "./contract-approved-do.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class ContractApprovedDoComponent extends BaseFormComponent implements OnInit {
|
||||
|
||||
override dataForm: any = {};
|
||||
dataView: IProduct = {};
|
||||
auth: any = {};
|
||||
title = "";
|
||||
api: any = API;
|
||||
storage: any = STORAGE;
|
||||
attachments: any = [];
|
||||
equipment: any = [];
|
||||
equipmentOther: any = [];
|
||||
settings: any = [];
|
||||
masterProductUnit: any = [];
|
||||
deviation: any = 0;
|
||||
isTabs: any = 1;
|
||||
prefixData = PREFIX;
|
||||
genderData = GENDER;
|
||||
conditions = CONDITIONS;
|
||||
|
||||
constructor(
|
||||
public activatedRoute: ActivatedRoute,
|
||||
public router: Router,
|
||||
public changeDetectorRef: ChangeDetectorRef,
|
||||
public appService: AppService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.activatedRoute.params.subscribe(async params => {
|
||||
this.ids = params["id"];
|
||||
this.action = params["action"];
|
||||
this.auth = this.appService.auth();
|
||||
this.dataForm.customer = {};
|
||||
this.dataForm.sellsr = {};
|
||||
if (this.ids) await this.getData();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
async onAction(action: string) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.BACK));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
if (action === "back") return this.router.navigate(["/pages/contract/approved/list", this.action]);
|
||||
return;
|
||||
}
|
||||
|
||||
async getData() {
|
||||
if (!this.ids) this.appService.message(EAction.INFO, EText.NO_DATA);
|
||||
try {
|
||||
this.dataForm = await lastValueFrom(this.appService.get(`${this.api.quotation}/getById/${this.ids}`));
|
||||
this.attachments = this.dataForm.images ? this.dataForm.images?.split(",") : [];
|
||||
this.equipment = this.dataForm.equipment ? this.dataForm.equipment?.split(",") : [];
|
||||
this.equipmentOther = this.dataForm.equipmentOther ? this.dataForm.equipmentOther?.split(",") : [];
|
||||
this.dataForm.deposit = Number(this.dataForm.deposit) + Number(this.dataForm.sellerDeposit2ndTime) + Number(this.dataForm.sellerDeposit3rdTime);
|
||||
if (!this.dataForm.customerId) {
|
||||
this.dataForm.customer = {};
|
||||
this.dataForm.customer.prefix = this.dataForm.customerPrefix;
|
||||
this.dataForm.customer.firstName = this.dataForm.customerFirstName;
|
||||
this.dataForm.customer.lastName = this.dataForm.customerLastName;
|
||||
this.dataForm.customer.phone = this.dataForm.customerPhone;
|
||||
}
|
||||
|
||||
sortByProperty(this.dataForm.quotationDetail, 'installment', 'ASC');
|
||||
|
||||
this.dataForm.principleSum = 0
|
||||
this.dataForm.interestTotalSum = 0
|
||||
this.dataForm.feeSum = 0
|
||||
this.dataForm.feeSum = 0
|
||||
this.dataForm.totalPaymentSum = 0
|
||||
|
||||
this.dataForm.quotationDetail.map((item : any) => {
|
||||
this.dataForm.principleSum += Number(item.principle)
|
||||
this.dataForm.interestTotalSum += Number(item.interestTotal)
|
||||
this.dataForm.feeSum += Number(item.fee)
|
||||
this.dataForm.totalPaymentSum += Number(item.totalPayment)
|
||||
})
|
||||
this.dataForm.principleSum = Math.round(this.dataForm.principleSum);
|
||||
|
||||
this.dataForm.contractBankName = 'ธนาคารทหารไทยธนชาต จำกัด (มหาชน)';
|
||||
this.dataForm.contractAccountName = 'บริษัท ซีเอ็ม เอฟเอส จำกัด';
|
||||
this.dataForm.contractAccountNumber = '263-2-17778-4';
|
||||
this.dataForm.contractDetail = 'ชำระเงินงวดอย่างน้อย ทุกเดือนตามวันและยอดขั้นต่ำตามตาราง โดยที่ไม่เสียค่าปรับ ทั้งนี้หากเกินกำหนด ผู้กู้ต้องเสียค่าดอกเบี้ยผิดนัดเพิ่มเติมวันละ 1,000 บาท (ไม่รวมค่าทวงถาม) หากขาดส่งเกินกว่า 60 วัน นับแต่วันผ่อนล่าสุดจะถือว่าผิดสัญญา โดยหากผู้กู้ติดสัญญาไม่ว่ากรณีใดๆ ผู้กู้ยินดีที่จะนำสังหาริมทรัพย์ที่ผู้กู้นำเงินที่กู้ไปซื้อเป็นค่าตอบแทนในการชำระหนี้สินส่วนที่เหลือโดยทันที';
|
||||
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async onSubmitCancel(form: any) {
|
||||
this.dataForm.isStatusContract = 'cancel';
|
||||
await this.onSubmit(form)
|
||||
}
|
||||
async onSubmit(form: any) {
|
||||
try {
|
||||
// console.log(form);
|
||||
// if (!form.valid) return false;
|
||||
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.CREATE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
|
||||
|
||||
if (this.dataForm.isStatusContract) {
|
||||
this.dataForm.statusContract = 'cancel';
|
||||
this.dataForm.contractCancelDate = new Date();
|
||||
this.dataForm.contractCancelBy = this.auth.id;
|
||||
}
|
||||
if (!this.dataForm.isStatusContract) {
|
||||
this.dataForm.statusContract = 'approved';
|
||||
this.dataForm.contractApprovedDate = new Date();
|
||||
this.dataForm.contractApprovedBy = this.auth.id;
|
||||
this.dataForm.statusWarehouse = 'warehouse';
|
||||
}
|
||||
|
||||
this.dataForm.images = this.attachments?.[0] ? this.attachments.join(",") : null;
|
||||
return await this.onUpdate();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
async onUpdate() {
|
||||
try {
|
||||
await lastValueFrom(this.appService.post(`${this.api.quotation}/update/${this.ids}`, this.dataForm));
|
||||
await this.appService.message(EAction.SUCCESS, EText.UPDATE);
|
||||
await this.router.navigate(["/pages/contract/approved/list", this.action]);
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async onAttachments($event: any, type: any) {
|
||||
const file = $event.target.files[0];
|
||||
if (!file) return;
|
||||
const formData = new FormData();
|
||||
formData.append("ref", type);
|
||||
formData.append("file", file);
|
||||
try {
|
||||
const res = await lastValueFrom(this.appService.post(`${this.api.attachments}/products`, formData));
|
||||
if (!this.attachments[0]) {
|
||||
this.dataForm.coverImage = res.fileName;
|
||||
}
|
||||
this.attachments.push(res.fileName);
|
||||
console.log(this.attachments, res);
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} catch (e) {
|
||||
this.appService.message(EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
async onRemoveAttachments(i: number, fileName: string) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.DELETE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
// await lastValueFrom(this.appService.delete(`${this.api.attachments}/deleteByName`, fileName));
|
||||
this.attachments?.splice(i, 1);
|
||||
if (!this.attachments[0]) {
|
||||
this.dataForm.coverImage = null;
|
||||
}
|
||||
this.changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
|
||||
protected readonly SOURCES = SOURCES;
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
<div class="card card-table">
|
||||
|
||||
<div class="card-filter text-right">
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-5 md:col-span-12 md:order-2">
|
||||
<mat-form-field>
|
||||
<i matTextPrefix class="bi bi-search"></i>
|
||||
<input matInput name="keyword" #keyword="ngModel" [(ngModel)]="dataFilter.keyword" (ngModelChange)="onFilter($event)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-7 md:col-span-12 md:order-1">
|
||||
<button type="button" class="btn btn-export" (click)="onExport()">Export</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 items-center md:gap-2 ">
|
||||
<div class="col-span-6 md:col-span-12">
|
||||
<div class="tabs-btn">
|
||||
<button type="button" class="btn" [ngClass]="{ 'active' : action === 'pending'}" (click)="onTabs('pending')">รออนุมัติ</button>
|
||||
<button type="button" class="btn" [ngClass]="{ 'active' : action === 'approved'}" (click)="onTabs('approved')">อนุมัติแล้ว</button>
|
||||
<button type="button" class="btn" [ngClass]="{ 'active' : action === 'cancel'}" (click)="onTabs('cancel')">ไม่อนุมัติ</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 md:col-span-12 ">
|
||||
<div class="flex w-full justify-end md:justify-start">
|
||||
<div class="">จำนวนทั้งหมด {{totalItem}} รายการ</div>
|
||||
<div class="pl-2 pr-2">|</div>
|
||||
<div class="">ค้นหาจำนวน {{totalOfElement}} รายการ</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-wrap">
|
||||
<table class="table table-main" mat-table [dataSource]="dataSource" matSort (matSortChange)="onSort($event)">
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
|
||||
<ng-container matColumnDef="quotationNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>เลขที่ใบเสนอราคา</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">{{item.quotationNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="customerFirstName">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>ชื่อลูกค้า</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">
|
||||
<ng-container *ngIf="item.customerId"> {{item.customer?.prefix}}{{item.customer?.firstName}} {{item.customer?.lastName}}</ng-container>
|
||||
<ng-container *ngIf="!item.customerId">{{item.customerFirstName}} {{item.customerLastName}}</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" mat-sort-header>BOM</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">{{item.productNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productName">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Model</th>
|
||||
<td mat-cell *matCellDef="let item" class="" style="min-width: 220px;">{{item.productName }}</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="productBrandName">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Brand</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productBrandName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productSize">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Main</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productSize }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productWeight">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" >น้ำหนัก</th>
|
||||
<td mat-cell *matCellDef="let item" class="">{{item.productWeight }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productColor">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Color</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productColor }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productYear">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Year</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productYear }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="userFullName">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">ชื่อคนขาย</th>
|
||||
<td mat-cell *matCellDef="let item" style="min-width: 200px;" >{{item.userFullName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="price">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>จำนวนเงิน</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-green"> {{item.price | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="deposit">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>จำนวนมัดจำ</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-orange"> {{item.deposit | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="wantToInstallmentTerm">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ระยะเวลาผ่อน</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.wantToInstallmentTerm }} งวด</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="createdDate">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">วันที่บันทึก</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.createdDate | date : 'dd/MM/YYYY'}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="contractApprovedDate">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">วันที่อนุมัติ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.contractApprovedDate | date : 'dd/MM/YYYY'}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="contractCancelDate">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">วันที่ไม่อนุมัติ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.contractCancelDate | date : 'dd/MM/YYYY'}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">สถานะ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac" style="min-width: 100px;">
|
||||
<div *ngIf="item.status === 'paid' " class="status status-active">ชำระแล้ว</div>
|
||||
<div *ngIf="item.status === 'pending'" class="status status-disabled">รอชำระ</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ประเภทการชำระ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.type === 'deposit' " class="status-text status-deposit">ค่ามัดจำ</div>
|
||||
<div *ngIf="item.type === 'installment'" class="status-text status-installment">ผ่อนสินค้า</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="paymentType">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ประเภทการชำระ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.paymentType === 'deposit' " class="status-text status-deposit">ค่ามัดจำ</div>
|
||||
<div *ngIf="item.paymentType === 'installment'" class="status-text status-installment">ผ่อนสินค้า</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="paymentMethod">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>วิธีชำระ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.paymentMethod === 'transfer' " class="status-text status-transfer">โอนเงิน</div>
|
||||
<div *ngIf="item.paymentMethod === 'cash'" class="status-text status-cash">เงินสด</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="paymentAmountAll">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>จำนวนเงิน</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div class="b-color-green">{{item.paymentAmountAll | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="contractBy">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">พนักงานทำรายการ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item?.userContractBy?.name}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="contractApprovedBy">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">ผู้อนุมัติ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item?.userApprovedBy?.name }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="contractCancelBy">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">ผู้ไม่อนุมัติ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item?.userCancelBy?.name }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="action">
|
||||
<th mat-header-cell *matHeaderCellDef width="80">Action</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="action flex justify-center">
|
||||
<div class="item" *ngIf="item.statusContract === 'pending' " >
|
||||
<i class="bi bi-pencil-square icon-edit" (click)="onAction('do', item.id)"></i>
|
||||
</div>
|
||||
<div class="item" *ngIf="['approved', 'cancel'].includes(item.statusContract) ">
|
||||
<i class="bi bi-eye color-green" (click)="onAction('do', item.id)"></i>
|
||||
</div>
|
||||
<div class="item" *ngIf="['approved', 'cancel'].includes(item.statusContract) ">
|
||||
<i class="bi bi-filetype-pdf color-main" (click)="onAction('pdf', item.id)"></i>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
</table>
|
||||
<div *ngIf="dataSource?.length === 0" class="no-data"></div>
|
||||
</div>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" showFirstLastButtons (page)="getData($event)"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,125 @@
|
||||
import { ChangeDetectorRef, Component, OnInit } from "@angular/core";
|
||||
import { BaseListComponent } from "../../../../@common/base/base-list.component";
|
||||
import { debounceTime, distinctUntilChanged, lastValueFrom, Subject } from "rxjs";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { API, EAction, EStatusContract, EStatusQuotation, EText } from "../../../../@config/app";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import generateParamsValue from "../../../../@common/utils/GenerateParamsValue";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-3rd-time-index",
|
||||
templateUrl: "./contract-approved-index.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class ContractApprovedIndexComponent extends BaseListComponent implements OnInit {
|
||||
|
||||
pageTitle = "สัญญา";
|
||||
action = "pending";
|
||||
apiUrl: string = API.quotation;
|
||||
api: any = API;
|
||||
|
||||
displayedColumns: string[] = [];
|
||||
masterProductCategory: any = [];
|
||||
masterProductBrand: any = [];
|
||||
filterKeyword: Subject<string> = new Subject<string>();
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
public appService: AppService,
|
||||
public activatedRoute: ActivatedRoute,
|
||||
public changeDetectorRef: ChangeDetectorRef
|
||||
) {
|
||||
super();
|
||||
|
||||
this.filterKeyword.pipe(debounceTime(1000), distinctUntilChanged()).subscribe(model => {
|
||||
this.getData();
|
||||
});
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.activatedRoute.params.subscribe(async params => {
|
||||
this.action = params["action"];
|
||||
if (!this.action) this.router.navigate(["/pages/contract/approved/list", EStatusQuotation.PENDING]);
|
||||
await this.getData();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async onTabs(action?: any) {
|
||||
this.dataFilter = {};
|
||||
return this.router.navigate(["/pages/contract/approved/list", action]);
|
||||
}
|
||||
|
||||
onAction(action : any, id?: any) {
|
||||
if (action === 'do') return this.router.navigate([`/pages/contract/approved/do/${this.action}`, id]);
|
||||
if (action === 'pdf') return this.router.navigate([`/pages/contract/approved/pdf/${this.action}`, id]);
|
||||
return;
|
||||
}
|
||||
|
||||
async getData($event?: any) {
|
||||
try {
|
||||
this.dataSource = [];
|
||||
this.dataFilter.step = 5;
|
||||
this.dataFilter.statusContract = this.action;
|
||||
|
||||
let url = API.quotation;
|
||||
if (this.action === EStatusContract.PENDING) {
|
||||
url = API.quotation;
|
||||
this.displayedColumns = ["action", "price", "wantToInstallmentTerm", "customerFirstName", "productNo", "productName", "productBrandName", "productSize", "productWeight", "productColor","contractBy", "createdDate"];
|
||||
}
|
||||
if (this.action === EStatusContract.APPROVED) {
|
||||
url = API.quotation;
|
||||
this.displayedColumns = ["action", "price", "wantToInstallmentTerm", "customerFirstName", "productNo", "productName", "productBrandName", "productSize", "productWeight", "productColor","contractBy", "contractApprovedBy", "contractApprovedDate"];
|
||||
}
|
||||
if (this.action === EStatusContract.CANCEL) {
|
||||
url = API.quotation;
|
||||
this.displayedColumns = ["action", "price", "wantToInstallmentTerm", "customerFirstName", "productNo", "productName", "productBrandName", "productSize", "productWeight", "productColor","contractBy", "contractCancelBy", "contractCancelDate"];
|
||||
}
|
||||
this.dataFilter.keywordColumn = "quotationNo,productNo,customerFirstName,customerLastName,price,productName";
|
||||
const dataSource = await lastValueFrom(this.appService.get(this.setParams(url, $event)));
|
||||
this.dataSource = this.setDataSource<any>(dataSource);
|
||||
} catch (e) {
|
||||
this.dataSource = [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onFilter($event?: any) {
|
||||
this.filterKeyword.next($event);
|
||||
}
|
||||
|
||||
clearDate($event?: any) {
|
||||
$event.stopPropagation();
|
||||
this.dataFilter.createdDate = null;
|
||||
}
|
||||
|
||||
async onSort($event: any) {
|
||||
this.dataFilter.orderBy = $event.active;
|
||||
this.dataFilter.sort = $event.direction;
|
||||
await this.getData();
|
||||
console.log($event);
|
||||
}
|
||||
|
||||
|
||||
async onDelete(ids: any) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.DELETE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
try {
|
||||
await lastValueFrom(this.appService.delete(this.apiUrl, ids));
|
||||
await this.appService.message(EAction.SUCCESS, EText.DELETE);
|
||||
await this.getData(this.getCurrentPage());
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
onExport() {
|
||||
const filter = generateParamsValue(this.dataFilter);
|
||||
const url = `${API.quotation}/export-contract-approved?${filter ? '&' + filter : '' }`;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<mat-progress-bar *ngIf="!pdfView" mode="indeterminate"></mat-progress-bar>
|
||||
<iframe *ngIf="pdfView" [src]="pdfView"></iframe>
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
import { ChangeDetectorRef, Component, OnInit } from "@angular/core";
|
||||
import { BaseListComponent } from "../../../../@common/base/base-list.component";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { API, STORAGE } from "../../../../@config/app";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { DomSanitizer } from "@angular/platform-browser";
|
||||
import { BaseFormComponent } from "../../../../@common/base/base-form.component";
|
||||
import { IQuotation } from "../../../../@common/interface/Quotation";
|
||||
import { format, parseISO } from "date-fns";
|
||||
|
||||
@Component({
|
||||
selector: "app-contract-make-pdf-index",
|
||||
templateUrl: "./contract-approved-pdf.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class ContractApprovedPdfComponent extends BaseFormComponent implements OnInit {
|
||||
|
||||
pageTitle = "สัญญา";
|
||||
apiUrl: string = API.quotation;
|
||||
api: any = API;
|
||||
dataView: any;
|
||||
pdfView: any;
|
||||
|
||||
|
||||
constructor(
|
||||
public activatedRoute: ActivatedRoute,
|
||||
public router: Router,
|
||||
public changeDetectorRef: ChangeDetectorRef,
|
||||
public appService: AppService,
|
||||
private sanitizer: DomSanitizer
|
||||
) {
|
||||
super();
|
||||
|
||||
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.activatedRoute.params.subscribe(async params => {
|
||||
this.ids = params["id"];
|
||||
await this.getData();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async getData() {
|
||||
try {
|
||||
const quotation : IQuotation = await lastValueFrom(this.appService.get(`${this.api.quotation}/getById/${this.ids}`));
|
||||
const startDate = quotation.startDate ? format(parseISO(quotation.startDate), "dd/MM/yyyy") : null;
|
||||
const customerPrefix = quotation.customerPrefix ? quotation.customerPrefix : '';
|
||||
const customerName = quotation.customerId ? `${quotation.customer?.prefix} ${quotation.customer?.firstName} ${quotation.customer?.lastName}` :
|
||||
`${customerPrefix} ${quotation.customerFirstName} ${quotation.customerLastName}`;
|
||||
const data = {
|
||||
doc_no: quotation.quotationNo,
|
||||
product_code: quotation.productNo,
|
||||
customer_name: customerName,
|
||||
first_name: quotation.customerFirstName,
|
||||
last_name: quotation.customerLastName,
|
||||
start_date: startDate,
|
||||
phone_no: quotation.customerPhone,
|
||||
|
||||
picture: `${STORAGE.products}/${quotation.coverImage}`,
|
||||
price: Number(quotation.price),
|
||||
deposit: Number(quotation.deposit),
|
||||
seller_deposit: Number(quotation.sellerDeposit),
|
||||
cmfs_deposit: Number(quotation.cmfsDeposit),
|
||||
total_balance: Number(quotation.principalBalanceTotal),
|
||||
installment: Number(quotation.wantToInstallmentTerm),
|
||||
packing: Number(quotation.plusPacking),
|
||||
luxury_handbag_authentication: Number(quotation.plusLuxuryHandbag),
|
||||
bankfee_insurance_storage: Number(quotation.plusBankFee),
|
||||
transfer_amount: Number(quotation.transferSummary),
|
||||
deduct_seller_deposit: Number(quotation.sellerDepositSum),
|
||||
authenticity_verification: 0,
|
||||
|
||||
|
||||
|
||||
data: [],
|
||||
total1: 0,
|
||||
total2: 0,
|
||||
total3: 0,
|
||||
total4: 0
|
||||
}
|
||||
const quotationDetail: any = [];
|
||||
quotation.quotationDetail?.map(item => {
|
||||
const dueDate = item.dueDate ? format(parseISO(item.dueDate), "dd/MM/yyyy") : null;
|
||||
const map = {
|
||||
due_date: dueDate,
|
||||
principle: Number(item.principle),
|
||||
interest_total: Number(item.interestTotal),
|
||||
bank_fee: Number(item.fee),
|
||||
total_payment: Number(item.totalPayment),
|
||||
principle_total: Number(item.principleTotal)
|
||||
}
|
||||
quotationDetail.push(map);
|
||||
})
|
||||
|
||||
data.data = quotationDetail;
|
||||
|
||||
const pdf = await lastValueFrom(this.appService.post(`${this.api.installmentContractReport}/pdf`, data, { responseType: "arraybuffer" }));
|
||||
const url = URL.createObjectURL(new Blob([pdf], { type: "application/pdf" }));
|
||||
this.pdfView = this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
||||
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
28
src/app/pages/contract/make/contract-make-routing.module.ts
Normal file
28
src/app/pages/contract/make/contract-make-routing.module.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
import { ContractMakeIndexComponent } from "./index/contract-make-index.component";
|
||||
import { ContractMakeDoComponent } from "./do/contract-make-do.component";
|
||||
import { ContractMakePdfComponent } from "./pdf/contract-make-pdf.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: "", component: ContractMakeIndexComponent },
|
||||
{ path: "list", component: ContractMakeIndexComponent },
|
||||
{ path: "list/:action", component: ContractMakeIndexComponent },
|
||||
{ path: "do/:action", component: ContractMakeDoComponent },
|
||||
{ path: "do/:action/:id", component: ContractMakeDoComponent },
|
||||
{ path: "pdf/:action/:id", component: ContractMakePdfComponent }
|
||||
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class RoutingModule {
|
||||
}
|
||||
|
||||
export const RoutingComponents = [
|
||||
ContractMakeIndexComponent,
|
||||
ContractMakeDoComponent,
|
||||
ContractMakePdfComponent
|
||||
];
|
||||
16
src/app/pages/contract/make/contract-make.module.ts
Normal file
16
src/app/pages/contract/make/contract-make.module.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import {RoutingComponents, RoutingModule} from './contract-make-routing.module';
|
||||
import {AppSharedModule} from "../../../app.shared";
|
||||
import { NgOptimizedImage } from "@angular/common";
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
...RoutingComponents,
|
||||
],
|
||||
imports: [
|
||||
AppSharedModule,
|
||||
RoutingModule,
|
||||
NgOptimizedImage
|
||||
]
|
||||
})
|
||||
export class ContractMakeModule {}
|
||||
867
src/app/pages/contract/make/do/contract-make-do.component.html
Normal file
867
src/app/pages/contract/make/do/contract-make-do.component.html
Normal file
@@ -0,0 +1,867 @@
|
||||
<ul class="progressbar">
|
||||
<li [ngClass]="{ 'active' : isTabs === 1}" (click)="isTabs = 1">รายละเอียดหลัก</li>
|
||||
<li [ngClass]="{ 'active' : isTabs === 2}" (click)="isTabs = 2">การจัดผ่อน</li>
|
||||
<li [ngClass]="{ 'active' : isTabs === 3}" (click)="isTabs = 3">ข้อมูลรับชำระเงิน</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<form class="main-form" #ngf="ngForm" (ngSubmit)="onSubmit(ngf)">
|
||||
|
||||
<ng-container *ngIf="isTabs === 1">
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> สัญญาเงินกู้ระหว่าง CM-FS. Co., Ltd. ("บริษัทฯ") กับ</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 mt-4 mb-4">
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เลขที่สัญญา/BOM</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="productNo" #productNo="ngModel" [(ngModel)]="dataForm.productNo" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<!-- <div class="col-span-4 md:col-span-12 ">-->
|
||||
<!-- <mat-label>ชื่อลูกค้า</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <div class="flex">-->
|
||||
<!-- <input style="width: 75px; padding-right: 0 !important;" matInput name="customerPrefix" #customerPrefix="ngModel" [(ngModel)]="dataForm.customer.prefix" disabled>-->
|
||||
<!-- <input style="padding-left: 0 !important;" matInput name="customerFirstName" #customerFirstName="ngModel" [(ngModel)]="dataForm.customer.firstName" disabled>-->
|
||||
<!-- </div>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-span-4 md:col-span-12 ">-->
|
||||
<!-- <mat-label>นามสกุล</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <input matInput name="customerLastName" #customerLastName="ngModel" [(ngModel)]="dataForm.customer.lastName" disabled>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-span-4 md:col-span-12 ">-->
|
||||
<!-- <mat-label>เบอร์โทร</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <input matInput name="customerPhone" #customerPhone="ngModel" [(ngModel)]="dataForm.customer.phone" disabled>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- <div class="col-span-4 md:col-span-12 ">-->
|
||||
<!-- <mat-label>เลขบัตรประชาชน</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <input matInput name="customerIdCard" #customerIdCard="ngModel" [(ngModel)]="dataForm.customer.idCard" disabled>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>วันที่ทำสัญญา</mat-label>
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
name="contractDate"
|
||||
#contractDate="ngModel"
|
||||
(click)="dpkName.open()"
|
||||
[(ngModel)]="dataForm.contractDate"
|
||||
[matDatepicker]="dpkName"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
<mat-datepicker-toggle [for]="dpkName" matSuffix></mat-datepicker-toggle>
|
||||
<mat-datepicker #dpkName></mat-datepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:hidden"></div>
|
||||
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>คำนำหน้า</mat-label>
|
||||
<ng-select placeholder="เลือกคำนำหน้า" name="prefix" #prefix="ngModel" [(ngModel)]="dataForm.customer.prefix" appendTo="body" disabled>
|
||||
<ng-option *ngFor="let item of prefixData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ชื่อลูกค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="firstName" #firstName="ngModel" [(ngModel)]="dataForm.customer.firstName" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>นามสกุล</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="lastName" #lastName="ngModel" [(ngModel)]="dataForm.customer.lastName" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>เพศ</mat-label>
|
||||
<ng-select placeholder="" name="gender" #gender="ngModel" [(ngModel)]="dataForm.customer.gender" appendTo="body" disabled>
|
||||
<ng-option *ngFor="let item of genderData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เบอร์โทร</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="phone" #phone="ngModel" [(ngModel)]="dataForm.customer.phone" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เลขบัตรประชาชน</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="idCard" #idCard="ngModel" [(ngModel)]="dataForm.customer.idCard" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-span-12 md:col-span-12 ">
|
||||
<mat-label>ที่อยู่ตามบัตรประชาชน</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="address" #address="ngModel" [(ngModel)]="dataForm.customer.address" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-12 md:col-span-12 ">
|
||||
<mat-label>ที่อยู่ในการจัดส่ง</mat-label>
|
||||
<label class="inline-flex items-center cursor-pointer select-none ml-2">
|
||||
<input type="checkbox" name="isAddress" [(ngModel)]="dataForm.customer.isAddress" disabled>
|
||||
<span style="padding-left: 2px;">ใช้ที่อยู่ตามบัตรประชาชน</span>
|
||||
</label>
|
||||
|
||||
<mat-form-field>
|
||||
<input matInput name="deliveryAddress" #deliveryAddress="ngModel" [(ngModel)]="dataForm.customer.deliveryAddress" [disabled]="dataForm.customer.isAddress" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>E-mail</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="email" #email="ngModel" [(ngModel)]="dataForm.customer.email" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-8 md:col-span-12 ">
|
||||
<mat-label>อาชีพ</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="occupation" #occupation="ngModel" [(ngModel)]="dataForm.customer.occupation" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ID Line</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="line" #line="ngModel" [(ngModel)]="dataForm.customer.line" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>Facebook</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="facebook" #facebook="ngModel" [(ngModel)]="dataForm.customer.facebook" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>IG</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="ig" #ig="ngModel" [(ngModel)]="dataForm.customer.ig" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> ข้อมูลร้านค้า</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 mt-4 mb-4">
|
||||
|
||||
|
||||
<!-- <div class="col-span-4 md:col-span-12 ">-->
|
||||
<!-- <mat-label>ชื่อคนขาย/ร้านค้า</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <input matInput name="sellerName" #sellerName="ngModel" [(ngModel)]="dataForm.seller.name" disabled>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>คำนำหน้า</mat-label>
|
||||
<ng-select placeholder="เลือกคำนำหน้า" name="sellerprefix" #sellerprefix="ngModel" [(ngModel)]="dataForm.seller.prefix" appendTo="body" disabled>
|
||||
<ng-option *ngFor="let item of prefixData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ชื่อลูกค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerfirstName" #sellerfirstName="ngModel" [(ngModel)]="dataForm.seller.firstName" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>นามสกุล</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerlastName" #sellerlastName="ngModel" [(ngModel)]="dataForm.seller.lastName" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-12 ">
|
||||
<mat-label>เพศ</mat-label>
|
||||
<ng-select placeholder="" name="sellergender" #sellergender="ngModel" [(ngModel)]="dataForm.seller.gender" appendTo="body" disabled>
|
||||
<ng-option *ngFor="let item of genderData" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เบอร์โทร</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerPhone" #sellerPhone="ngModel" [(ngModel)]="dataForm.seller.phone" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>Facebook</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerFacebook" #sellerFacebook="ngModel" [(ngModel)]="dataForm.seller.facebook" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ID Line</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerLine" #sellerLine="ngModel" [(ngModel)]="dataForm.seller.line" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ID LINE ร้านค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerLineShop" #sellerLineShop="ngModel" [(ngModel)]="dataForm.seller.lineShop" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>IG</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerIg" #sellerIg="ngModel" [(ngModel)]="dataForm.seller.ig" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>S/N สินค้า</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="sellerSnProduct" #sellerSnProduct="ngModel" [(ngModel)]="dataForm.seller.snProduct" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>แหล่งที่มา</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="source" #source="ngModel" [(ngModel)]="dataForm.source" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<!-- <div class="col-span-4 md:col-span-12 ">-->
|
||||
<!-- <mat-label>ค่าขนส่ง</mat-label>-->
|
||||
<!-- <mat-form-field>-->
|
||||
<!-- <input matInput name="shippingCost" #shippingCost="ngModel" [(ngModel)]="dataForm.shippingCost" disabled>-->
|
||||
<!-- </mat-form-field>-->
|
||||
<!-- </div>-->
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-table card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> ข้อมูลสินค้า</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 mb-2">
|
||||
<div class="col-span-3 md:col-span-12 ">
|
||||
<mat-label>Condition</mat-label>
|
||||
<ng-select placeholder="Condition" name="condition" #condition="ngModel" [(ngModel)]="dataForm.productCondition" >
|
||||
<ng-option *ngFor="let item of conditions" [value]="item">{{item}}</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
|
||||
<div class="col-span-3 md:col-span-12 ">
|
||||
<mat-label>Year</mat-label>
|
||||
<mat-form-field>
|
||||
<input appNumberOnly matInput name="year" #year="ngModel" [(ngModel)]="dataForm.productYear" >
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-wrap">
|
||||
<table class="tables ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>BOM</th>
|
||||
<th>Model</th>
|
||||
<th>Brand</th>
|
||||
<th>Main</th>
|
||||
<th>น้ำหนัก</th>
|
||||
<th>Color</th>
|
||||
<th>Year</th>
|
||||
<th>ราคาสินค้า</th>
|
||||
<th>จำนวนเงินมัดจำ</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="text-center">{{dataForm.productNo}}</td>
|
||||
<td class="text-center">{{dataForm.productName }}</td>
|
||||
<td class="text-center">{{dataForm.productBrandName}}</td>
|
||||
<td class="text-center">{{dataForm.productSize }}</td>
|
||||
<td class="text-center">{{dataForm.productWeight }}</td>
|
||||
<td class="text-center">{{dataForm.productColor }}</td>
|
||||
<td class="text-center">{{dataForm.productYear }}</td>
|
||||
<td class="text-center">{{dataForm.price | number : '1.2-2'}}</td>
|
||||
<td class="text-center">
|
||||
<div class="b-color-orange">{{dataForm.deposit | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title flex items-center">
|
||||
<div class="">รูปสินค้าจากลูกค้า</div>
|
||||
|
||||
<div class="ml-4">
|
||||
<input hidden type="file" accept="image/*" #productImages (change)="onAttachments($event, 'products')" />
|
||||
<button type="button" class="btn btn-sm btn-success-o" (click)="productImages.click()">เพิ่มรูปภาพสินค้า</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="list-images">
|
||||
<div class=" grid grid-cols-12 gap-2 md:gap-2 items-center">
|
||||
<ng-container *ngFor="let item of attachments; let i = index">
|
||||
<div class="col-span-2 md:col-span-4">
|
||||
<div class="flex justify-center items-center list-images-item">
|
||||
<div class="list-images-action">
|
||||
<i *ngIf="dataForm.coverImage !== item" (click)="dataForm.coverImage = item"
|
||||
matTooltip="ใช้ทำเอกสาร" class="bi bi-star color-main cursor-pointer select-none"></i>
|
||||
<i *ngIf="dataForm.coverImage === item" class="bi bi bi-star-fill color-main cursor-pointer select-none"></i>
|
||||
<i (click)="onRemoveAttachments(i, item)" class="bi bi-x-circle color-red cursor-pointer select-none"></i>
|
||||
</div>
|
||||
<img src="{{storage.products}}/{{item}}" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title flex items-center">
|
||||
<div class="">อุปกรณ์</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<ng-container *ngFor="let item of equipment; let i = index">
|
||||
<div class="form-list">
|
||||
<div class="form-list-item grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-9 md:col-span-8 " >{{item}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="equipment.includes('อื่นๆ')">
|
||||
<ng-container *ngFor="let item of equipmentOther; let i = index">
|
||||
<div class="form-list">
|
||||
<div class="form-list-item grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-9 md:col-span-8 " >{{item}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<div style="height: 20px;"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="isTabs === 2">
|
||||
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 ">
|
||||
<div class="col-span-6 md:col-span-12">
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> ข้อมูลการจัดผ่อน</div>
|
||||
</div>
|
||||
<div class="card-body form-input-list">
|
||||
<div style="height: 20px;"></div>
|
||||
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> วันที่เริ่มจัดผ่อน</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
name="startDate"
|
||||
#startDate="ngModel"
|
||||
(click)="dpkName.open()"
|
||||
[(ngModel)]="dataForm.startDate"
|
||||
[matDatepicker]="dpkName"
|
||||
readonly
|
||||
disabled
|
||||
/>
|
||||
<mat-datepicker-toggle [for]="dpkName" matSuffix></mat-datepicker-toggle>
|
||||
<mat-datepicker #dpkName></mat-datepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> ราคา (Price)</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="price" #price="ngModel" [(ngModel)]="dataForm.price" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> มัดจำแม่ค้า</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="sellerDeposit" #sellerDeposit="ngModel" [(ngModel)]="dataForm.sellerDeposit" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> มัดจำ CMFS</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="deposit" #deposit="ngModel" [(ngModel)]="dataForm.deposit" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> เงินต้นคงเหลือ (Total)</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="principalBalanceTotal" #principalBalanceTotal="ngModel" [(ngModel)]="dataForm.principalBalanceTotal" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> ต้องการผ่อน (Term)</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput type="number" name="wantToInstallmentTerm" #wantToInstallmentTerm="ngModel" [(ngModel)]="dataForm.wantToInstallmentTerm" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">งวด</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 20px;"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-6 md:col-span-12">
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> รายละเอียดค่าใช้จ่ายในการโอนเงิน</div>
|
||||
</div>
|
||||
<div class="card-body form-input-list">
|
||||
<div style="height: 20px;"></div>
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> มัดจำ CMFS Deposit</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="cmfsDeposit" #cmfsDeposit="ngModel" [(ngModel)]="dataForm.cmfsDeposit" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> หัก เงินมัดจำแม่ค้า </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="lessSellerDeposit" #lessSellerDeposit="ngModel" [(ngModel)]="dataForm.lessSellerDeposit" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> บวก Packing </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="plusPacking" #plusPacking="ngModel" [(ngModel)]="dataForm.plusPacking" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> บวก Luxury handbag </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="plusLuxuryHandbag" #plusLuxuryHandbag="ngModel" [(ngModel)]="dataForm.plusLuxuryHandbag" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> บวก Bank fee, Insurance , Storage</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="plusBankFee" #plusBankFee="ngModel" [(ngModel)]="dataForm.plusBankFee" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> ส่วนลด </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="discount" #discount="ngModel" [(ngModel)]="dataForm.discount" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> สรุปยอดโอน </label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="transferSummary" #transferSummary="ngModel" [(ngModel)]="dataForm.transferSummary" disabled>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="height: 10px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="card card-table mb-6">
|
||||
<div class="card-body">
|
||||
<div class="table-wrap" *ngIf="dataForm.quotationDetail?.[0]">
|
||||
<table class="tables">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>งวดที่</th>
|
||||
<th>กำหนดจ่ายวันที่ <br>Due date</th>
|
||||
<th>วันที่จ่าย <br>Payment date</th>
|
||||
<th>เงินต้น <br>Principle</th>
|
||||
<th>ดอกเบี้ย(บาท) <br>Interest Total</th>
|
||||
<th>Bank fee, <br>Insurance ,Storage</th>
|
||||
<th>ค่าชำระล่าช้า</th>
|
||||
<th>รวมยอดจ่ายต่อเดือน <br>Total payment</th>
|
||||
<th>เงินต้นคงเหลือ <br>Principle Total</th>
|
||||
<th>ชำระเงิน</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<ng-container *ngFor="let item of dataForm.quotationDetail; let i = index">
|
||||
<tr>
|
||||
<td class="text-center">{{item.installment }}</td>
|
||||
<td class="text-center">{{item.dueDate | date : 'dd/MM/YYYY'}}</td>
|
||||
<td class="text-center"><span *ngIf="item.status === 'paid'"> {{item.paymentDate | date : 'dd/MM/YYYY'}}</span></td>
|
||||
<td class="text-center">{{item.principle | number : '1.0-0'}}</td>
|
||||
<td class="text-center">{{item.interestTotal | number : '1.0-0'}}</td>
|
||||
<td class="text-center">{{item.fee | number : '1.0-0'}}</td>
|
||||
<td class="text-center">
|
||||
<div class="b-color-red" *ngIf="item.interestLateTotal">
|
||||
{{item.interestLateTotal | number : '1.2-2'}}
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="b-color-green">
|
||||
<ng-container *ngIf="item.totalPaymentAll"> {{ item.totalPaymentAll | number : '1.0-0'}}</ng-container>
|
||||
<ng-container *ngIf="!item.totalPaymentAll"> {{ item.totalPayment | number : '1.0-0'}}</ng-container>
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-center"><span class="b-color-orange" *ngIf="item.principleTotal">{{item.principleTotal | number : '1.0-0'}}</span></td>
|
||||
<td class="text-center">
|
||||
<span *ngIf="item.status === 'paid'"> <i class="i bi-check-circle-fill color-green"></i></span>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
<tr>
|
||||
<td colspan="3" class="text-right"><b>รวม</b></td>
|
||||
<td class="text-center">{{dataForm.principleSum | number : '1.0-0'}}</td>
|
||||
<td class="text-center">{{dataForm.interestTotalSum | number : '1.0-0'}}</td>
|
||||
<td class="text-center">{{dataForm.feeSum | number : '1.0-0'}}</td>
|
||||
<td class="text-center">{{dataForm.interestLateTotalSum | number : '1.0-0'}}</td>
|
||||
<td class="text-center"><span class="b-color-green">{{dataForm.totalPaymentSum | number : '1.0-0'}}</span></td>
|
||||
<td class="text-center"></td>
|
||||
<td class="text-center"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-table mb-6" *ngIf="quotationPayment?.[0]">
|
||||
<div class="card-header"><b>ชำระเงินเพิ่มเติม</b></div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="table-wrap">
|
||||
<table class="tables">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="60"></th>
|
||||
<th width="150">วันที่จ่าย</th>
|
||||
<th width="">วิธีชำระ</th>
|
||||
<th>จำนวนเงิน</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<ng-container *ngFor="let item of quotationPayment; let i = index">
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<div class="item" *ngIf="item.status === 'paid' && item.paymentImages ">
|
||||
<i class="bi bi-file-image-fill color-main" (click)="onAttachmentsView(item.paymentImages)"></i>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">{{item.paymentDate | date : 'dd/MM/YYYY'}}</td>
|
||||
<td class="text-center">
|
||||
<div *ngIf="item.paymentMethod === 'transfer' " class="status-text status-transfer">โอนเงิน</div>
|
||||
<div *ngIf="item.paymentMethod === 'cash'" class="status-text status-cash">เงินสด</div>
|
||||
</td>
|
||||
<td class="text-center"><span class="b-color-green">{{item.paymentAmountAll | number : '1.0-0'}}</span></td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
<tr>
|
||||
<td colspan="3" class="text-right"><b>รวม</b></td>
|
||||
<td class="text-center"><span class="b-color-green">{{dataForm.quotationPaymentSum | number : '1.0-0'}}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" class="text-right"><b>ยอดคงเหลือ</b></td>
|
||||
<td class="text-center"><span class="b-color-green">{{dataForm.contractPriceSum | number : '1.0-0'}}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card card-table " *ngIf="dataForm.statusPayment === 'paid'">
|
||||
<div class="card-body">
|
||||
<div class="no-data color-green font-bold"> ปิดยอดแล้ว</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="dataForm.statusPayment !== 'paid' ">
|
||||
|
||||
<div class="mt-4 mb-4">
|
||||
<label class="inline-flex items-center cursor-pointer select-none ">
|
||||
<input type="checkbox" name="isContractClosing" [(ngModel)]="dataForm.isContractClosing">
|
||||
<span style="padding-left: 2px;">ปิดยอด</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6" *ngIf="dataForm.isContractClosing">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> ปิดยอดการผ่อนชำระ</div>
|
||||
</div>
|
||||
<div class="card-body form-input-list">
|
||||
<div style="height: 20px;"></div>
|
||||
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> วันที่ปิดยอด</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
name="contractClosingDate"
|
||||
#contractClosingDate="ngModel"
|
||||
(click)="dpkClosingDate.open()"
|
||||
[(ngModel)]="dataForm.contractClosingDate"
|
||||
[matDatepicker]="dpkClosingDate"
|
||||
readonly
|
||||
|
||||
/>
|
||||
<mat-datepicker-toggle [for]="dpkClosingDate" matSuffix></mat-datepicker-toggle>
|
||||
<mat-datepicker #dpkClosingDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> เงินต้นคงเหลือ (Total)</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="contractPrice" #contractPrice="ngModel" [(ngModel)]="dataForm.contractPrice">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> ดอกเบี้ย</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="contractInterest" #contractInterest="ngModel" [(ngModel)]="dataForm.contractInterest">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-4 md:col-span-12 text-right md:text-left">
|
||||
<label> สรุปยอดที่ต้องชำระ</label>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<mat-form-field>
|
||||
<input matInput appCurrencyInputMask name="contractPriceSum" #contractPriceSum="ngModel" [(ngModel)]="dataForm.contractPriceSum">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12">
|
||||
<div class="unit">บาท (THB)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="height: 20px;"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="isTabs === 3">
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> ข้อมูลธนาคารที่รับชำระเงิน</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 mt-4 mb-4">
|
||||
<div class="col-span-8 md:col-span-12 ">
|
||||
<mat-label>ชื่อธนาคาร</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="productNo" #productNo="ngModel" [(ngModel)]="dataForm.contractBankName" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:hidden"></div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>ชื่อบัญชี</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="contractAccountName" #contractAccountName="ngModel" [(ngModel)]="dataForm.contractAccountName" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-4 md:col-span-12 ">
|
||||
<mat-label>เลขที่บัญชี</mat-label>
|
||||
<mat-form-field>
|
||||
<input matInput name="contractAccountNumber" #contractAccountNumber="ngModel" [(ngModel)]="dataForm.contractAccountNumber" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-form-panel card-form-panel-blue mb-6">
|
||||
<div class="card-header ">
|
||||
<div class="card-title"> รายละเอียดท้ายสัญญา</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-12 gap-4 md:gap-2 mt-4 mb-4">
|
||||
<div class="col-span-12 md:col-span-12 ">
|
||||
<mat-form-field>
|
||||
<textarea matInput [(ngModel)]="dataForm.contractDetail" name="contractDetail" #contractDetail="ngModel" placeholder="" required></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ng-container>
|
||||
|
||||
<div class="main-form-action text-right">
|
||||
<button type="submit" class="btn btn-submit">บันทึก</button>
|
||||
<button type="button" class="btn btn-back" (click)="onAction('back')">ยกเลิก</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
222
src/app/pages/contract/make/do/contract-make-do.component.ts
Normal file
222
src/app/pages/contract/make/do/contract-make-do.component.ts
Normal file
@@ -0,0 +1,222 @@
|
||||
import { ChangeDetectorRef, Component, OnInit } from "@angular/core";
|
||||
import {API, CONDITIONS, EAction, EText, GENDER, PREFIX, STORAGE} from "../../../../@config/app";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { BaseFormComponent } from "../../../../@common/base/base-form.component";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { IProduct } from "../../../../app.interface";
|
||||
import {orderByArray, sortByProperty} from "../../../../@common/utils/OrderBy";
|
||||
import deepCopy from "../../../../@common/utils/DeepCopy";
|
||||
import {AttachmentsViewComponent} from "../../../@popup/attachments-view/attachments-view.component";
|
||||
import {MatDialog} from "@angular/material/dialog";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-contract-make-do",
|
||||
templateUrl: "./contract-make-do.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class ContractMakeDoComponent extends BaseFormComponent implements OnInit {
|
||||
|
||||
override dataForm: any = {};
|
||||
dataView: IProduct = {};
|
||||
auth: any = {};
|
||||
title = "";
|
||||
api: any = API;
|
||||
storage: any = STORAGE;
|
||||
attachments: any = [];
|
||||
equipment: any = [];
|
||||
equipmentOther: any = [];
|
||||
settings: any = [];
|
||||
masterProductUnit: any = [];
|
||||
quotationPayment: any = [];
|
||||
deviation: any = 0;
|
||||
isTabs: any = 1;
|
||||
prefixData = PREFIX;
|
||||
genderData = GENDER;
|
||||
conditions = CONDITIONS;
|
||||
|
||||
constructor(
|
||||
public activatedRoute: ActivatedRoute,
|
||||
public router: Router,
|
||||
public changeDetectorRef: ChangeDetectorRef,
|
||||
private attachmentsView: MatDialog,
|
||||
public appService: AppService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.activatedRoute.params.subscribe(async params => {
|
||||
this.ids = params["id"];
|
||||
this.action = params["action"];
|
||||
this.auth = this.appService.auth();
|
||||
this.dataForm.customer = {};
|
||||
this.dataForm.seller = {};
|
||||
if (this.ids) await this.getData();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
async onAction(action: string) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.BACK));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
if (action === "back") return this.router.navigate(["/pages/contract/make/list", this.action]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
async getData() {
|
||||
if (!this.ids) this.appService.message(EAction.INFO, EText.NO_DATA);
|
||||
try {
|
||||
this.dataForm = await lastValueFrom(this.appService.get(`${this.api.quotation}/getById/${this.ids}`));
|
||||
this.attachments = this.dataForm.images ? this.dataForm.images?.split(",") : [];
|
||||
this.equipment = this.dataForm.equipment ? this.dataForm.equipment?.split(",") : [];
|
||||
this.equipmentOther = this.dataForm.equipmentOther ? this.dataForm.equipmentOther?.split(",") : [];
|
||||
this.dataForm.deposit = Number(this.dataForm.deposit) + Number(this.dataForm.sellerDeposit2ndTime) + Number(this.dataForm.sellerDeposit3rdTime);
|
||||
this.dataForm.contractDate = new Date();
|
||||
|
||||
|
||||
if (!this.dataForm.customerId) {
|
||||
this.dataForm.customer = {};
|
||||
this.dataForm.customer.prefix = this.dataForm.customerPrefix;
|
||||
this.dataForm.customer.firstName = this.dataForm.customerFirstName;
|
||||
this.dataForm.customer.lastName = this.dataForm.customerLastName;
|
||||
this.dataForm.customer.phone = this.dataForm.customerPhone;
|
||||
}
|
||||
|
||||
sortByProperty(this.dataForm.quotationDetail, 'installment', 'ASC');
|
||||
|
||||
this.dataForm.principleSum = 0
|
||||
this.dataForm.interestTotalSum = 0
|
||||
this.dataForm.interestLateTotalSum = 0
|
||||
this.dataForm.feeSum = 0
|
||||
this.dataForm.totalPaymentSum = 0
|
||||
|
||||
this.dataForm.contractPrincipleSum = 0
|
||||
this.dataForm.contractInterestTotalSum = 0
|
||||
this.dataForm.contractFeeSum = 0
|
||||
this.dataForm.contractTotalPaymentSum = 0
|
||||
|
||||
this.dataForm.quotationDetail.map((item : any) => {
|
||||
this.dataForm.principleSum += Number(item.principle)
|
||||
this.dataForm.interestTotalSum += Number(item.interestTotal)
|
||||
this.dataForm.interestLateTotalSum += Number(item.interestLateTotal)
|
||||
this.dataForm.feeSum += Number(item.fee)
|
||||
this.dataForm.totalPaymentSum += item.totalPaymentAll ? Number(item.totalPaymentAll) : Number(item.totalPayment)
|
||||
if (item.status === 'pending') {
|
||||
this.dataForm.contractPrincipleSum += Number(item.principle)
|
||||
this.dataForm.contractInterestTotalSum += Number(item.interestTotal)
|
||||
this.dataForm.contractFeeSum += Number(item.fee)
|
||||
this.dataForm.contractTotalPaymentSum += item.totalPaymentAll ? Number(item.totalPaymentAll) : Number(item.totalPayment)
|
||||
}
|
||||
|
||||
})
|
||||
this.dataForm.principleSum = Math.round(this.dataForm.principleSum);
|
||||
this.dataForm.contractTotalPaymentSum = Math.round(this.dataForm.contractTotalPaymentSum);
|
||||
|
||||
|
||||
this.dataForm.contractClosingDate = new Date();
|
||||
this.dataForm.contractPrice = this.dataForm.contractPrincipleSum;
|
||||
this.dataForm.contractInterest = this.dataForm.contractInterestTotalSum;
|
||||
this.dataForm.contractPriceSum = this.dataForm.contractTotalPaymentSum + this.dataForm.contractInterestTotalSum;
|
||||
|
||||
this.dataForm.contractBankName = 'ธนาคารทหารไทยธนชาต จำกัด (มหาชน)';
|
||||
this.dataForm.contractAccountName = 'บริษัท ซีเอ็ม เอฟเอส จำกัด';
|
||||
this.dataForm.contractAccountNumber = '263-2-17778-4';
|
||||
this.dataForm.contractDetail = 'ชำระเงินงวดอย่างน้อย ทุกเดือนตามวันและยอดขั้นต่ำตามตาราง โดยที่ไม่เสียค่าปรับ ทั้งนี้หากเกินกำหนด ผู้กู้ต้องเสียค่าดอกเบี้ยผิดนัดเพิ่มเติมวันละ 1,000 บาท (ไม่รวมค่าทวงถาม) หากขาดส่งเกินกว่า 60 วัน นับแต่วันผ่อนล่าสุดจะถือว่าผิดสัญญา โดยหากผู้กู้ติดสัญญาไม่ว่ากรณีใดๆ ผู้กู้ยินดีที่จะนำสังหาริมทรัพย์ที่ผู้กู้นำเงินที่กู้ไปซื้อเป็นค่าตอบแทนในการชำระหนี้สินส่วนที่เหลือโดยทันที';
|
||||
|
||||
|
||||
this.quotationPayment = await lastValueFrom(this.appService.get(`${API.quotationPayment}?showAll=true&status=paid&paymentType=receive"ationId=${this.ids}`));
|
||||
|
||||
this.dataForm.quotationPaymentSum = 0;
|
||||
this.quotationPayment.map((item : any) => {
|
||||
this.dataForm.quotationPaymentSum += Number(item.paymentAmountAll)
|
||||
});
|
||||
|
||||
if (this.dataForm.quotationPaymentSum) {
|
||||
this.dataForm.contractPriceSum = this.dataForm.contractPriceSum - this.dataForm.quotationPaymentSum;
|
||||
}
|
||||
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async onSubmit(form: any) {
|
||||
if (!form.valid) return false;
|
||||
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.CREATE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
|
||||
this.dataForm.pageAction = 'contractMake';
|
||||
this.dataForm.images = this.attachments?.[0] ? this.attachments.join(",") : null;
|
||||
|
||||
|
||||
this.dataForm.contractBy = this.auth.id;
|
||||
this.dataForm.contractPrice = Number(this.dataForm.contractPrice);
|
||||
this.dataForm.contractInterest = Number(this.dataForm.contractInterest);
|
||||
this.dataForm.contractPriceSum = Number(this.dataForm.contractPriceSum);
|
||||
|
||||
return await this.onUpdate();
|
||||
|
||||
}
|
||||
|
||||
|
||||
async onUpdate() {
|
||||
try {
|
||||
await lastValueFrom(this.appService.post(`${this.api.quotation}/update/${this.ids}`, this.dataForm));
|
||||
await this.appService.message(EAction.SUCCESS, EText.UPDATE);
|
||||
await this.router.navigate(["/pages/contract/make/list", this.action]);
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async onAttachments($event: any, type: any) {
|
||||
const file = $event.target.files[0];
|
||||
if (!file) return;
|
||||
const formData = new FormData();
|
||||
formData.append("ref", type);
|
||||
formData.append("file", file);
|
||||
try {
|
||||
const res = await lastValueFrom(this.appService.post(`${this.api.attachments}/products`, formData));
|
||||
if (!this.attachments[0]) {
|
||||
this.dataForm.coverImage = res.fileName;
|
||||
}
|
||||
this.attachments.push(res.fileName);
|
||||
console.log(this.attachments, res);
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} catch (e) {
|
||||
this.appService.message(EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
async onRemoveAttachments(i: number, fileName: string) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.DELETE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
// await lastValueFrom(this.appService.delete(`${this.api.attachments}/deleteByName`, fileName));
|
||||
this.attachments?.splice(i, 1);
|
||||
if (!this.attachments[0]) {
|
||||
this.dataForm.coverImage = null;
|
||||
}
|
||||
this.changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
async onAttachmentsView(images : any) {
|
||||
const dialogConfig = deepCopy(this.dialogConfig);
|
||||
dialogConfig.data.action = EAction.POPUP;
|
||||
dialogConfig.data.title = 'ไฟล์แนบ';
|
||||
dialogConfig.data.type = 'images';
|
||||
dialogConfig.data.images = images;
|
||||
const dialogRef = this.attachmentsView.open(AttachmentsViewComponent, dialogConfig);
|
||||
const afterClosed = await lastValueFrom(dialogRef.afterClosed());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
<div class="card card-table">
|
||||
|
||||
<div class="card-filter text-right">
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 md:gap-2 items-center">
|
||||
<div class="col-span-5 md:col-span-12 md:order-2">
|
||||
<mat-form-field>
|
||||
<i matTextPrefix class="bi bi-search"></i>
|
||||
<input matInput name="keyword" #keyword="ngModel" [(ngModel)]="dataFilter.keyword" (ngModelChange)="onFilter($event)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-span-7 md:col-span-12 md:order-1">
|
||||
<button type="button" class="btn btn-export" (click)="onExport()">Export</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-filter-section grid grid-cols-12 gap-4 items-center md:gap-2 ">
|
||||
<div class="col-span-6 md:col-span-12">
|
||||
<div class="tabs-btn">
|
||||
<button type="button" class="btn" [ngClass]="{ 'active' : action === 'wait'}" (click)="onTabs('wait')">รอทำสัญญา</button>
|
||||
<button type="button" class="btn" [ngClass]="{ 'active' : action === 'pending'}" (click)="onTabs('pending')">รออนุมัติ</button>
|
||||
<button type="button" class="btn" [ngClass]="{ 'active' : action === 'approved'}" (click)="onTabs('approved')">สัญญา</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 md:col-span-12 ">
|
||||
<div class="flex w-full justify-end md:justify-start">
|
||||
<div class="">จำนวนทั้งหมด {{totalItem}} รายการ</div>
|
||||
<div class="pl-2 pr-2">|</div>
|
||||
<div class="">ค้นหาจำนวน {{totalOfElement}} รายการ</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-wrap">
|
||||
<table class="table table-main" mat-table [dataSource]="dataSource" matSort (matSortChange)="onSort($event)">
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
|
||||
<ng-container matColumnDef="quotationNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>เลขที่ใบเสนอราคา</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">{{item.quotationNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="customerFirstName">
|
||||
<th mat-header-cell *matHeaderCellDef class="" mat-sort-header>ชื่อลูกค้า</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">
|
||||
<ng-container *ngIf="item.customerId"> {{item.customer?.prefix}}{{item.customer?.firstName}} {{item.customer?.lastName}}</ng-container>
|
||||
<ng-container *ngIf="!item.customerId">{{item.customerFirstName}} {{item.customerLastName}}</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" mat-sort-header>BOM</th>
|
||||
<td mat-cell *matCellDef="let item" width="150" class="">{{item.productNo}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productName">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Model</th>
|
||||
<td mat-cell *matCellDef="let item" class="" style="min-width: 220px;">{{item.productName }}</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="productBrandName">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Brand</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productBrandName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productSize">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Main</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productSize }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productWeight">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" >น้ำหนัก</th>
|
||||
<td mat-cell *matCellDef="let item" class="">{{item.productWeight }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productColor">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Color</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productColor }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productYear">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">Year</th>
|
||||
<td mat-cell *matCellDef="let item" class="" >{{item.productYear }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="userFullName">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal">ชื่อคนขาย</th>
|
||||
<td mat-cell *matCellDef="let item" style="min-width: 200px;" >{{item.userFullName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="price">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>จำนวนเงิน</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-green"> {{item.price | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="deposit">
|
||||
<th mat-header-cell *matHeaderCellDef class="tal" width="150" mat-sort-header>จำนวนมัดจำ</th>
|
||||
<td mat-cell *matCellDef="let item" class="">
|
||||
<div class="b-color-orange"> {{item.deposit | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="wantToInstallmentTerm">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ระยะเวลาผ่อน</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.wantToInstallmentTerm }} งวด</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="createdDate">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">วันที่บันทึก</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.createdDate | date : 'dd/MM/YYYY'}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="contractApprovedDate">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">วันที่อนุมัติ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item.contractApprovedDate | date : 'dd/MM/YYYY'}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">สถานะ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac" style="min-width: 100px;">
|
||||
<div *ngIf="item.status === 'paid' " class="status status-active">ชำระแล้ว</div>
|
||||
<div *ngIf="item.status === 'pending'" class="status status-disabled">รอชำระ</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ประเภทการชำระ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.type === 'deposit' " class="status-text status-deposit">ค่ามัดจำ</div>
|
||||
<div *ngIf="item.type === 'installment'" class="status-text status-installment">ผ่อนสินค้า</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="paymentType">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>ประเภทการชำระ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.paymentType === 'deposit' " class="status-text status-deposit">ค่ามัดจำ</div>
|
||||
<div *ngIf="item.paymentType === 'installment'" class="status-text status-installment">ผ่อนสินค้า</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="paymentMethod">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>วิธีชำระ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div *ngIf="item.paymentMethod === 'transfer' " class="status-text status-transfer">โอนเงิน</div>
|
||||
<div *ngIf="item.paymentMethod === 'cash'" class="status-text status-cash">เงินสด</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="paymentAmountAll">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>จำนวนเงิน</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div class="b-color-green">{{item.paymentAmountAll | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="sellerDeposit3rdTime">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac" width="150" mat-sort-header>เงินมัดจำเพิ่ม</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">
|
||||
<div class="b-color-red" *ngIf="item.sellerDeposit3rdTime">{{item.sellerDeposit3rdTime | number : '1.2-2'}}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
|
||||
<ng-container matColumnDef="contractBy">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">พนักงานทำรายการ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item?.userContractBy?.name}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="contractApprovedBy">
|
||||
<th mat-header-cell *matHeaderCellDef class="tac">ผู้อนุมัติ</th>
|
||||
<td mat-cell *matCellDef="let item" class="tac">{{item?.userApprovedBy?.name }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="action">
|
||||
<th mat-header-cell *matHeaderCellDef width="80">Action</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="action flex justify-center">
|
||||
<div class="item" *ngIf="['wait', 'approved'].includes(item.statusContract)" >
|
||||
<i class="bi bi-pencil-square icon-edit" (click)="onAction('do', item.id)"></i>
|
||||
</div>
|
||||
<div class="item" *ngIf="['pending', 'approved'].includes(item.statusContract)">
|
||||
<i class="bi bi-filetype-pdf color-red" (click)="onAction('pdf', item.id)"></i>
|
||||
</div>
|
||||
<div class="item" *ngIf="['pending', 'approved'].includes(item.statusContract)">
|
||||
<i class="bi bi bi-arrow-clockwise color-green" (click)="onAction('refinance', item.id)"></i>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
</table>
|
||||
<div *ngIf="dataSource?.length === 0" class="no-data"></div>
|
||||
</div>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" showFirstLastButtons (page)="getData($event)"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,131 @@
|
||||
import { ChangeDetectorRef, Component, OnInit } from "@angular/core";
|
||||
import { BaseListComponent } from "../../../../@common/base/base-list.component";
|
||||
import { debounceTime, distinctUntilChanged, lastValueFrom, Subject } from "rxjs";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { AppService } from "../../../../app.service";
|
||||
import { API, EAction, EStatusContract, EStatusQuotation, EText } from "../../../../@config/app";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import generateParamsValue from "../../../../@common/utils/GenerateParamsValue";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-appraisal-3rd-time-index",
|
||||
templateUrl: "./contract-make-index.component.html",
|
||||
styleUrls: []
|
||||
})
|
||||
export class ContractMakeIndexComponent extends BaseListComponent implements OnInit {
|
||||
|
||||
pageTitle = "สัญญา";
|
||||
action = "pending";
|
||||
apiUrl: string = API.quotation;
|
||||
api: any = API;
|
||||
|
||||
displayedColumns: string[] = [];
|
||||
masterProductCategory: any = [];
|
||||
masterProductBrand: any = [];
|
||||
filterKeyword: Subject<string> = new Subject<string>();
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
public appService: AppService,
|
||||
public activatedRoute: ActivatedRoute,
|
||||
public changeDetectorRef: ChangeDetectorRef
|
||||
) {
|
||||
super();
|
||||
|
||||
this.filterKeyword.pipe(debounceTime(1000), distinctUntilChanged()).subscribe(model => {
|
||||
this.getData();
|
||||
});
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.activatedRoute.params.subscribe(async params => {
|
||||
this.action = params["action"];
|
||||
if (!this.action) this.router.navigate(["/pages/contract/make/list", EStatusQuotation.WAIT]);
|
||||
await this.getData();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async onTabs(action?: any) {
|
||||
this.dataFilter = {};
|
||||
return this.router.navigate(["/pages/contract/make/list", action]);
|
||||
}
|
||||
|
||||
async onAction(action : any, id?: any) {
|
||||
if (action === 'do') return this.router.navigate([`/pages/contract/make/do/${this.action}`, id]);
|
||||
if (action === 'pdf') return this.router.navigate([`/pages/contract/make/pdf/${this.action}`, id]);
|
||||
if (action === 'refinance') {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.REFINANCE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
async getData($event?: any) {
|
||||
try {
|
||||
this.dataSource = [];
|
||||
this.dataFilter.step = 5;
|
||||
this.dataFilter.statusContract = this.action;
|
||||
|
||||
let url = API.quotation;
|
||||
if (this.action === EStatusContract.WAIT) {
|
||||
url = API.quotation;
|
||||
this.displayedColumns = ["action", "price", "wantToInstallmentTerm", "customerFirstName", "productNo", "productName", "productBrandName", "productSize", "productWeight", "productColor", "productYear", "contractBy", "userFullName"];
|
||||
}
|
||||
if (this.action === EStatusContract.PENDING) {
|
||||
url = API.quotation;
|
||||
this.displayedColumns = ["action", "price", "wantToInstallmentTerm", "customerFirstName", "productNo", "productName", "productBrandName", "productSize", "productWeight", "productColor", "contractBy", "createdDate"];
|
||||
}
|
||||
if (this.action === EStatusContract.APPROVED) {
|
||||
url = API.quotation;
|
||||
this.displayedColumns = ["action", "price", "wantToInstallmentTerm", "customerFirstName", "productNo", "productName", "productBrandName", "productSize", "productWeight", "productColor", "contractBy", "contractApprovedBy", "contractApprovedDate"];
|
||||
}
|
||||
this.dataFilter.keywordColumn = "quotationNo,productNo,customerFirstName,price";
|
||||
const dataSource = await lastValueFrom(this.appService.get(this.setParams(url, $event)));
|
||||
this.dataSource = this.setDataSource<any>(dataSource);
|
||||
} catch (e) {
|
||||
this.dataSource = [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onFilter($event?: any) {
|
||||
this.filterKeyword.next($event);
|
||||
}
|
||||
|
||||
clearDate($event?: any) {
|
||||
$event.stopPropagation();
|
||||
this.dataFilter.createdDate = null;
|
||||
}
|
||||
|
||||
async onSort($event: any) {
|
||||
this.dataFilter.orderBy = $event.active;
|
||||
this.dataFilter.sort = $event.direction;
|
||||
await this.getData();
|
||||
console.log($event);
|
||||
}
|
||||
|
||||
|
||||
async onDelete(ids: any) {
|
||||
const sweetalert = await lastValueFrom(this.appService.confirm(EAction.DELETE));
|
||||
if (!sweetalert.isConfirmed) return;
|
||||
try {
|
||||
await lastValueFrom(this.appService.delete(this.apiUrl, ids));
|
||||
await this.appService.message(EAction.SUCCESS, EText.DELETE);
|
||||
await this.getData(this.getCurrentPage());
|
||||
} catch (err) {
|
||||
this.appService.message(EAction.ERROR, EText.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onExport() {
|
||||
const filter = generateParamsValue(this.dataFilter);
|
||||
const url = `${API.quotation}/export-contract?${filter ? '&' + filter : '' }`;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<mat-progress-bar *ngIf="!pdfView" mode="indeterminate"></mat-progress-bar>
|
||||
<iframe *ngIf="pdfView" [src]="pdfView"></iframe>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user