Commit f9119eaf authored by 伊藤雄大's avatar 伊藤雄大

Initial commit

parent 47b82738
......@@ -27,7 +27,8 @@
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": [
"zone.js"
"zone.js",
"@angular/localize/init"
],
"tsConfig": "tsconfig.app.json",
"assets": [
......@@ -37,9 +38,15 @@
}
],
"styles": [
"./node_modules/jqwidgets-ng/jqwidgets/styles/jqx.base.css",
"@angular/material/prebuilt-themes/azure-blue.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.css"
],
"scripts": []
"scripts": [
"node_modules/bootstrap/dist/js/bootstrap.min.js",
"node_modules/jquery/dist/jquery.min.js"
]
},
"configurations": {
"production": {
......@@ -85,7 +92,8 @@
"options": {
"polyfills": [
"zone.js",
"zone.js/testing"
"zone.js/testing",
"@angular/localize/init"
],
"tsConfig": "tsconfig.spec.json",
"assets": [
......@@ -95,12 +103,18 @@
}
],
"styles": [
"src/styles.css"
"./node_modules/jqwidgets-ng/jqwidgets/styles/jqx.base.css",
"@angular/material/prebuilt-themes/azure-blue.css",
"src/styles.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css"
],
"scripts": []
"scripts": [
"node_modules/bootstrap/dist/js/bootstrap.min.js",
"node_modules/jquery/dist/jquery.min.js"
]
}
}
}
}
}
}
}
\ No newline at end of file
This diff is collapsed.
......@@ -11,13 +11,21 @@
"private": true,
"dependencies": {
"@angular/animations": "^18.0.0",
"@angular/cdk": "^18.0.3",
"@angular/common": "^18.0.0",
"@angular/compiler": "^18.0.0",
"@angular/core": "^18.0.0",
"@angular/forms": "^18.0.0",
"@angular/material": "^18.0.3",
"@angular/platform-browser": "^18.0.0",
"@angular/platform-browser-dynamic": "^18.0.0",
"@angular/router": "^18.0.0",
"@ng-bootstrap/ng-bootstrap": "^17.0.0",
"@popperjs/core": "^2.11.8",
"ag-grid-angular": "^31.3.2",
"bootstrap": "^5.3.2",
"jquery": "^3.7.1",
"jqwidgets-ng": "^19.2.2",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.14.3"
......@@ -26,6 +34,7 @@
"@angular-devkit/build-angular": "^18.0.4",
"@angular/cli": "^18.0.4",
"@angular/compiler-cli": "^18.0.0",
"@angular/localize": "^18.0.0",
"@types/jasmine": "~5.1.0",
"jasmine-core": "~5.1.0",
"karma": "~6.4.0",
......
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { TopComponent } from './top/top.component';
import { MenuComponent } from './menu/menu.component';
const routes: Routes = [];
const routes: Routes = [
{ path: '', redirectTo: '/top', pathMatch: 'full' },
{ path: 'top', component: TopComponent },
{ path: 'menu', component: MenuComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
......
This diff is collapsed.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { jqxGridModule } from 'jqwidgets-ng/jqxgrid';
import { CommonModule } from '@angular/common';
import { CdkListbox, CdkOption } from '@angular/cdk/listbox';
import { TopComponent } from './top/top.component';
import { HeaderComponent } from './header/header.component';
import { MenuComponent } from './menu/menu.component';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { StaffListComponent } from './menu/staff-list/staff-list.component';
import { UserListComponent } from './menu/user-list/user-list.component';
import { RoleMstComponent } from './menu/master/role-mst/role-mst.component';
import { PassFareComponent } from './menu/master/pass-fare/pass-fare.component';
import { StaffRegistComponent } from './menu/staff-regist/staff-regist.component'
@NgModule({
declarations: [
AppComponent
AppComponent,
TopComponent,
HeaderComponent,
MenuComponent,
StaffListComponent,
UserListComponent,
RoleMstComponent,
PassFareComponent,
StaffRegistComponent
],
imports: [
BrowserModule,
AppRoutingModule
AppRoutingModule,
NgbModule,
FormsModule,
jqxGridModule,
CommonModule,
CdkListbox,
CdkOption,
ReactiveFormsModule
],
providers: [
provideAnimationsAsync()
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
.header {
background-color: #0caccd;
color: white;
height: 40px;
}
<div class="header">
<table width="100%">
<tr>
<td style="padding-left:10px;padding-top:5px;">
タッチ決済サービス
</td>
@if (mode === 1) {
<td class="logout" style="text-align: right;">
<div (click)="onClickLogout()">ログアウト</div>
</td>
}
</tr>
</table>
</div>
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HeaderComponent } from './header.component';
describe('HeaderComponent', () => {
let component: HeaderComponent;
let fixture: ComponentFixture<HeaderComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [HeaderComponent]
})
.compileComponents();
fixture = TestBed.createComponent(HeaderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, Input } from '@angular/core';
import { RouteService } from '../service/route.service';
/**
* ヘッダ
*/
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrl: './header.component.css'
})
export class HeaderComponent {
//モード(0:タイトルのみ、1:ログアウトあり)
@Input() mode: number = 0;
/**
* コンストラクタ
* @param routeService 画面遷移サービス
*/
constructor(private routeService: RouteService) { }
/**
* ログアウト
*/
onClickLogout(): void {
this.routeService.navigateTop();
}
}
.listbox-container {
display: block;
width: 600px;
border: 1px solid black;
}
.listbox-invalid {
border-color: red;
}
.listbox-label {
display: block;
padding: 5px;
}
.listbox-invalid .label {
color: red;
}
.listbox {
list-style: none;
padding: 0;
margin: 0;
height: 500px;
overflow: auto;
}
.option {
position: relative;
padding: 5px 5px 5px 25px;
}
.option[aria-selected="true"]::before {
content: "";
display: block;
width: 20px;
height: 20px;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path d="m9.55 18-5.7-5.7 1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4Z"/></svg>'); /* stylelint-disable-line */
background-size: cover;
position: absolute;
left: 2px;
}
.option:focus {
background: rgba(0, 0, 0, 0.2);
}
.listbox-errors {
color: red;
}
.label {
width: 80px;
}
.input-item {
width: 35%;
}
<table style="margin-top:10px;margin-left:10px;">
<tr>
<td>
<table>
<tr>
<td>
<span>事業所</span>
</td>
<td>
<select class="form-select" [(ngModel)]="agencyId" (change)="onChangeAgency()">
@for (item of agencyList|keyvalue;track item.key) {
<option [value]="item.key">{{item.value}}</option>
}
</select>
</td>
<td style="padding-left:10px;">
<span>路線</span>
</td>
<td>
<select class="form-select" [(ngModel)]="routeId" (change)="onChangeRoute()">
@for (item of routeList|keyvalue;track item.key) {
<option [value]="item.key">{{item.value}}</option>
}
</select>
</td>
</tr>
</table>
<div class="listbox-container" style="margin-top:10px;" [class.listbox-invalid]="invalid | async">
<ul cdkListbox [formControl]="formControl" class="listbox">
@for (item of passFareList; track item) {
<li [cdkOption]="item" class="option" (click)="onClickSel(item)">
<table>
<tr>
<td>
{{item.useTermName}}
</td>
<td style="padding-left:10px;">
{{item.routeName}}
</td>
<td style="padding-left:10px;">
{{item.getonStopName}}
</td>
<td style="padding-left:10px;">
{{item.getoffStopName}}
</td>
<td style="padding-left:10px;">
{{item.fare|number}}円
</td>
</tr>
</table>
</li>
}
</ul>
</div>
</td>
<td style="padding-left:10px;">
<div>
<input type="button" class="common-button rounded" value="追加" (click)="onClickAdd()">
</div>
<div style="margin-top:5px;">
<input type="button" class="common-button rounded" value="更新" (click)="onClickUpdate()">
</div>
<div style="margin-top:5px;">
<input type="button" class="common-button rounded" value="削除" (click)="onClickDel()">
</div>
</td>
<td style="padding-left:10px;">
<table>
<tr>
<td class="label">
<span>使用期間</span>
</td>
<td class="input-item">
<select class="form-select" [(ngModel)]="useTermId">
@for(item of useTermList|keyvalue;track item.key) {
<option [value]="item.key">{{item.value}}</option>
}
</select>
</td>
<td></td>
<td class="input-item"></td>
</tr>
<tr>
<td class="label">
<span>区間</span>
</td>
<td class="input-item">
<select class="form-select" [(ngModel)]="getonStopId">
@for(item of stopList|keyvalue;track item.key) {
<option [value]="item.key">{{item.value}}</option>
}
</select>
</td>
<td>
<span></span>
</td>
<td class="input-item">
<select class="form-select" [(ngModel)]="getoffStopId">
@for(item of stopList|keyvalue;track item.key) {
<option [value]="item.key">{{item.value}}</option>
}
</select>
</td>
</tr>
<tr>
<td class="label">
<span>金額</span>
</td>
<td class="input-item">
<input type="number" class="form-control" [(ngModel)]="fare">
</td>
<td>
<span></span>
</td>
<td class="input-item"></td>
</tr>
</table>
</td>
</tr>
</table>
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PassFareComponent } from './pass-fare.component';
describe('PassFareComponent', () => {
let component: PassFareComponent;
let fixture: ComponentFixture<PassFareComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [PassFareComponent]
})
.compileComponents();
fixture = TestBed.createComponent(PassFareComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
import { PassFareModel } from '../../../model/pass-fare.model';
import { FormControl, Validators } from '@angular/forms';
import { Observable } from 'rxjs';
/**
* 定期運賃マスタメンテ
*/
@Component({
selector: 'app-pass-fare',
templateUrl: './pass-fare.component.html',
styleUrl: './pass-fare.component.css'
})
export class PassFareComponent implements OnInit {
invalid?: Observable<boolean>;
formControl = new FormControl<PassFareModel[]>([], Validators.required);
//事業所一覧
agencyList?: Map<string, string>;
//路線一覧
routeList?: Map<string, string>;
//使用期間一覧
useTermList?: Map<string, string>;
//停留所一覧
stopList?: Map<string, string>
//定期運賃情報
passFareList: PassFareModel[] = [];
//事業所ID
agencyId?: string;
//路線ID
routeId?: string;
//使用期間ID
useTermId?: string;
//乗車停留所ID
getonStopId?: string;
//降車停留所ID
getoffStopId?: string;
//運賃
fare: number = 0;
/**
* コンストラクタ
*/
constructor() { }
/**
* 初期処理
*/
ngOnInit(): void {
//事業所一覧
this.agencyList = new Map();
for (let i = 0; i < 5; i++) {
let str = String(i + 1);
this.agencyList.set(str, "事業所" + str);
}
this.agencyId = "1";
this.onChangeAgency();
}
/**
* 事業者選択
*/
onChangeAgency(): void {
//路線一覧
this.routeList = new Map();
for (let i = 0; i < 5; i++) {
let str = String(i + 1);
this.routeList.set(str, "路線" + str);
}
this.routeId = "1";
this.onChangeRoute();
//使用期間
this.useTermList = new Map();
this.useTermList.set("1", "1ヶ月");
this.useTermList.set("3", "3ヶ月");
this.useTermList.set("6", "6ヶ月");
//停留所
this.stopList = new Map();
for (let i = 0; i < 5; i++) {
let str = String(i + 1);
this.stopList.set(str, "停留所" + str);
}
}
/**
* 路線選択
*/
onChangeRoute(): void {
//停留所
this.stopList = new Map();
for (let i = 0; i < 5; i++) {
let str = String(i + 1);
this.stopList.set(str, "停留所" + str);
}
this.passFareList = new Array();
for (let i = 0; i < 10; i++) {
let model: PassFareModel = new PassFareModel();
model.id = String(i + 1);
model.agencyId = this.agencyId;
model.routeId = this.routeId;
model.useTermId = "1";
model.useTermName = "1ヶ月";
model.routeName = "【◯◯系統】△△行き";
model.getonStopId = "1";
model.getonStopName = "テスト乗車停留所";
model.getoffStopId = "5";
model.getoffStopName = "テスト降車停留所";
model.fare = 600;
this.passFareList.push(model);
}
}
/**
* 一覧選択
* @param model 選択情報
*/
onClickSel(model: PassFareModel): void {
this.useTermId = model.useTermId;
this.getonStopId = model.getonStopId;
this.getoffStopId = model.getoffStopId;
this.fare = model.fare;
}
/**
* 追加
*/
onClickAdd(): void {
let model: PassFareModel = new PassFareModel();
model.id = String(this.passFareList.length + 1);
model.agencyId = this.agencyId;
model.routeId = this.routeId;
if (typeof this.routeId !== 'undefined') {
model.routeName = this.routeList?.get(this.routeId);
}
model.useTermId = this.useTermId;
if (typeof this.useTermId !== 'undefined') {
model.useTermName = this.useTermList?.get(this.useTermId);
}
model.getonStopId = this.getonStopId;
if (typeof this.getonStopId !== 'undefined') {
model.getonStopName = this.stopList?.get(this.getonStopId);
}
model.getoffStopId = this.getoffStopId;
if (typeof this.getoffStopId !== 'undefined') {
model.getoffStopName = this.stopList?.get(this.getoffStopId);
}
model.fare = this.fare;
this.passFareList.push(model);
}
/**
* 更新
*/
onClickUpdate(): void {
let list = this.formControl.value;
if (list !== null) {
let model = list[0];
for (let i = 0; i < this.passFareList.length; i++) {
if (this.passFareList[i].id === model.id) {
this.passFareList[i].useTermId = this.useTermId;
if (typeof this.useTermId !== 'undefined') {
this.passFareList[i].useTermName = this.useTermList?.get(this.useTermId);
}
this.passFareList[i].getonStopId = this.getonStopId;
if (typeof this.getonStopId !== 'undefined') {
this.passFareList[i].getonStopName = this.stopList?.get(this.getonStopId);
}
this.passFareList[i].getoffStopId = this.getoffStopId;
if (typeof this.getoffStopId !== 'undefined') {
this.passFareList[i].getoffStopName = this.stopList?.get(this.getoffStopId);
}
this.passFareList[i].fare = this.fare;
break;
}
}
}
}
/**
* 削除
*/
onClickDel(): void {
let list = this.formControl.value;
if (list !== null) {
let model = list[0];
let newList = new Array();
for (let i = 0; i < this.passFareList.length; i++) {
if (this.passFareList[i].id !== model.id) {
newList.push(this.passFareList[i]);
}
}
this.passFareList = newList;
this.useTermId = "";
this.getonStopId = "";
this.getoffStopId = "";
this.fare = 0;
}
}
}
.listbox-container {
display: block;
width: 250px;
border: 1px solid black;
}
.listbox-invalid {
border-color: red;
}
.listbox-label {
display: block;
padding: 5px;
}
.listbox-invalid .label {
color: red;
}
.listbox {
list-style: none;
padding: 0;
margin: 0;
height: 200px;
overflow: auto;
}
.option {
position: relative;
padding: 5px 5px 5px 25px;
}
.option[aria-selected="true"]::before {
content: "";
display: block;
width: 20px;
height: 20px;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path d="m9.55 18-5.7-5.7 1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4Z"/></svg>'); /* stylelint-disable-line */
background-size: cover;
position: absolute;
left: 2px;
}
.option:focus {
background: rgba(0, 0, 0, 0.2);
}
.listbox-errors {
color: red;
}
<table style="margin-top:10px;margin-left:10px;">
<tr>
<td>
<div class="listbox-container" [class.listbox-invalid]="invalid | async">
<ul cdkListbox [formControl]="formControl" class="listbox">
@for (item of roleList; track item) {
<li [cdkOption]="item" class="option" (click)="onClickSel(item)">{{item.name}}</li>
}
</ul>
</div>
</td>
<td style="padding-left:10px;">
<div>
<input type="button" class="common-button rounded" value="追加" (click)="onClickAdd()">
</div>
<div style="margin-top:5px;">
<input type="button" class="common-button rounded" value="更新" (click)="onClickUpdate()">
</div>
<div style="margin-top:5px;">
<input type="button" class="common-button rounded" value="削除" (click)="onClickDel()">
</div>
</td>
<td style="padding-left:10px;">
<table>
<tr>
<td>
<span>権限</span>
</td>
<td>
<input type="text" class="form-control" [(ngModel)]="roleName">
</td>
</tr>
<tr>
<td style="padding-top:10px;">
<span>事業所担当者</span>
</td>
<td style="padding-top:10px;">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="staffNo" name="staffRole" [value]="0"
[(ngModel)]="staffRole">
<label class="form-check-label" for="staffNo">閲覧不可</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="staffOnly" name="staffRole" [value]="1"
[(ngModel)]="staffRole">
<label class="form-check-label" for="staffOnly">自事業所のみ</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="staffAll" name="staffRole" [value]="2"
[(ngModel)]="staffRole">
<label class="form-check-label" for="staffAll">全事業所</label>
</div>
</td>
</tr>
<tr>
<td style="padding-top:10px;">
<span>利用者検索</span>
</td>
<td style="padding-top:10px;">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="userNo" name="userRole" [value]="0"
[(ngModel)]="userRole">
<label class="form-check-label" for="userNo">閲覧不可</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="userOnly" name="userRole" [value]="1"
[(ngModel)]="userRole">
<label class="form-check-label" for="userOnly">自事業所のみ</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="userAll" name="userRole" [value]="2"
[(ngModel)]="userRole">
<label class="form-check-label" for="userAll">全事業所</label>
</div>
</td>
</tr>
<tr>
<td style="padding-top:10px;">
<span>定期券検索</span>
</td>
<td style="padding-top:10px;">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="passNo" name="passRole" [value]="0"
[(ngModel)]="passRole">
<label class="form-check-label" for="passNo">閲覧不可</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="passOnly" name="passRole" [value]="1"
[(ngModel)]="passRole">
<label class="form-check-label" for="passOnly">自事業所のみ</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="passAll" name="passRole" [value]="2"
[(ngModel)]="passRole">
<label class="form-check-label" for="passAll">全事業所</label>
</div>
</td>
</tr>
<tr>
<td style="padding-top:10px;">
<span>乗降履歴</span>
</td>
<td style="padding-top:10px;">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="historyNo" name="historyRole" [value]="0"
[(ngModel)]="historyRole">
<label class="form-check-label" for="historyNo">閲覧不可</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="historyOnly" name="historyRole" [value]="1"
[(ngModel)]="historyRole">
<label class="form-check-label" for="historyOnly">自事業所のみ</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="historyAll" name="historyRole" [value]="2"
[(ngModel)]="historyRole">
<label class="form-check-label" for="historyAll">全事業所</label>
</div>
</td>
</tr>
<tr>
<td style="padding-top:10px;">
<span>拒否リスト</span>
</td>
<td style="padding-top:10px;">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="denyListNo" name="denyListRole" [value]="0"
[(ngModel)]="denyListRole">
<label class="form-check-label" for="denyListNo">閲覧不可</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="denyListOnly" name="denyListRole"
[value]="1" [(ngModel)]="denyListRole">
<label class="form-check-label" for="denyListOnly">自事業所のみ</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="denyListAll" name="denyListRole"
[value]="2" [(ngModel)]="denyListRole">
<label class="form-check-label" for="denyListAll">全事業所</label>
</div>
</td>
</tr>
<tr>
<td style="padding-top:10px;">
<span>マスタメンテ</span>
</td>
<td style="padding-top:10px;">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="masterNo" name="masterRole" [value]="0"
[(ngModel)]="masterRole">
<label class="form-check-label" for="masterNo">不可</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="masterOk" name="masterRole" [value]="1"
[(ngModel)]="masterRole">
<label class="form-check-label" for="masterOk"></label>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RoleMstComponent } from './role-mst.component';
describe('RoleMstComponent', () => {
let component: RoleMstComponent;
let fixture: ComponentFixture<RoleMstComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [RoleMstComponent]
})
.compileComponents();
fixture = TestBed.createComponent(RoleMstComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
import { RoleModel } from '../../../model/role.model';
import { FormControl, Validators } from '@angular/forms';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
/**
* 権限マスタ
*/
@Component({
selector: 'app-role-mst',
templateUrl: './role-mst.component.html',
styleUrl: './role-mst.component.css'
})
export class RoleMstComponent implements OnInit {
invalid?: Observable<boolean>;
formControl = new FormControl<RoleModel[]>([], Validators.required);
//権限一覧
roleList: RoleModel[] = [];
//権限名
roleName?: string;
//事業所担当者
staffRole: number = 0;
//利用者検索
userRole: number = 0;
//定期券検索
passRole: number = 0;
//乗降履歴
historyRole: number = 0;
//拒否リスト
denyListRole: number = 0;
//マスタメンテ
masterRole: number = 0;
/**
* コンストラクタ
*/
constructor() {
this.invalid = this.formControl.valueChanges.pipe(
map(() => this.formControl.touched && !this.formControl.valid),
);
}
/**
* 初期化
*/
ngOnInit(): void {
this.roleList = new Array();
let model: RoleModel = new RoleModel;
model.roleId = "1";
model.name = "担当";
model.staffRole = 0;
model.userRole = 1;
model.passRole = 1;
model.historyRole = 1;
model.denyListRole = 1;
model.masterRole = 0;
this.roleList.push(model);
model = new RoleModel;
model.roleId = "2";
model.name = "事業所管理者";
model.staffRole = 1;
model.userRole = 1;
model.passRole = 1;
model.historyRole = 1;
model.denyListRole = 1;
model.masterRole = 0;
this.roleList.push(model);
model = new RoleModel;
model.roleId = "3";
model.name = "システム管理者";
model.staffRole = 2;
model.userRole = 2;
model.passRole = 2;
model.historyRole = 2;
model.denyListRole = 2;
model.masterRole = 1;
this.roleList.push(model);
}
/**
* 追加
*/
onClickAdd(): void {
let model: RoleModel = new RoleModel();
model.roleId = String(this.roleList.length + 1);
model.name = this.roleName;
model.staffRole = this.staffRole;
model.userRole = this.userRole;
model.passRole = this.passRole;
model.historyRole = this.historyRole;
model.denyListRole = this.denyListRole;
model.masterRole = this.masterRole;
this.roleList.push(model);
}
/**
* 更新
*/
onClickUpdate(): void {
let list = this.formControl.value;
if (list !== null) {
let model = list[0];
for (let i = 0; i < this.roleList.length; i++) {
if (this.roleList[i].roleId === model.roleId) {
this.roleList[i].name = this.roleName;
this.roleList[i].staffRole = this.staffRole;
this.roleList[i].userRole = this.userRole;
this.roleList[i].passRole = this.passRole;
this.roleList[i].historyRole = this.historyRole;
this.roleList[i].denyListRole = this.denyListRole;
this.roleList[i].masterRole = this.masterRole;
break;
}
}
}
}
/**
* 削除
*/
onClickDel(): void {
let list = this.formControl.value;
if (list !== null) {
let model = list[0];
let newList = new Array();
for (let i = 0; i < this.roleList.length; i++) {
if (this.roleList[i].roleId !== model.roleId) {
newList.push(this.roleList[i]);
}
}
this.roleList = newList;
this.roleName = "";
this.staffRole = 0;
this.userRole = 0;
this.passRole = 0;
this.historyRole = 0;
this.denyListRole = 0;
this.masterRole = 0;
}
}
/**
* 選択
* @param model 権限情報
*/
onClickSel(model: RoleModel): void {
this.roleName = model.name;
this.staffRole = model.staffRole;
this.userRole = model.userRole;
this.passRole = model.passRole;
this.historyRole = model.historyRole;
this.denyListRole = model.denyListRole;
this.masterRole = model.masterRole;
}
}
html {
height: 100%;
}
body {
height: 100%;
margin: 0;
}
<app-header [mode]="1"></app-header>
<div class="container" style="max-width:100%;height:96%;">
<div class="row h-100">
<div class="col-md-auto border">
<div class="common-link" type="button" style="margin-top:20px;" (click)="onClickBusiness()">事業所担当者</div>
<div class="common-link" type="button" style="margin-top:10px;" (click)=" onClickUser()">利用者検索</div>
<div class="common-link" type="button" style="margin-top:10px;" (click)="onClickRoleMst()">権限マスタ</div>
<div class="common-link" type="button" style="margin-top:10px;" (click)="onClickPassFare()">定期券運賃マスタ</div>
</div>
<div class="col">
@if (mode === 0) {
<app-staff-list (clickNew)="onClickNew()" (clickEdit)="onClickEdit($event)"></app-staff-list>
} @else if (mode === 1) {
<app-user-list></app-user-list>
} @else if (mode === 2) {
<app-staff-regist [mode]="staffEditMode" (clickBack)="onClickRegist()"></app-staff-regist>
} @else if (mode === 3) {
<app-role-mst></app-role-mst>
} @else if (mode === 4) {
<app-pass-fare></app-pass-fare>
}
</div>
</div>
</div>
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MenuComponent } from './menu.component';
describe('MenuComponent', () => {
let component: MenuComponent;
let fixture: ComponentFixture<MenuComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [MenuComponent]
})
.compileComponents();
fixture = TestBed.createComponent(MenuComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { FlatTreeControl } from '@angular/cdk/tree';
import { Component } from '@angular/core';
interface ExampleFlatNode {
expandable: boolean;
name: string;
level: number;
}
@Component({
selector: 'app-menu',
templateUrl: './menu.component.html',
styleUrl: './menu.component.css'
})
export class MenuComponent {
//モード(0:事業所担当者、1:利用者検索、2:利用者登録・更新、3:権限マスタ、4:定期券運賃マスタ)
mode: number = 0;
//担当者編集モード(0:登録、1:編集)
staffEditMode: number = 0;
/**
* 事業所担当者
*/
onClickBusiness(): void {
this.mode = 0;
}
/**
* 利用者検索
*/
onClickUser(): void {
this.mode = 1;
}
/**
* 新規
*/
onClickNew(): void {
this.mode = 2;
}
/**
* 編集
* @param row 行番号
*/
onClickEdit(row: number): void {
this.mode = 2;
}
/**
* 担当者登録後
*/
onClickRegist(): void {
this.mode = 0;
}
/**
* 権限マスタ
*/
onClickRoleMst(): void {
this.mode = 3;
}
/**
* 定期券運賃マスタ
*/
onClickPassFare(): void {
this.mode = 4;
}
}
@import "jqwidgets-ng/jqwidgets/styles/jqx.base.css";
<table style="margin-top:10px;margin-left:10px;">
<tr>
<td>
<span>事業所</span>
</td>
<td style="padding-left:10px;">
<select class="form-select" [(ngModel)]="agencyId">
@for (item of agencyList|keyvalue;track item.key) {
<option [value]="item.key">{{item.value}}</option>
}
</select>
</td>
<td style="padding-left:10px;">
<input type="button" class="btn common-button" value="検索" (click)="onClickSearch()" />
</td>
</tr>
</table>
<table style="margin-top:10px;">
<tr>
<td>
<input type="button" class="btn common-button" value="新規" (click)="onClickNew()" />
</td>
<td>
<input type="button" class="btn common-button" value="削除" (click)="onClickDel()" />
</td>
</tr>
</table>
<jqxGrid style="margin-top:20px;" [width]="770" [selectionmode]="'checkbox'" [source]="source" [theme]="'material'"
[autoheight]="true" [pageable]="true" [altrows]="true" [filterable]="true" [sortable]="true" [columns]="columns"
#grid></jqxGrid>
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { StaffListComponent } from './staff-list.component';
describe('StaffListComponent', () => {
let component: StaffListComponent;
let fixture: ComponentFixture<StaffListComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [StaffListComponent]
})
.compileComponents();
fixture = TestBed.createComponent(StaffListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core';
import { StaffInfoModel } from '../../model/staff-info.model';
import { jqxGridComponent } from 'jqwidgets-ng/jqxgrid';
/**
* 事業所担当者一覧
*/
@Component({
selector: 'app-staff-list',
templateUrl: './staff-list.component.html',
styleUrl: './staff-list.component.css'
})
export class StaffListComponent implements OnInit {
@Output() clickNew: EventEmitter<void> = new EventEmitter();
@Output() clickEdit: EventEmitter<number> = new EventEmitter();
@ViewChild('grid', { static: false }) myGrid?: jqxGridComponent;
//事業所ID
agencyId: string = "";
//事業所一覧
agencyList: Map<string, string> = new Map();
//担当者一覧
staffList: StaffInfoModel[] = [];
source: any = {
datatype: 'json',
datafields: [
{ name: 'update', type: 'string' },
{ name: 'email', type: 'string' },
{ name: 'name', type: 'string' },
{ name: 'company', type: 'string' },
{ name: 'department', type: 'string' },
{ name: 'roleName', type: 'string' }
]
}
columns = [
{
text: '', datafield: 'update', width: 40, cellsrenderer: function (row: any, column: any, value: any) {
return '<input type="button" style="width:40px;height:100%;" data-row="' + row + '" onclick="onClickEdit(' + row + ')" value="編集">';
}
},
{ text: 'メールアドレス', datafield: 'email', width: 200, },
{ text: '氏名', datafield: 'name', width: 200 },
{ text: '会社', datafield: 'company', width: 100 },
{ text: '部署', datafield: 'department', width: 100 },
{ text: '権限', datafield: 'roleName', width: 100 }
];
/**
* コンストラクタ
*/
constructor() { }
/**
* 初期処理
*/
ngOnInit(): void {
this.agencyList = new Map();
for (let i = 0; i < 5; i++) {
let str = String(i + 1);
this.agencyList.set("000" + str, "事業所" + str);
if (i == 0) {
this.agencyId = "000" + str;
}
}
}
/**
* 検索
*/
onClickSearch(): void {
//担当者一覧取得
this.staffList = new Array();
for (let i = 0; i < 5; i++) {
let model = new StaffInfoModel();
model.email = "test" + String(i + 1) + "@test.com";
model.name = "山田 太郎";
model.company = "テスト会社";
model.department = "テスト部";
model.roleId = "0";
model.roleName = "システム管理者";
this.staffList.push(model);
}
this.source.localdata = JSON.stringify(this.staffList);
this.myGrid?.updatebounddata();
}
/**
* 新規
*/
onClickNew(): void {
this.clickNew.emit();
}
/**
* 編集
*/
onClickEdit(row: number): void {
this.clickEdit.emit(row);
}
/**
* 削除
*/
onClickDel(): void {
//TODO
if (typeof this.myGrid !== "undefined") {
let rows = this.myGrid.getselectedrowindexes();
for (let i = 0; i < rows.length; i++) {
console.log(rows[i]);
}
}
}
}
<table>
<tr>
<td style="padding-top:10px;padding-left:10px;">
<span>事業所</span>
</td>
<td style="padding-top:10px;padding-left:10px;">
<select class="form-select" [(ngModel)]="agencyId" [disabled]="mode === 1">
@for (item of agencyList|keyvalue;track item.key) {
<option [value]="item.key">{{item.value}}</option>
}
</select>
</td>
</tr>
<tr>
<td style="padding-top:10px;padding-left:10px;">
<span>メールアドレス</span>
</td>
<td style="padding-top:10px;padding-left:10px;">
<input type="email" class="form-control" [(ngModel)]="email" [disabled]="mode === 1">
</td>
</tr>
<tr>
<td style="padding-top:10px;padding-left:10px;">
<span>パスワード</span>
</td>
<td style="padding-top:10px;padding-left:10px;">
<input type="password" class="form-control" [(ngModel)]="password">
</td>
</tr>
<tr>
<td style="padding-top:10px;padding-left:10px;">
<span>氏名</span>
</td>
<td style="padding-top:10px;padding-left:10px;">
<input type="text" class="form-control" [(ngModel)]="name">
</td>
</tr>
<tr>
<td style="padding-top:10px;padding-left:10px;">
<span>部署</span>
</td>
<td style="padding-top:10px;padding-left:10px;">
<input type="text" class="form-control" [(ngModel)]="department">
</td>
</tr>
<tr>
<td style="padding-top:10px;padding-left:10px;">
権限
</td>
<td style="padding-top:10px;padding-left:10px;">
<select class="form-select" [(ngModel)]="roleId">
@for (item of roleList|keyvalue;track item.key) {
<option [value]="item.key">{{item.value}}</option>
}
</select>
</td>
</tr>
<tr>
<td colspan="2" style="padding-top:10px;">
<table>
<tr>
<td>
@if (mode === 0) {
<input type="button" class="btn common-button" value="登録" (click)="onClickRegist()">
} @else {
<input type="button" class="btn common-button" value="更新" (click)="onClickUpdate()">
}
</td>
<td>
<input type="button" class="btn common-button" value="戻る" (click)="onClickBack()">
</td>
</tr>
</table>
</td>
</tr>
</table>
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { StaffRegistComponent } from './staff-regist.component';
describe('StaffRegistComponent', () => {
let component: StaffRegistComponent;
let fixture: ComponentFixture<StaffRegistComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [StaffRegistComponent]
})
.compileComponents();
fixture = TestBed.createComponent(StaffRegistComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
@Component({
selector: 'app-staff-regist',
templateUrl: './staff-regist.component.html',
styleUrl: './staff-regist.component.css'
})
export class StaffRegistComponent implements OnInit {
@Input() mode: number = 0;
@Output() clickBack: EventEmitter<void> = new EventEmitter();
//事業所ID
agencyId?: string;
//事業所一覧
agencyList?: Map<string, string>
//メールアドレス
email?: string;
//パスワード
password?: string;
//氏名
name?: string;
//部署
department?: string;
//権限
roleId?: string;
//権限一覧
roleList?: Map<string, string>
/**
* コンストラクタ
*/
constructor() { }
/**
* 初期処理
*/
ngOnInit(): void {
//事業所一覧
this.agencyList = new Map();
for (let i = 0; i < 5; i++) {
let str = String(i + 1);
this.agencyList?.set(str, "事業所" + str)
}
//権限一覧
this.roleList = new Map();
for (let i = 0; i < 3; i++) {
let str = String(i + 1);
this.roleList?.set(str, "権限" + str)
}
}
/**
* 登録
*/
onClickRegist(): void {
//担当者登録
this.clickBack.emit();
}
/**
* 更新
*/
onClickUpdate(): void {
//担当者更新
this.clickBack.emit();
}
/**
* 戻る
*/
onClickBack(): void {
this.clickBack.emit();
}
}
<table style="margin-top:10px;margin-left:10px;">
<tr>
<td>
<span>利用者名</span>
</td>
<td style="padding-left:10px;">
<input type="text" class="form-control" [(ngModel)]="userName" />
</td>
<td style="padding-left:10px;">
<input type="button" class="btn common-button" value="検索" (click)="onClickSearch()" />
</td>
</tr>
</table>
<jqxGrid style="margin-top:20px;" [width]="940" [source]="source" [theme]="'material'" [autoheight]="true"
[pageable]="true" [altrows]="true" [filterable]="true" [sortable]="true" [columns]="columns" #grid></jqxGrid>
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UserListComponent } from './user-list.component';
describe('UserListComponent', () => {
let component: UserListComponent;
let fixture: ComponentFixture<UserListComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [UserListComponent]
})
.compileComponents();
fixture = TestBed.createComponent(UserListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, ViewChild } from '@angular/core';
import { UserInfoModel } from '../../model/user-info.model';
import { jqxGridComponent } from 'jqwidgets-ng/jqxgrid';
/**
* 利用者検索画面
*/
@Component({
selector: 'app-user-list',
templateUrl: './user-list.component.html',
styleUrl: './user-list.component.css'
})
export class UserListComponent {
@ViewChild('grid', { static: false }) myGrid?: jqxGridComponent;
//利用者名
userName?: string;
//利用者一覧
userList: UserInfoModel[] = [];
source: any = {
datatype: 'json',
datafields: [
{ name: 'name', type: 'string' },
{ name: 'nameKana', type: 'string' },
{ name: 'email', type: 'string' },
{ name: 'phoneNumber', type: 'string' },
{ name: 'pass', type: 'string' },
{ name: 'history', type: 'string' },
{ name: 'denyList', type: 'string' }
]
}
columns = [
{ text: '氏名', datafield: 'name', width: 200, },
{ text: 'フリガナ', datafield: 'nameKana', width: 200 },
{ text: 'メールアドレス', datafield: 'email', width: 200 },
{ text: '電話番号', datafield: 'phoneNumber', width: 100 },
{
text: '', datafield: 'pass', width: 80, cellsrenderer: function (row: any, column: any, value: any) {
return '<input type="button" style="width:80px;height:100%;" data-row="' + row + '" onclick="onClickPass(' + row + ')" value="定期券">';
}
},
{
text: '', datafield: 'history', width: 80, cellsrenderer: function (row: any, column: any, value: any) {
return '<input type="button" style="width:80px;height:100%;" data-row="' + row + '" onclick="onClickHistory(' + row + ')" value="乗降履歴">';
}
},
{
text: '', datafield: 'denyList', width: 80, cellsrenderer: function (row: any, column: any, value: any) {
return '<input type="button" style="width:80px;height:100%;" data-row="' + row + '" onclick="onClickHistory(' + row + ')" value="拒否リスト">';
}
}
];
/**
* コンストラクタ
*/
constructor() { }
/**
* 検索
*/
onClickSearch(): void {
this.userList = new Array();
for (let i = 0; i < 10; i++) {
let str = String(i + 1);
let model = new UserInfoModel();
model.name = "山田太郎" + str;
model.nameKana = "ヤマダタロウ" + str;
model.email = "tarou_yamada" + str + "@test.com";
model.phoneNumber = "09088882456";
this.userList.push(model);
}
this.source.localdata = JSON.stringify(this.userList);
this.myGrid?.updatebounddata();
}
}
/**
* 定期券運賃情報
*/
export class PassFareModel {
//ID
id?: string;
//事業者ID
agencyId?: string;
//経路ID
routeId?: string;
//経路名
routeName?: string;
//使用期間ID
useTermId?: string;
//使用期間名
useTermName?: string;
//乗車停留所ID
getonStopId?: string;
//乗車停留所名
getonStopName?: string;
//降車停留所ID
getoffStopId?: string;
//降車停留所名
getoffStopName?: string;
//運賃
fare: number = 0;
}
\ No newline at end of file
/**
* 権限情報
*/
export class RoleModel {
//権限ID
roleId: string = "";
//権限名
name?: string;
//担当者管理(0:閲覧不可、1:自事業所のみ、2:全事業所)
staffRole: number = 0;
//利用者検索(0:閲覧不可、1:自事業所のみ、2:全事業所)
userRole: number = 0;
//定期券検索(0:閲覧不可、1:自事業所のみ、2:全事業所)
passRole: number = 0;
//乗降履歴(0:閲覧不可、1:自事業所のみ、2:全事業所)
historyRole: number = 0;
//拒否リスト(0:閲覧不可、1:自事業所のみ、2:全事業所)
denyListRole: number = 0;
//マスタメンテ(0:不可、1:可)
masterRole: number = 0;
}
\ No newline at end of file
/**
* スタッフ情報
*/
export class StaffInfoModel {
//選択状態
select: boolean = false;
//メールアドレス
email?: string;
//スタッフ氏名
name?: string;
//会社名
company?: string;
//部署
department?: string;
//権限ID
roleId?: string;
//権限名
roleName?: string;
}
\ No newline at end of file
/**
* 利用者情報
*/
export class UserInfoModel {
//氏名
name?: string;
//フリガナ
nameKana?: string;
//メールアドレス
email?: string;
//電話番号
phoneNumber?: string;
}
\ No newline at end of file
import { TestBed } from '@angular/core/testing';
import { RouteService } from './route.service';
describe('RouteService', () => {
let service: RouteService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(RouteService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
/**
* 画面遷移サービス
*/
@Injectable({
providedIn: 'root'
})
export class RouteService {
/**
* コンストラクタ
* @param router ルーター
*/
constructor(private router: Router) { }
navigateTop(): void {
this.router.navigate(['top'])
}
/**
* メニューへ遷移
*/
navigateMenu(): void {
this.router.navigate(['menu'])
}
}
.login-block {
width: 400px;
}
<app-header></app-header>
<div class="mx-auto login-block" style="margin-top:20px;">
<table>
<tr>
<td>
<span>メールアドレス</span>
</td>
<td style="padding-left:10px;">
<input type="email" class="form-control" [(ngModel)]="email" />
</td>
</tr>
<tr>
<td>
<span>パスワード</span>
</td>
<td style="padding-left:10px;">
<input type="password" class="form-control" [(ngModel)]="password" />
</td>
</tr>
<tr>
<td colspan="2" align="center" style="padding-top:20px;">
<input type="button" class="btn common-button" value="ログイン" (click)="onClickLogin()" />
</td>
</tr>
</table>
</div>
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TopComponent } from './top.component';
describe('TopComponent', () => {
let component: TopComponent;
let fixture: ComponentFixture<TopComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [TopComponent]
})
.compileComponents();
fixture = TestBed.createComponent(TopComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component } from '@angular/core';
import { RouteService } from '../service/route.service';
/**
* ログイン画面
*/
@Component({
selector: 'app-top',
templateUrl: './top.component.html',
styleUrl: './top.component.css'
})
export class TopComponent {
//メールアドレス
email?: string;
//パスワード
password?: string;
/**
* コンストラクタ
*/
constructor(private routeService: RouteService) {
}
/**
* ログイン
*/
onClickLogin(): void {
this.routeService.navigateMenu();
}
}
......@@ -6,6 +6,8 @@
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<app-root></app-root>
......
/// <reference types="@angular/localize" />
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
......
/* You can add global styles to this file, and also import other style files */
.common-button {
background-color: #f19024;
color: white;
height: 40px;
padding-left: 20px;
padding-right: 20px;
}
.common-link {
text-decoration: underline;
color: #0caccd;
}
html,
body {
height: 100%;
}
body {
margin: 0;
font-family: Roboto, "Helvetica Neue", sans-serif;
}
......@@ -4,7 +4,9 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
"types": [
"@angular/localize"
]
},
"files": [
"src/main.ts"
......
......@@ -30,4 +30,4 @@
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
}
\ No newline at end of file
......@@ -5,7 +5,8 @@
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jasmine"
"jasmine",
"@angular/localize"
]
},
"include": [
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment