Commit e20da866 authored by nanahira's avatar nanahira

favicon

parent 133d488b
Pipeline #14565 canceled with stages
in 2 minutes and 5 seconds
/src/app/api
dist/*
build/*
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
root: true,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.*.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
};
stages:
- install
- build
- deploy
variables:
GIT_DEPTH: "1"
npm_ci:
stage: install
tags:
- linux
script:
- npm ci
artifacts:
paths:
- node_modules
.build_base:
stage: build
tags:
- linux
dependencies:
- npm_ci
build:
extends: .build_base
script: npm run build
artifacts:
paths:
- dist/
test:
extends: .build_base
script: npm run test
upload_to_minio:
stage: deploy
dependencies:
- build
tags:
- linux
script:
- aws s3 --endpoint=https://minio.momobako.com:9000 sync dist/wenyuanwall/ s3://nanahira/wenyuanwall
only:
- master
#!/bin/bash
npm install --save \
bootstrap \
@ng-bootstrap/ng-bootstrap
npm install --save-dev \
'@typescript-eslint/eslint-plugin@^4.28.2' \
'@typescript-eslint/parser@^4.28.2 '\
'eslint@^7.30.0' \
'eslint-config-prettier@^8.3.0' \
'eslint-plugin-prettier@^3.4.0'
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -6,7 +6,8 @@ ...@@ -6,7 +6,8 @@
"start": "ng serve", "start": "ng serve",
"build": "ng build", "build": "ng build",
"watch": "ng build --watch --configuration development", "watch": "ng build --watch --configuration development",
"test": "ng test" "test": "ng test",
"gen": "ng-openapi-gen -i http://localhost:3000/docs-json"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
...@@ -18,6 +19,9 @@ ...@@ -18,6 +19,9 @@
"@angular/platform-browser": "~13.3.0", "@angular/platform-browser": "~13.3.0",
"@angular/platform-browser-dynamic": "~13.3.0", "@angular/platform-browser-dynamic": "~13.3.0",
"@angular/router": "~13.3.0", "@angular/router": "~13.3.0",
"@ng-bootstrap/ng-bootstrap": "^12.1.2",
"bootstrap": "^5.1.3",
"moment": "^2.29.4",
"rxjs": "~7.5.0", "rxjs": "~7.5.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
...@@ -28,12 +32,18 @@ ...@@ -28,12 +32,18 @@
"@angular/compiler-cli": "~13.3.0", "@angular/compiler-cli": "~13.3.0",
"@types/jasmine": "~3.10.0", "@types/jasmine": "~3.10.0",
"@types/node": "^12.11.1", "@types/node": "^12.11.1",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^3.4.1",
"jasmine-core": "~4.0.0", "jasmine-core": "~4.0.0",
"karma": "~6.3.0", "karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0", "karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.1.0", "karma-coverage": "~2.1.0",
"karma-jasmine": "~4.0.0", "karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "~1.7.0", "karma-jasmine-html-reporter": "~1.7.0",
"ng-openapi-gen": "^0.21.2",
"typescript": "~4.6.2" "typescript": "~4.6.2"
} }
} }
/* tslint:disable */
/* eslint-disable */
import { Injectable } from '@angular/core';
/**
* Global configuration
*/
@Injectable({
providedIn: 'root',
})
export class ApiConfiguration {
rootUrl: string = '';
}
/**
* Parameters for `ApiModule.forRoot()`
*/
export interface ApiConfigurationParams {
rootUrl?: string;
}
/* tslint:disable */
/* eslint-disable */
import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ApiConfiguration, ApiConfigurationParams } from './api-configuration';
import { ApiService } from './services/api.service';
/**
* Module that provides all services and configuration.
*/
@NgModule({
imports: [],
exports: [],
declarations: [],
providers: [
ApiService,
ApiConfiguration
],
})
export class ApiModule {
static forRoot(params: ApiConfigurationParams): ModuleWithProviders<ApiModule> {
return {
ngModule: ApiModule,
providers: [
{
provide: ApiConfiguration,
useValue: params
}
]
}
}
constructor(
@Optional() @SkipSelf() parentModule: ApiModule,
@Optional() http: HttpClient
) {
if (parentModule) {
throw new Error('ApiModule is already loaded. Import in your base AppModule only.');
}
if (!http) {
throw new Error('You need to import the HttpClientModule in your AppModule! \n' +
'See also https://github.com/angular/angular/issues/20575');
}
}
}
/* tslint:disable */
/* eslint-disable */
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ApiConfiguration } from './api-configuration';
/**
* Base class for services
*/
@Injectable()
export class BaseService {
constructor(
protected config: ApiConfiguration,
protected http: HttpClient
) {
}
private _rootUrl: string = '';
/**
* Returns the root url for all operations in this service. If not set directly in this
* service, will fallback to `ApiConfiguration.rootUrl`.
*/
get rootUrl(): string {
return this._rootUrl || this.config.rootUrl;
}
/**
* Sets the root URL for API operations in this service.
*/
set rootUrl(rootUrl: string) {
this._rootUrl = rootUrl;
}
}
export { Blacklist } from './models/blacklist';
export { BlacklistAccount } from './models/blacklist-account';
export { BlacklistAccountPaginatedReturnMessageDto } from './models/blacklist-account-paginated-return-message-dto';
/* tslint:disable */
/* eslint-disable */
import { BlacklistAccount } from './blacklist-account';
export interface BlacklistAccountPaginatedReturnMessageDto {
/**
* Return data.
*/
data?: Array<BlacklistAccount>;
/**
* Return message
*/
message: string;
/**
* Current page.
*/
pageCount: number;
/**
* Records per page.
*/
recordsPerPage: number;
/**
* Return code
*/
statusCode: number;
/**
* Whether success.
*/
success: boolean;
/**
* Total record count.
*/
total: number;
/**
* Total page count.
*/
totalPages: number;
}
/* tslint:disable */
/* eslint-disable */
import { Blacklist } from './blacklist';
export interface BlacklistAccount {
/**
* QQ account number.
*/
account: string;
blacklist: Blacklist;
/**
* Blacklist ID.
*/
blacklistId: string;
createTime: string;
deleteTime: string;
id: number;
/**
* The nth page, starting with 1.
*/
pageCount?: number;
/**
* Records per page.
*/
recordsPerPage?: number;
updateTime: string;
}
/* tslint:disable */
/* eslint-disable */
import { BlacklistAccount } from './blacklist-account';
export interface Blacklist {
accounts: Array<BlacklistAccount>;
/**
* Tweet content
*/
content: string;
createTime: string;
deleteTime: string;
id: string;
/**
* Twitter link
*/
link: string;
/**
* The nth page, starting with 1.
*/
pageCount?: number;
/**
* Records per page.
*/
recordsPerPage?: number;
/**
* Tweet time
*/
time: string;
updateTime: string;
}
This diff is collapsed.
export { ApiService } from './services/api.service';
/* tslint:disable */
/* eslint-disable */
import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { BaseService } from '../base-service';
import { ApiConfiguration } from '../api-configuration';
import { StrictHttpResponse } from '../strict-http-response';
import { RequestBuilder } from '../request-builder';
import { Observable } from 'rxjs';
import { map, filter } from 'rxjs/operators';
import { BlacklistAccountPaginatedReturnMessageDto } from '../models/blacklist-account-paginated-return-message-dto';
@Injectable({
providedIn: 'root',
})
export class ApiService extends BaseService {
constructor(
config: ApiConfiguration,
http: HttpClient
) {
super(config, http);
}
/**
* Path part for operation blacklistAccountControllerFindAll
*/
static readonly BlacklistAccountControllerFindAllPath = '/api/blacklist';
/**
* Find all BlacklistAccount.
*
*
*
* This method provides access to the full `HttpResponse`, allowing access to response headers.
* To access only the response body, use `blacklistAccountControllerFindAll()` instead.
*
* This method doesn't expect any request body.
*/
blacklistAccountControllerFindAll$Response(params?: {
/**
* The nth page, starting with 1.
*/
pageCount?: number;
/**
* Records per page.
*/
recordsPerPage?: number;
id?: number;
/**
* QQ account number.
*/
account?: string;
/**
* Blacklist ID.
*/
blacklistId?: string;
}): Observable<StrictHttpResponse<BlacklistAccountPaginatedReturnMessageDto>> {
const rb = new RequestBuilder(this.rootUrl, ApiService.BlacklistAccountControllerFindAllPath, 'get');
if (params) {
rb.query('pageCount', params.pageCount, {});
rb.query('recordsPerPage', params.recordsPerPage, {});
rb.query('id', params.id, {});
rb.query('account', params.account, {});
rb.query('blacklistId', params.blacklistId, {});
}
return this.http.request(rb.build({
responseType: 'json',
accept: 'application/json'
})).pipe(
filter((r: any) => r instanceof HttpResponse),
map((r: HttpResponse<any>) => {
return r as StrictHttpResponse<BlacklistAccountPaginatedReturnMessageDto>;
})
);
}
/**
* Find all BlacklistAccount.
*
*
*
* This method provides access to only to the response body.
* To access the full response (for headers, for example), `blacklistAccountControllerFindAll$Response()` instead.
*
* This method doesn't expect any request body.
*/
blacklistAccountControllerFindAll(params?: {
/**
* The nth page, starting with 1.
*/
pageCount?: number;
/**
* Records per page.
*/
recordsPerPage?: number;
id?: number;
/**
* QQ account number.
*/
account?: string;
/**
* Blacklist ID.
*/
blacklistId?: string;
}): Observable<BlacklistAccountPaginatedReturnMessageDto> {
return this.blacklistAccountControllerFindAll$Response(params).pipe(
map((r: StrictHttpResponse<BlacklistAccountPaginatedReturnMessageDto>) => r.body as BlacklistAccountPaginatedReturnMessageDto)
);
}
}
/* tslint:disable */
/* eslint-disable */
import { HttpResponse } from '@angular/common/http';
/**
* Constrains the http response to not have the body defined as `T | null`, but `T` only.
*/
export type StrictHttpResponse<T> = HttpResponse<T> & {
readonly body: T;
}
This diff is collapsed.
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { ToastService } from './toast.service';
import { BlacklistAccount } from './api/models/blacklist-account';
import { ApiService } from './api/services/api.service';
import { lastValueFrom } from 'rxjs';
import * as moment from 'moment';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.css'] styleUrls: ['./app.component.css'],
}) })
export class AppComponent { export class AppComponent {
title = 'wenyuanwall'; search = '';
displayingAccount = '';
title = '蔷蔷挂人查询';
result?: BlacklistAccount[];
constructor(public toast: ToastService, private api: ApiService) {}
displayDate(date: string) {
return moment(date).format('YYYY-MM-DD HH:mm:ss');
}
async onSearch() {
this.result = undefined;
const search = this.search.trim();
if (!search) {
this.toast.warn('不能为空。');
return;
}
if (search.length > 10) {
this.toast.warn('不能超过 10 个字符。');
return;
}
if (!search.match(/^\d+$/)) {
this.toast.warn('只能输入数字。');
return;
}
try {
const { data } = await lastValueFrom(
this.api.blacklistAccountControllerFindAll({
recordsPerPage: 100,
account: search,
})
);
this.result = data;
this.displayingAccount = this.search;
} catch (e) {
this.toast.error(`查询失败:${(e as Error).toString()}`);
}
}
} }
...@@ -2,15 +2,27 @@ import { NgModule } from '@angular/core'; ...@@ -2,15 +2,27 @@ import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { ToastComponent } from './toast/toast.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { FormsModule } from '@angular/forms';
import { environment } from '../environments/environment';
import { ApiModule } from './api/api.module';
import { HttpClientModule } from '@angular/common/http';
@NgModule({ @NgModule({
declarations: [ declarations: [AppComponent, ToastComponent],
AppComponent
],
imports: [ imports: [
BrowserModule BrowserModule,
NgbModule,
FormsModule,
HttpClientModule,
ApiModule.forRoot({
rootUrl: environment.production
? 'https://blapi.wenaiwu.net'
: 'http://localhost:3000',
}),
], ],
providers: [], providers: [],
bootstrap: [AppComponent] bootstrap: [AppComponent],
}) })
export class AppModule { } export class AppModule {}
import { TestBed } from '@angular/core/testing';
import { ToastService } from './toast.service';
describe('ToastService', () => {
let service: ToastService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ToastService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
import { Injectable } from '@angular/core';
export interface ToastInfo {
id: number;
header: string;
body: string;
persist?: boolean;
classname?: string;
}
@Injectable({
providedIn: 'root',
})
export class ToastService {
currentId = 0;
toasts: ToastInfo[] = [];
show(header: string, body: string, classname?: string) {
const id = ++this.currentId;
this.toasts.push({ id, header, body, classname });
return id;
}
hide(id: number) {
const index = this.toasts.findIndex((t) => t.id === id);
if (index !== -1) {
this.toasts.splice(index, 1);
}
}
error(message: string) {
this.show('错误', message, 'bg-danger text-light');
}
warn(message: string) {
this.show('警告', message, 'bg-warning');
}
success(message?: string) {
this.show('成功', message || '操作成功', 'bg-success text-light');
}
attention(message: string) {
this.show('注意', message, 'bg-primary');
}
info(message: string) {
this.show('消息', message);
}
constructor() {}
}
<ngb-toast
*ngFor="let toast of toastService.toasts"
[class]="toast.classname"
[header]="toast.header" [autohide]="!toast.persist" [delay]="5000"
(hidden)="toastService.hide(toast.id)"
class="ngb-toasts"
>{{toast.body}}</ngb-toast>
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ToastComponent } from './toast.component';
describe('ToastComponent', () => {
let component: ToastComponent;
let fixture: ComponentFixture<ToastComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ToastComponent],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ToastComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
import { ToastService } from '../toast.service';
@Component({
selector: 'app-toasts',
templateUrl: './toast.component.html',
styleUrls: ['./toast.component.css'],
})
export class ToastComponent implements OnInit {
constructor(public toastService: ToastService) {}
ngOnInit(): void {}
}
src/favicon.ico

948 Bytes | W: | H:

src/favicon.ico

264 KB | W: | H:

src/favicon.ico
src/favicon.ico
src/favicon.ico
src/favicon.ico
  • 2-up
  • Swipe
  • Onion skin
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Wenyuanwall</title> <title>蔷蔷挂人查询</title>
<base href="/"> <base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
......
/***************************************************************************************************
* Load `$localize` onto the global scope - used if i18n tags appear in Angular templates.
*/
import '@angular/localize/init';
/** /**
* This file includes polyfills needed by Angular and is loaded before the app. * This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file. * You can add your own extra polyfills to this file.
......
/* You can add global styles to this file, and also import other style files */ /* You can add global styles to this file, and also import other style files */
@import '~bootstrap';
body {
min-height: 100vh;
min-height: -webkit-fill-available;
}
html {
height: -webkit-fill-available;
}
/*干掉站长统计的文本*/
a[title="站长统计"] {
display: none;
}
/*标题*/
h1.title {
font-family: 'Helvetica Neue', Helvetica, 'Microsoft Yahei', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', sans-serif;
font-size: 22px;
padding-bottom: 15px;
border-bottom: 1px solid #eee;
}
.index .navbar-nav>li.index>a, .index .navbar-nav>li.index>a:focus, .index .navbar-nav>li.index>a:hover,
.download .navbar-nav>li.download>a, .download .navbar-nav>li.download>a:focus, .download .navbar-nav>li.download>a:hover,
.usage .navbar-nav>li.usage>a, .usage .navbar-nav>li.usage>a:focus, .usage .navbar-nav>li.usage>a:hover,
.changelog .navbar-nav>li.changelog>a, .changelog .navbar-nav>li.changelog>a:focus, .changelog .navbar-nav>li.changelog>a:hover,
.bugs .navbar-nav>li.bugs>a, .bugs .navbar-nav>li.bugs>a:focus, .bugs .navbar-nav>li.bugs>a:hover,
.lab .navbar-nav>li.lab>a, .lab .navbar-nav>li.lab>a:focus, .lab .navbar-nav>li.lab>a:hover,
.pre .navbar-nav>li.pre>a, .pre .navbar-nav>li.pre>a:focus, .pre .navbar-nav>li.pre>a:hover
{
color: #555;
background-color: #e7e7e7;
}
h1.title .date {
font-size: 14px;
float: right;
padding-top: 10px;
}
h2.title {
font-family: 'Helvetica Neue', Helvetica, 'Microsoft Yahei', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', sans-serif;
font-size: 16px;
padding: 8px 0 8px 8px;
border-left: 2px solid #ddd;
}
footer {
/*margin: 100px 0 10px 0;*/
color: #767676;
text-align: center;
}
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