This commit is contained in:
sx1989827 2021-12-27 21:59:34 +08:00
parent 867d1595a6
commit 0e724bd185
41 changed files with 619 additions and 68 deletions

View File

@ -1,12 +1,10 @@
export interface ICommon_Model_Field { export interface ICommon_Model_Field {
id:string, id:string,
type_id:string, type_id:string,
system:number, reserved:number,
description:string, description:string,
created_time:Date, created_time:Date,
modified_time:Date, modified_time:Date,
created_by:string,
modified_by:string,
name:string name:string
} }
export const Table_Field="field" export const Table_Field="field"

View File

@ -2,14 +2,8 @@ import { BaseModel } from "./base"
export interface ICommon_Model_Field_Component_Field { export interface ICommon_Model_Field_Component_Field {
id:string, id:string,
type_id:string, field_component_id:string,
system:number, field_id:string
description:string,
created_time:Date,
modified_time:Date,
created_by:string,
modified_by:string,
name:string
} }
export const Table_Field_Component_Field="field_component_field" export const Table_Field_Component_Field="field_component_field"

View File

@ -6,6 +6,6 @@ export interface ICommon_Model_Field_Solution {
modified_by: string, modified_by: string,
name :string, name :string,
description :string, description :string,
system :number, reserved :number,
} }
export const Table_Field_Solution="field_solution" export const Table_Field_Solution="field_solution"

View File

@ -1,8 +1,19 @@
import { BaseModel } from "./base"
export interface ICommon_Model_Issue_Type { export interface ICommon_Model_Issue_Type {
id:string, id:string,
name:string, name:string,
icon:string, icon:string,
description:string, description:string,
multi:number reserved:number,
created_time:Date,
modify_time:Date,
} }
export const Table_Issue_Type="issue_type" export const Table_Issue_Type="issue_type"
class IssueTypeModel extends BaseModel {
table=Table_Issue_Type
model=<ICommon_Model_Issue_Type>{}
}
export let issueTypeModel=new IssueTypeModel

View File

@ -1,11 +1,18 @@
import { BaseModel } from "./base"
export interface ICommon_Model_Issue_Type_Solution { export interface ICommon_Model_Issue_Type_Solution {
id :string , id :string ,
name :string, name :string,
description :string, description :string,
system :number, reserved :number,
created_time :Date, created_time :Date,
modified_time :Date, modified_time :Date,
created_by :string ,
modified_by :string ,
} }
export const Table_Issue_Type_Solution="issue_type_solution" export const Table_Issue_Type_Solution="issue_type_solution"
class IssueTypeSolutionModel extends BaseModel {
table=Table_Issue_Type_Solution
model=<ICommon_Model_Issue_Type_Solution>{}
}
export let issueTypeSolutionModel=new IssueTypeSolutionModel

View File

@ -1,6 +1,15 @@
export interface ICommon_Model_Issue_Type { import { BaseModel } from "./base"
export interface ICommon_Model_Issue_Type_Solution_Issue_Type {
id :string , id :string ,
issue_type_id :string, issue_type_id :string,
issue_type_solution_id :string, issue_type_solution_id :string,
} }
export const Table_Issue_Type="issue_type" export const Table_Issue_Type_Solution_Issue_Type="issue_type"
class IssueTypeSolutionIssueTypeModel extends BaseModel {
table=Table_Issue_Type_Solution_Issue_Type
model=<ICommon_Model_Issue_Type_Solution_Issue_Type>{}
}
export let issueTypeSolutionIssueTypeModel=new IssueTypeSolutionIssueTypeModel

View File

@ -2,10 +2,8 @@ export interface ICommon_Model_Workflow {
id :string , id :string ,
name :string, name :string,
description :string, description :string,
system :number, reserved :number,
created_time :Date, created_time :Date,
modified_time :Date, modified_time :Date,
created_by :string ,
modified_by :string ,
} }
export const Table_Workflow="workflow" export const Table_Workflow="workflow"

View File

@ -1,7 +1,7 @@
export interface ICommon_Model_Workflow_Action { export interface ICommon_Model_Workflow_Action {
id :string , id :string ,
name :string, name :string,
system :number, reserved :number,
description :string, description :string,
source_node_id :string , source_node_id :string ,
dest_node_id :string , dest_node_id :string ,

View File

@ -2,7 +2,7 @@ export interface ICommon_Model_Workflow_Node {
id :string , id :string ,
name :string, name :string,
description :string, description :string,
system :number, reserved :number,
status :number, status :number,
workflow_id :string , workflow_id :string ,
} }

View File

@ -2,9 +2,7 @@ export interface ICommon_Model_Workflow_Solution {
id :string , id :string ,
created_time :Date, created_time :Date,
modified_time :Date, modified_time :Date,
created_by :string , reserved :number,
modified_by :string,
system :number,
name :string, name :string,
description :string, description :string,
} }

View File

@ -0,0 +1,55 @@
import { ICommon_Model_Issue_Type } from './../model/issue_type';
import { ECommon_Services } from './../types';
import { ECommon_HttpApi_Method } from "./types";
const api={
baseUrl:"/issuetype",
service:ECommon_Services.Cooperation,
routes:{
list:{
method:ECommon_HttpApi_Method.GET,
path:"/list",
req:<{
}>{},
res:<ICommon_Model_Issue_Type[]>{}
},
info:{
method:ECommon_HttpApi_Method.GET,
path:"/item",
req:<{
issueTypeId:string
}>{},
res:<ICommon_Model_Issue_Type>{}
},
create:{
method:ECommon_HttpApi_Method.POST,
path:"/item",
req:<{
name:string,
icon?:string,
description?:string
}>{},
res:<ICommon_Model_Issue_Type>{}
},
update:{
method:ECommon_HttpApi_Method.PUT,
path:"/item",
req:<{
issueTypeId:string,
name?:string,
icon?:string,
description?:string
}>{},
res:<ICommon_Model_Issue_Type>{}
},
delete:{
method:ECommon_HttpApi_Method.DELETE,
path:"/item",
req:<{
issueTypeId:string
}>{},
res:{}
},
}
}
export=api

View File

@ -23,7 +23,7 @@ const api={
req:<{ req:<{
keyword :string, keyword :string,
name :string, name :string,
image? :string, photo? :string,
description? :string, description? :string,
}>{}, }>{},
res:<ICommon_Model_Project>{} res:<ICommon_Model_Project>{}
@ -34,7 +34,7 @@ const api={
req:<{ req:<{
keyword? :string, keyword? :string,
name? :string, name? :string,
image? :string, photo? :string,
description? :string, description? :string,
projectId:string projectId:string
}>{}, }>{},
@ -173,7 +173,8 @@ const api={
req:<{ req:<{
keyword?:string, keyword?:string,
page:number, page:number,
size:number size:number,
userId?:string
}>{}, }>{},
res:<ICommon_Route_Res_Project_List>{}, res:<ICommon_Route_Res_Project_List>{},
}, },

View File

@ -100,6 +100,18 @@ const api={
}>{}, }>{},
res:<ICommon_Route_Res_Team_List>{}, res:<ICommon_Route_Res_Team_List>{},
}, },
filterTeam:{
method:ECommon_HttpApi_Method.GET,
path:"/filter",
req:<{
name:string
}>{},
res:<{
name:string,
id:string,
photo:string
}[]>{},
}
} }
} }
export=api export=api

View File

@ -133,6 +133,26 @@ const api={
userId?:string userId?:string
}>{}, }>{},
res:<ICommon_Route_Res_User_Profile>{}, res:<ICommon_Route_Res_User_Profile>{},
},
infos:{
method:ECommon_HttpApi_Method.GET,
path:"/infos",
req:<{
userIds:string
}>{},
res:<Omit<ICommon_Model_User,"password"|"created_time"|"modified_time">[]>{},
},
filterUser:{
method:ECommon_HttpApi_Method.GET,
path:"/filter",
req:<{
name:string
}>{},
res:<{
name:string,
id:string,
photo:string
}[]>{},
} }
} }
} }

View File

@ -91,6 +91,16 @@ export namespace Err {
code:3301, code:3301,
msg:"member not exists" msg:"member not exists"
} }
},
Issue : {
issueTypeNotFound:{
code:3400,
msg:"issue type not found"
},
issueTypeForbidden:{
code:3401,
msg:"issue type forbidden"
}
} }
} }
export let Team = { export let Team = {

View File

@ -3,6 +3,12 @@ import { Err } from '../../../common/status/error';
import { EServer_Common_Event_Types } from '../event/types'; import { EServer_Common_Event_Types } from '../event/types';
import { emitServiceEvent } from '../rpc/rpc'; import { emitServiceEvent } from '../rpc/rpc';
import { Mapper } from './mapper'; import { Mapper } from './mapper';
let imagefields=[
"photo",
"image",
"img",
"icon"
]
export abstract class Entity<T extends BaseModel,M extends Mapper<T>> { export abstract class Entity<T extends BaseModel,M extends Mapper<T>> {
protected item:T["model"]; protected item:T["model"];
protected _item:T["model"]; protected _item:T["model"];
@ -20,9 +26,9 @@ export abstract class Entity<T extends BaseModel,M extends Mapper<T>> {
setItem(item:T["model"]) { setItem(item:T["model"]) {
this.item=item this.item=item
} }
assignItem(item:Partial<T["model"]>) { assignItem(item:Partial<T["model"]>,clear:boolean=false) {
if(typeof(item)=="object") { if(typeof(item)=="object") {
if(!this.item) { if(!this.item || clear) {
this.item=<T>{} this.item=<T>{}
} }
for(let key in item) { for(let key in item) {
@ -41,9 +47,11 @@ export abstract class Entity<T extends BaseModel,M extends Mapper<T>> {
} }
await this.mapper.create(this.item) await this.mapper.create(this.item)
await this.loadItem(); await this.loadItem();
if(this.item["photo"]) { imagefields.forEach(item=>{
emitServiceEvent(EServer_Common_Event_Types.File.REF,this.item["photo"]) if(this.item[item]) {
} emitServiceEvent(EServer_Common_Event_Types.File.REF,this.item[item])
}
})
return this.item; return this.item;
} }
async update():Promise<T["model"]>{ async update():Promise<T["model"]>{
@ -52,14 +60,17 @@ export abstract class Entity<T extends BaseModel,M extends Mapper<T>> {
} }
let ret=await this.mapper.getById(this.item.id) let ret=await this.mapper.getById(this.item.id)
await this.mapper.update(this.item) await this.mapper.update(this.item)
if(!ret["photo"] && this.item["photo"]) { imagefields.forEach(item=>{
emitServiceEvent(EServer_Common_Event_Types.File.REF,this.item["photo"]) if(!ret[item] && this.item[item]) {
} else if(ret["photo"] && ret["photo"]!=this.item["photo"]) { emitServiceEvent(EServer_Common_Event_Types.File.REF,this.item[item])
if(this.item["photo"]) { } else if(ret[item] && ret[item]!=this.item[item]) {
emitServiceEvent(EServer_Common_Event_Types.File.REF,this.item["photo"]) if(this.item[item]) {
emitServiceEvent(EServer_Common_Event_Types.File.REF,this.item[item])
}
emitServiceEvent(EServer_Common_Event_Types.File.UNREF,ret[item])
} }
emitServiceEvent(EServer_Common_Event_Types.File.UNREF,ret["photo"]) })
} await this.loadItem();
return this.item; return this.item;
} }
async delete(eventPulish?:EServer_Common_Event_Types.Types){ async delete(eventPulish?:EServer_Common_Event_Types.Types){
@ -67,9 +78,12 @@ export abstract class Entity<T extends BaseModel,M extends Mapper<T>> {
if(eventPulish) { if(eventPulish) {
emitServiceEvent(eventPulish,this.item.id); emitServiceEvent(eventPulish,this.item.id);
} }
if(this.item["photo"]) { imagefields.forEach(item=>{
emitServiceEvent(EServer_Common_Event_Types.File.UNREF,this.item["photo"]) if(this.item[item]) {
} emitServiceEvent(EServer_Common_Event_Types.File.UNREF,this.item[item])
}
})
} }
async loadItem():Promise<T["model"]>{ async loadItem():Promise<T["model"]>{
if(!this.item || !this.item.id) { if(!this.item || !this.item.id) {

View File

@ -28,7 +28,9 @@ export abstract class Mapper<T extends BaseModel> {
return ret return ret
} }
async updateConfig(info:T["model"]){} async updateConfig(info:T["model"]){}
async update(info:T["model"]):Promise<void> { async update(data:T["model"]):Promise<void> {
let info:T["model"]={}
Object.assign(info,data)
if(!info.id) { if(!info.id) {
throw Err.Common.itemNotFound throw Err.Common.itemNotFound
} }

View File

@ -1,5 +1,5 @@
export namespace EServer_Common_Event_Types { export namespace EServer_Common_Event_Types {
export type Types= User|Project|Team|File export type Types= User|Project|Team|File|IssueType
export enum User { export enum User {
DELETE="delete user" //userId:string DELETE="delete user" //userId:string
} }
@ -13,4 +13,7 @@ export namespace EServer_Common_Event_Types {
REF="ref file", REF="ref file",
UNREF="unref file" //fileId:string UNREF="unref file" //fileId:string
} }
export enum IssueType {
DELETE="delete issueType" //issueTypeId:string
}
} }

View File

@ -0,0 +1,5 @@
export default interface IServer_Common_RPC_File {
getPath?(fileId:string):Promise<string>
getPaths?(fileIds:string[]):Promise<string[]>
}

View File

@ -36,9 +36,13 @@ function handleExp(key:string,value:EXPRVALUEEXP,arrExpr:string[]) {
} else if(value.exp=="is null") { } else if(value.exp=="is null") {
arrExpr.push(`${key} is null`) arrExpr.push(`${key} is null`)
} else if(value.exp=="in") { } else if(value.exp=="in") {
arrExpr.push(`${key} in (${(<string[] | number[]>value.value).map((item)=>{ if(typeof(value.value)=="string") {
return typeof(item)=="number"?item:("'"+item+"'") arrExpr.push(`${key} in (${value.value})`)
}).join(",")})`) } else {
arrExpr.push(`${key} in (${(<string[] | number[]>value.value).map((item)=>{
return typeof(item)=="number"?item:("'"+item+"'")
}).join(",")})`)
}
} else if(value.exp=="is not null") { } else if(value.exp=="is not null") {
arrExpr.push(`${key} is not null`) arrExpr.push(`${key} is not null`)
} else if(value.exp=="between") { } else if(value.exp=="between") {
@ -575,4 +579,19 @@ export function exculdeColumns<R1 extends keyof BaseModel["model"],R2 extends R1
}) })
return <any>arr; return <any>arr;
} }
}
export function generateCountSql<T extends BaseModel>(model:T,objExpr?:{
[param in keyof T["model"]]?:EXPRVALUE
},exprMode?:"and"|"or"):{
value:string,
type:{
[key in keyof T["model"]]:T["model"][key]
}
} {
let expr=generateExp(objExpr,exprMode);
return {
value:`select count(1) from ${model.table}${expr?(" where "+expr):""}`,
type:model.model
}
} }

View File

@ -1,4 +1,5 @@
import Application from "../../common/app/app"; import Application from "../../common/app/app";
import "../http/issueType";
import "../http/module"; import "../http/module";
import "../http/project"; import "../http/project";
import "../http/tag"; import "../http/tag";

View File

@ -0,0 +1,67 @@
import * as issueTypeApi from "../../../common/routes/issueType";
import { Err } from "../../../common/status/error";
import { DComponent } from "../../common/decorate/component";
import { DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired } from "../../common/http/http";
import IssueTypeService from "../service/issueType";
@DComponent
@DHttpController(issueTypeApi)
class IssueTypeController {
@DHttpApi(issueTypeApi.routes.list)
async list():Promise<typeof issueTypeApi.routes.list.res> {
let ret=await IssueTypeService.list()
return ret;
}
@DHttpApi(issueTypeApi.routes.info)
async info(@DHttpReqParamRequired("issueTypeId") issueTypeId:string):Promise<typeof issueTypeApi.routes.info.res> {
let ret=await IssueTypeService.getItemById(issueTypeId)
if(!ret) {
throw Err.Project.Issue.issueTypeNotFound
}
return ret.getItem();
}
@DHttpApi(issueTypeApi.routes.create)
async create(@DHttpReqParamRequired("name") name:string,@DHttpReqParam("icon") icon:string,@DHttpReqParam("description") description:string):Promise<typeof issueTypeApi.routes.create.res> {
let obj=new IssueTypeService()
obj.assignItem({
name,
icon,
description
})
let ret=await obj.create()
return ret;
}
@DHttpApi(issueTypeApi.routes.update)
async update(@DHttpReqParamRequired("issueTypeId") issueTypeId:string,@DHttpReqParam("name") name:string,@DHttpReqParam("icon") icon:string,@DHttpReqParam("description") description:string):Promise<typeof issueTypeApi.routes.update.res> {
let obj=await IssueTypeService.getItemById(issueTypeId)
if(!obj) {
throw Err.Project.Issue.issueTypeNotFound
}
if(obj.getItem().reserved) {
throw Err.Project.Issue.issueTypeForbidden
}
obj.assignItem({
id:issueTypeId,
name,
icon,
description
},true)
let ret=await obj.update()
return ret;
}
@DHttpApi(issueTypeApi.routes.delete)
async delete(@DHttpReqParamRequired("issueTypeId") issueTypeId:string,@DHttpReqParam("name") name:string,@DHttpReqParam("icon") icon:string,@DHttpReqParam("description") description:string):Promise<typeof issueTypeApi.routes.delete.res> {
let obj=await IssueTypeService.getItemById(issueTypeId)
if(!obj) {
throw Err.Project.Issue.issueTypeNotFound
}
if(obj.getItem().reserved) {
throw Err.Project.Issue.issueTypeForbidden
}
await obj.delete()
return;
}
}

View File

@ -3,6 +3,7 @@ import * as projectApi from "../../../common/routes/project";
import { Err } from "../../../common/status/error"; import { Err } from "../../../common/status/error";
import { DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired, DHttpUser } from "../../common/http/http"; import { DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired, DHttpUser } from "../../common/http/http";
import { IUserSession } from "../../common/rpc/api/user"; import { IUserSession } from "../../common/rpc/api/user";
import { EServer_Common_User_Type } from "../../common/types/user";
import ProjectService from "../service/project"; import ProjectService from "../service/project";
@DHttpController(projectApi) @DHttpController(projectApi)
@ -96,8 +97,14 @@ class ProjectController {
} }
@DHttpApi(projectApi.routes.list) @DHttpApi(projectApi.routes.list)
async list(@DHttpReqParam("keyword") keyword:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number) :Promise<typeof projectApi.routes.list.res>{ async list(@DHttpReqParam("keyword") keyword:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number,@DHttpReqParam("userId") userId:string,@DHttpUser userInfo:IUserSession) :Promise<typeof projectApi.routes.list.res>{
let list=await ProjectService.list(page,size,keyword) let user=""
if(userInfo.type==EServer_Common_User_Type.ADMIN && userId) {
user=userId
} else if(userInfo.type==EServer_Common_User_Type.USER) {
user=userInfo.userId
}
let list=await ProjectService.list(page,size,keyword,user)
return list return list
} }

View File

@ -0,0 +1,19 @@
import { getMysqlInstance } from "../../common/db/mysql";
import { Mapper } from "../../common/entity/mapper";
import { generateQuerySql } from "../../common/util/sql";
import { ICommon_Model_Issue_Type, issueTypeModel } from './../../../common/model/issue_type';
class IssueTypeMapper extends Mapper<typeof issueTypeModel> {
constructor() {
super(issueTypeModel)
}
async list():Promise<ICommon_Model_Issue_Type[]>
{
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(issueTypeModel,[],null,null,{
field:"name",
type:"asc"
}))
return ret;
}
}
export let issueTypeMapper=new IssueTypeMapper

View File

@ -181,7 +181,7 @@ class ProjectMapper extends Mapper<typeof projectModel>{
})) }))
} }
async list(page:number,size:number,keyword?:string):Promise<{ async list(page:number,size:number,keyword?:string,userId?:string):Promise<{
count:number, count:number,
totalPage:number, totalPage:number,
data:ICommon_Model_Project[] data:ICommon_Model_Project[]
@ -190,14 +190,36 @@ class ProjectMapper extends Mapper<typeof projectModel>{
throw Err.Common.paramError throw Err.Common.paramError
} }
var mysql=getMysqlInstance(); var mysql=getMysqlInstance();
let count=Object.values(await mysql.executeOne<number>(`select count(1) from ${Table_Project}${keyword?` where name like '%${keyword}%'`:""}`))[0] let str=`select count(1) from ${Table_Project}`,keywrodStr="",userIdStr=""
if(keyword) {
keywrodStr=`name like '%${keyword}%'`
}
if(userId) {
userIdStr=`id in (select project_id from ${Table_Project_Member} where member_id='${userId}')`
}
if(keywrodStr && userIdStr) {
str+=" where "+keywrodStr+" and "+userIdStr
} else if(keywrodStr) {
str+=" where "+keywrodStr
} else if(userIdStr) {
str+=" where "+userIdStr
}
let count=Object.values(await mysql.executeOne<number>(str))[0]
let totalPage=CommonUtil.pageTotal(count,size) let totalPage=CommonUtil.pageTotal(count,size)
let ret=await mysql.execute(generateQuerySql(projectModel,[],keyword?{ let ret=await mysql.execute(generateQuerySql(projectModel,[],{
name:{ ...(keyword && {
exp:"%like%", name:{
value:keyword exp:"%like%",
} value:keyword
}:null,"and",{ }
}),
...(userId && {
id:{
exp:"in",
value:`select project_id from ${Table_Project_Member} where member_id='${userId}'`
}
})
},"and",{
field:"name", field:"name",
type:"asc" type:"asc"
},page*size,size)) },page*size,size))

View File

@ -0,0 +1,12 @@
import { Entity } from "../../common/entity/entity";
import { issueTypeModel } from './../../../common/model/issue_type';
import { issueTypeMapper } from './../mapper/issueType';
export default class IssueType extends Entity<typeof issueTypeModel,typeof issueTypeMapper> {
constructor(){
super(issueTypeMapper)
}
static async list(){
let ret=await issueTypeMapper.list()
return ret;
}
}

View File

@ -36,8 +36,8 @@ export default class Project extends Entity<typeof projectModel,typeof projectMa
await projectMapper.changeRole(this.item.id,memberId,roleId) await projectMapper.changeRole(this.item.id,memberId,roleId)
} }
static async list(page:number,size:number,keyword?:string):Promise<ICommon_Route_Res_Project_List>{ static async list(page:number,size:number,keyword?:string,userId?:string):Promise<ICommon_Route_Res_Project_List>{
let ret=await projectMapper.list(page,size,keyword) let ret=await projectMapper.list(page,size,keyword,userId)
return { return {
count:ret.count, count:ret.count,
totalPage:ret.totalPage, totalPage:ret.totalPage,

View File

@ -6,6 +6,7 @@ import CommonUtil from "../../common/util/common";
import { generateDeleteSql } from "../../common/util/sql"; import { generateDeleteSql } from "../../common/util/sql";
import "../event/file"; import "../event/file";
import "../http/file"; import "../http/file";
import "../rpc/file";
import { ECommon_Model_File_Type, fileModel, ICommon_Model_File, Table_File } from './../../../common/model/file'; import { ECommon_Model_File_Type, fileModel, ICommon_Model_File, Table_File } from './../../../common/model/file';
import path = require("path"); import path = require("path");
export default class File extends Application { export default class File extends Application {

View File

@ -15,6 +15,20 @@ class FileMapper extends Mapper<typeof fileModel> {
let ret=await mysql.executeOne(generateQuerySql(fileModel,[],{md5:md5})) let ret=await mysql.executeOne(generateQuerySql(fileModel,[],{md5:md5}))
return ret return ret
} }
async getPaths(ids:string[]) {
if(!ids) {
throw Err.File.fileNotFound
}
var mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(fileModel,[],{
id:{
exp:"in",
value:ids
}
}))
return ret;
}
} }
export let fileMapper=new FileMapper() export let fileMapper=new FileMapper()

View File

@ -0,0 +1,25 @@
import IServer_Common_RPC_File from "../../common/rpc/api/file";
import { DRPCRecieve } from "../../common/rpc/rpc";
import FileService from "../service/file";
class RpcFileApi implements IServer_Common_RPC_File {
@DRPCRecieve
async getPath(fileId: string): Promise<string> {
if(!fileId) {
return ""
}
let obj=await FileService.getItemById(fileId)
if(!obj) {
return ""
}
return "/file"+obj.getItem().path
}
@DRPCRecieve
async getPaths(fileIds: string[]): Promise<string[]> {
if(!fileIds || fileIds.length==0) {
return []
}
let obj=await FileService.getPaths(fileIds)
return obj;
}
}
export default new RpcFileApi;

View File

@ -30,4 +30,15 @@ export default class File extends Entity<typeof fileModel,typeof fileMapper> {
await super.create() await super.create()
return this.item.id; return this.item.id;
} }
static async getPaths(ids:string[]){
let ret=await fileMapper.getPaths(ids);
return ret.map(item=>{
if(item && item.path) {
return "/file"+item.path
} else {
return ""
}
})
}
} }

View File

@ -5,6 +5,7 @@ import * as koaStaticServer from "koa-static-server";
import { PassThrough } from "stream"; import { PassThrough } from "stream";
import { Permission_Base } from '../../../common/permission/permission'; import { Permission_Base } from '../../../common/permission/permission';
import * as fileApi from "../../../common/routes/file"; import * as fileApi from "../../../common/routes/file";
import * as issueTypeApi from "../../../common/routes/issueType";
import * as projectApi from "../../../common/routes/project"; import * as projectApi from "../../../common/routes/project";
import * as teamApi from "../../../common/routes/team"; import * as teamApi from "../../../common/routes/team";
import { ICommon_HttpApi } from "../../../common/routes/types"; import { ICommon_HttpApi } from "../../../common/routes/types";
@ -22,10 +23,10 @@ import { EServer_Common_User_Type } from '../../common/types/user';
import CommonUtil from "../../common/util/common"; import CommonUtil from "../../common/util/common";
import { generateHttpErrorResponse, generateHttpOkResponse } from "../../common/util/http"; import { generateHttpErrorResponse, generateHttpOkResponse } from "../../common/util/http";
import userRpcApi from '../rpc/user'; import userRpcApi from '../rpc/user';
import { initSystem, parseFormData } from "../util/util"; import { handleImageFields, initSystem, parseFormData } from "../util/util";
import { ICommon_Version_Config } from './../../../common/model/version'; import { ICommon_Version_Config } from './../../../common/model/version';
import { CacheService } from './../cache/service'; import { CacheService } from './../cache/service';
var apis:ICommon_HttpApi[]=[userApi,projectApi,teamApi,fileApi]; var apis:ICommon_HttpApi[]=[userApi,projectApi,teamApi,fileApi,issueTypeApi];
var app = new Koa(); var app = new Koa();
var config=<ICommon_Version_Config>{} var config=<ICommon_Version_Config>{}
var pipe = function (from, to): Promise<Buffer> { var pipe = function (from, to): Promise<Buffer> {
@ -129,10 +130,10 @@ export default class GateWay extends Application {
app.use(async function (ctx, next) { app.use(async function (ctx, next) {
let path = ctx.path let path = ctx.path
if(path.startsWith("/api/")) { if(path.startsWith("/api/")) {
path = path.substr("/api".length) path = path.substring("/api".length)
let method = ctx.req.method; let method = ctx.req.method;
let baseUrl = path.substring(1, path.indexOf("/", 1)) let baseUrl = path.substring(1, path.indexOf("/", 1))
let apiPath = path.substr(1 + baseUrl.length) let apiPath = path.substring(1 + baseUrl.length)
if (apiMap[baseUrl] && apiMap[baseUrl][method + " " + apiPath]) { if (apiMap[baseUrl] && apiMap[baseUrl][method + " " + apiPath]) {
let microServer = apiMap[baseUrl][method + " " + apiPath].service let microServer = apiMap[baseUrl][method + " " + apiPath].service
let ignoreValidate = apiMap[baseUrl][method + " " + apiPath].ignoreValidate let ignoreValidate = apiMap[baseUrl][method + " " + apiPath].ignoreValidate
@ -191,6 +192,9 @@ export default class GateWay extends Application {
} }
if(ret.data===undefined || typeof(ret.data)=="string" || typeof(ret.data)=="number" || typeof(ret.data)=="boolean" || typeof(ret.data)=="object") if(ret.data===undefined || typeof(ret.data)=="string" || typeof(ret.data)=="number" || typeof(ret.data)=="boolean" || typeof(ret.data)=="object")
{ {
if(typeof(ret.data)=="object") {
await handleImageFields(ret.data);
}
ctx.body = generateHttpOkResponse(ret.data); ctx.body = generateHttpOkResponse(ret.data);
} else { } else {
ctx.body = ret.data; ctx.body = ret.data;

View File

@ -0,0 +1,10 @@
import { ECommon_Services } from '../../../common/types';
import IServer_Common_RPC_File from "../../common/rpc/api/file";
import { DRPCSend } from "../../common/rpc/rpc";
class RpcFileApi implements IServer_Common_RPC_File {
@DRPCSend(ECommon_Services.File)
async getPaths(fileIds: string[]): Promise<string[]> {
return null;
}
}
export default new RpcFileApi

View File

@ -5,6 +5,10 @@ import { Permission_Base, Permission_Types } from '../../../common/permission/pe
import { getMysqlInstance } from "../../common/db/mysql"; import { getMysqlInstance } from "../../common/db/mysql";
import { getNacosInstance } from '../../common/nacos/nacos'; import { getNacosInstance } from '../../common/nacos/nacos';
import { generateSnowId } from '../../common/util/sql'; import { generateSnowId } from '../../common/util/sql';
import rpcFileApi from '../rpc/file';
import { Table_Issue_Type } from './../../../common/model/issue_type';
import { Table_Issue_Type_Solution } from './../../../common/model/issue_type_solution';
import { Table_Issue_Type_Solution_Issue_Type } from './../../../common/model/issue_type_solution_issue_type';
import { Table_Permission } from './../../../common/model/permission'; import { Table_Permission } from './../../../common/model/permission';
import { Table_Project_Member } from './../../../common/model/project_member'; import { Table_Project_Member } from './../../../common/model/project_member';
import { Table_Project_Role } from './../../../common/model/project_role'; import { Table_Project_Role } from './../../../common/model/project_role';
@ -74,6 +78,41 @@ export function parseFormData(str: Buffer, boundary: string): IServer_GateWay_Fo
return ret; return ret;
} }
export async function handleImageFields(data:object){
let arr=<{
object:object,
key:string|number
}[]>[]
function _clone(o){
var k, b;
if(o && ((b = (o instanceof Array)) || o instanceof Object)) {
for(k in o){
if(o.hasOwnProperty(k)){
if(["photo","image","icon","img"].includes(k) && typeof(o[k])=="string" && o[k].length>=18 && /^\d+$/.test(o[k])) {
arr.push({
object:o,
key:k
})
} else {
_clone(o[k])
}
}
}
}
}
_clone(data)
if(arr.length>0) {
let ids=arr.map(item=>{
return item.object[item.key];
})
let paths=await rpcFileApi.getPaths(ids)
for(let i=0;i<arr.length;i++)
{
arr[i].object[arr[i].key]=paths[i]
}
}
}
async function resetSystem(){ async function resetSystem(){
let mysql=getMysqlInstance() let mysql=getMysqlInstance()
await mysql.execute(`delete from ${Table_Version}`) await mysql.execute(`delete from ${Table_Version}`)
@ -86,6 +125,9 @@ async function resetSystem(){
await mysql.execute(`delete from ${Table_Team_Role}`) await mysql.execute(`delete from ${Table_Team_Role}`)
await mysql.execute(`delete from ${Table_Team}`) await mysql.execute(`delete from ${Table_Team}`)
await mysql.execute(`delete from ${Table_Team_User}`) await mysql.execute(`delete from ${Table_Team_User}`)
await mysql.execute(`delete from ${Table_Issue_Type}`)
await mysql.execute(`delete from ${Table_Issue_Type_Solution}`)
await mysql.execute(`delete from ${Table_Issue_Type_Solution_Issue_Type}`)
} }
export async function initSystem() { export async function initSystem() {
@ -158,6 +200,9 @@ export async function initSystem() {
} }
} }
await mysql.execute(`insert into ${Table_Team_User} (id,role_id,team_id,user_id) values ('${await generateSnowId()}','${groupRoleUserId}','${groupId}','${userId}')`) await mysql.execute(`insert into ${Table_Team_User} (id,role_id,team_id,user_id) values ('${await generateSnowId()}','${groupRoleUserId}','${groupId}','${userId}')`)
await mysql.execute(`insert into ${Table_Issue_Type} (id,name,reserved) values ('${await generateSnowId()}','Task',1)`)
await mysql.execute(`insert into ${Table_Issue_Type} (id,name,reserved) values ('${await generateSnowId()}','Bug',1)`)
await mysql.execute(`insert into ${Table_Issue_Type} (id,name,reserved) values ('${await generateSnowId()}','Ticket',1)`)
} }
console.log("init finish") console.log("init finish")
} }

View File

@ -107,4 +107,10 @@ class TeamController {
return list return list
} }
@DHttpApi(teamApi.routes.filterTeam)
async filterTeam(@DHttpReqParamRequired("name") name:string) :Promise<typeof teamApi.routes.filterTeam.res>{
let ret=await TeamService.filter(name,10);
return ret;
}
} }

View File

@ -145,4 +145,16 @@ class UserController {
let ret=await user.profile() let ret=await user.profile()
return ret; return ret;
} }
@DHttpApi(userApi.routes.infos)
async infos(@DHttpReqParam("userIds") userIds:string) :Promise<typeof userApi.routes.infos.res>{
let ret=await UserService.userInfos(userIds)
return ret;
}
@DHttpApi(userApi.routes.filterUser)
async filterUser(@DHttpReqParamRequired("name") name:string) :Promise<typeof userApi.routes.filterUser.res>{
let ret=await UserService.filter(name,10);
return ret;
}
} }

View File

@ -194,6 +194,27 @@ class TeamMapper extends Mapper<typeof teamModel> {
data:ret data:ret
}; };
} }
async filter(name:string,size:number)
{
if(!name) {
throw Err.User.userNameNotExists
}
if(!size) {
throw Err.Common.paramError
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(teamModel,["id","name","photo"],{
name:{
exp:"%like%",
value:name
}
},"and",{
field:"name",
type:"asc"
},0,size))
return ret;
}
} }
export let teamMapper=new TeamMapper() export let teamMapper=new TeamMapper()

View File

@ -171,5 +171,41 @@ class UserMapper extends Mapper<typeof userModel> {
data:ret.map(item=>item.project) data:ret.map(item=>item.project)
}; };
} }
async users(userIds:string[]){
if(!userIds){
throw Err.User.userIdNotExists
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(userModel,[],{
id:{
exp:"in",
value:userIds
}
}))
return ret;
}
async filter(name:string,size:number)
{
if(!name) {
throw Err.User.userNameNotExists
}
if(!size) {
throw Err.Common.paramError
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(userModel,["id","username","photo"],{
admin:0,
active:1,
username:{
exp:"%like%",
value:name
}
},"and",{
field:"username",
type:"asc"
},0,size))
return ret;
}
} }
export let userMapper=new UserMapper() export let userMapper=new UserMapper()

View File

@ -0,0 +1,10 @@
import { ECommon_Services } from '../../../common/types';
import IServer_Common_RPC_File from "../../common/rpc/api/file";
import { DRPCSend } from "../../common/rpc/rpc";
class RpcFileApi implements IServer_Common_RPC_File {
@DRPCSend(ECommon_Services.File)
async getPath(fileId: string): Promise<string> {
return null;
}
}
export default new RpcFileApi

View File

@ -3,6 +3,7 @@ import { ICommon_Route_Res_Team_List } from '../../../common/routes/response';
import { Err } from '../../../common/status/error'; import { Err } from '../../../common/status/error';
import { Entity } from "../../common/entity/entity"; import { Entity } from "../../common/entity/entity";
import { teamMapper } from '../mapper/team'; import { teamMapper } from '../mapper/team';
import rpcFileApi from "../rpc/file";
import { teamModel } from './../../../common/model/team'; import { teamModel } from './../../../common/model/team';
export default class Team extends Entity<typeof teamModel,typeof teamMapper> { export default class Team extends Entity<typeof teamModel,typeof teamMapper> {
constructor(){ constructor(){
@ -61,4 +62,31 @@ export default class Team extends Entity<typeof teamModel,typeof teamMapper> {
} }
} }
static async filter(name:string,size:number):Promise<{
name:string,
id:string,
photo:string
}[]>{
if(!name) {
throw Err.User.userNameNotExists
}
if(!size) {
throw Err.Common.paramError
}
let ret=await teamMapper.filter(name,size);
let arr=<{
name:string,
id:string,
photo:string
}[]>[]
for(let obj of ret) {
arr.push({
name:obj.name,
id:obj.id,
photo:obj.photo?(await rpcFileApi.getPath(obj.photo)):obj.photo
})
}
return ret;
}
} }

View File

@ -5,7 +5,8 @@ import { REDIS_USER } from "../../common/cache/keys/user";
import { Entity } from "../../common/entity/entity"; import { Entity } from "../../common/entity/entity";
import { getNacosInstance } from '../../common/nacos/nacos'; import { getNacosInstance } from '../../common/nacos/nacos';
import { userMapper } from '../mapper/user'; import { userMapper } from '../mapper/user';
import { userModel } from './../../../common/model/user'; import rpcFileApi from "../rpc/file";
import { ICommon_Model_User, userModel } from './../../../common/model/user';
import { EServer_Common_User_Type } from './../../common/types/user'; import { EServer_Common_User_Type } from './../../common/types/user';
export default class User extends Entity<typeof userModel,typeof userMapper> { export default class User extends Entity<typeof userModel,typeof userMapper> {
constructor(){ constructor(){
@ -107,4 +108,47 @@ export default class User extends Entity<typeof userModel,typeof userMapper> {
delete ret.info.password delete ret.info.password
return ret; return ret;
} }
static async userInfos(userIds:string):Promise<Omit<ICommon_Model_User,"password"|"created_time"|"modified_time">[]>{
if(!userIds) {
throw Err.User.userIdNotExists
}
let ret=await userMapper.users(userIds.split(","))
for(let obj of ret) {
delete obj.password;
delete obj.created_time;
delete obj.modified_time;
if(obj.photo) {
obj.photo=await rpcFileApi.getPath(obj.photo)
}
}
return ret;
}
static async filter(name:string,size:number):Promise<{
name:string,
id:string,
photo:string
}[]>{
if(!name) {
throw Err.User.userNameNotExists
}
if(!size) {
throw Err.Common.paramError
}
let ret=await userMapper.filter(name,size);
let arr=<{
name:string,
id:string,
photo:string
}[]>[]
for(let obj of ret) {
arr.push({
name:obj.username,
id:obj.id,
photo:obj.photo?(await rpcFileApi.getPath(obj.photo)):obj.photo
})
}
return arr;
}
} }