21 changed files with 2037 additions and 91 deletions
@ -0,0 +1,5 @@ |
|||||
|
{ |
||||
|
"recommendations": [ |
||||
|
"MarsCode.marscode-extension" |
||||
|
] |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,442 @@ |
|||||
|
package rongxin |
||||
|
|
||||
|
import ( |
||||
|
"appPlatform/models/modelshr" |
||||
|
personalitycolor "appPlatform/models/personalityColor" |
||||
|
"appPlatform/overall" |
||||
|
"appPlatform/overall/publicmethod" |
||||
|
"encoding/csv" |
||||
|
"encoding/json" |
||||
|
"fmt" |
||||
|
"net/url" |
||||
|
"sort" |
||||
|
"strconv" |
||||
|
"strings" |
||||
|
|
||||
|
"github.com/gin-gonic/gin" |
||||
|
) |
||||
|
|
||||
|
/* |
||||
|
* |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2024-09-13 08:55:14 |
||||
|
@ 功能:下载九型人格测试结果 |
||||
|
@ 参数 |
||||
|
|
||||
|
# |
||||
|
|
||||
|
@ 返回值 |
||||
|
|
||||
|
# |
||||
|
|
||||
|
@ 方法原型 |
||||
|
|
||||
|
# |
||||
|
*/ |
||||
|
func (a *ApiMethod) DownLoadNineTestPage(c *gin.Context) { |
||||
|
|
||||
|
keywords := c.Query("keywords") |
||||
|
adminorg := c.Query("adminorg") |
||||
|
emptype := c.Query("emptype") |
||||
|
|
||||
|
var peopleList []modelshr.PersonArchives |
||||
|
goormDb := overall.CONSTANT_DB_HrInside.Model(&modelshr.PersonArchives{}).Select("`number`,`name`,`admin_org`").Where("`emp_type` BETWEEN 1 AND 10") |
||||
|
|
||||
|
if keywords != "undefined" && keywords != "" { |
||||
|
goormDb = goormDb.Where("`name` LIKE ?", "%"+keywords+"%") |
||||
|
} |
||||
|
if adminorg != "undefined" && adminorg != "" { |
||||
|
adminorgInt, _ := strconv.ParseInt(adminorg, 10, 64) |
||||
|
var sunOrg publicmethod.GetOrgAllParent |
||||
|
sunOrg.GetOrgSun(adminorgInt) |
||||
|
sunOrg.Id = append(sunOrg.Id, adminorgInt) |
||||
|
if len(sunOrg.Id) > 0 { |
||||
|
goormDb = goormDb.Where("`admin_org` IN ?", sunOrg.Id) |
||||
|
} |
||||
|
} |
||||
|
var empInt []int |
||||
|
json.Unmarshal([]byte(emptype), &empInt) |
||||
|
if len(empInt) > 0 { |
||||
|
goormDb = goormDb.Where("`emp_type` IN ?", empInt) |
||||
|
} |
||||
|
err := goormDb.Find(&peopleList).Error |
||||
|
if err != nil || len(peopleList) < 1 { |
||||
|
c.String(c.Writer.Status(), "没有查询到数据") |
||||
|
return |
||||
|
} |
||||
|
// fmt.Printf("%v-%v-%v-%v\n", keywords, adminorg, emptype, peopleList)
|
||||
|
|
||||
|
testPageList := GetPeopleNineData(peopleList) |
||||
|
// fmt.Printf("testPageList->%v\n", testPageList)
|
||||
|
var builder strings.Builder |
||||
|
builder.WriteString("\xEF\xBB\xBF") //写入UTF-8 BOM 防止乱码
|
||||
|
writer := csv.NewWriter(&builder) |
||||
|
writer.Write([]string{"团队角色盘点"}) |
||||
|
writer.Write([]string{"序号", "工号", "姓名", "行政组织", "第一角色", "第二角色", "第三角色", "第四角色"}) |
||||
|
|
||||
|
for i, v := range testPageList { |
||||
|
var scvBody []string |
||||
|
xuHao := strconv.Itoa(i + 1) |
||||
|
scvBody = append(scvBody, xuHao) |
||||
|
scvBody = append(scvBody, v...) |
||||
|
writer.Write(scvBody) |
||||
|
} |
||||
|
|
||||
|
writer.Flush() |
||||
|
fileName := fmt.Sprintf("团队角色盘点_%v.csv", publicmethod.GetUUid(1)) |
||||
|
c.Writer.Header().Add("Content-type", "application/octet-stream") |
||||
|
c.Header("Content-Type", "application/vnd.ms-excel;charset=utf8") |
||||
|
c.Header("Content-Disposition", "attachment; filename="+url.PathEscape(fileName)) |
||||
|
// c.Header("Content-Disposition", "attachment; filename=团队角色盘点.csv")
|
||||
|
c.Header("Content-Transfer-Encoding", "binary") |
||||
|
c.Writer.Write([]byte(builder.String())) |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2024-09-13 10:30:19 |
||||
|
@ 功能: 获取人员九型性格数据 |
||||
|
*/ |
||||
|
func GetPeopleNineData(user []modelshr.PersonArchives) (list [][]string) { |
||||
|
if len(user) < 1 { |
||||
|
return |
||||
|
} |
||||
|
var numAry []string |
||||
|
for _, v := range user { |
||||
|
numAry = append(numAry, v.Number) |
||||
|
} |
||||
|
var xgAry []personalitycolor.Charcolortest |
||||
|
overall.CONSTANT_DB_Color.Model(&personalitycolor.Charcolortest{}).Where("`c_class` = ? AND `c_number` IN ?", 10000003, numAry).Find(&xgAry) |
||||
|
|
||||
|
for i := 0; i < len(xgAry); i++ { |
||||
|
|
||||
|
if xgAry[i].TestJson != "" { |
||||
|
var testPage JieShouDaaning |
||||
|
err := json.Unmarshal([]byte(xgAry[i].TestJson), &testPage) |
||||
|
if err == nil { |
||||
|
scoreForEachItem := CalculateScoresForEachItem(testPage) |
||||
|
sort.Slice(scoreForEachItem, func(i, j int) bool { |
||||
|
return scoreForEachItem[i].Value > scoreForEachItem[j].Value |
||||
|
}) |
||||
|
var itemList []string |
||||
|
number, name, org := GetUserName(xgAry[i].Number, user) |
||||
|
itemList = append(itemList, number) |
||||
|
itemList = append(itemList, name) |
||||
|
itemList = append(itemList, org) |
||||
|
for j := 0; j < 4; j++ { |
||||
|
itemList = append(itemList, scoreForEachItem[j].Attribute) |
||||
|
} |
||||
|
list = append(list, itemList) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2024-09-13 11:17:14 |
||||
|
@ 功能: 获取人员姓名 |
||||
|
*/ |
||||
|
func GetUserName(num string, user []modelshr.PersonArchives) (number, name, org string) { |
||||
|
for _, v := range user { |
||||
|
if v.Number == num { |
||||
|
number = num |
||||
|
name = v.Name |
||||
|
org = GetOrgInfo(v.AdminOrg) |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2024-09-14 10:31:36 |
||||
|
@ 功能: 获取行政组织 |
||||
|
*/ |
||||
|
func GetOrgInfo(orgId int64) string { |
||||
|
var fatherOrg publicmethod.GetOrgAllParent |
||||
|
fatherOrg.GetOrgAllFatherId(orgId, 4) |
||||
|
var orgName []string |
||||
|
orgIdLen := len(fatherOrg.Id) |
||||
|
if orgIdLen > 0 { |
||||
|
for i := orgIdLen - 1; i >= 0; i-- { |
||||
|
if fatherOrg.Id[i] != 0 { |
||||
|
var orgInfo modelshr.AdministrativeOrganization |
||||
|
orgInfo.GetCont(map[string]interface{}{"`id`": fatherOrg.Id[i]}, "`name`") |
||||
|
if orgInfo.Name != "" { |
||||
|
orgName = append(orgName, orgInfo.Name) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if len(orgName) > 0 { |
||||
|
return strings.Join(orgName, "/") |
||||
|
} |
||||
|
return "" |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2024-09-13 10:49:43 |
||||
|
@ 功能: 计算各项得分 |
||||
|
*/ |
||||
|
func CalculateScoresForEachItem(testPage JieShouDaaning) (ScoreForEachItem []Character) { |
||||
|
PL := 0 |
||||
|
RI := 0 |
||||
|
CO := 0 |
||||
|
SH := 0 |
||||
|
ME := 0 |
||||
|
TW := 0 |
||||
|
IM := 0 |
||||
|
CF := 0 |
||||
|
SP := 0 |
||||
|
DR := 0 |
||||
|
for _, v := range testPage.List { |
||||
|
|
||||
|
for _, av := range v.Answer { |
||||
|
// fmt.Printf("PL:%v\n", av.Attribute)
|
||||
|
switch av.Attribute { |
||||
|
case "PL": |
||||
|
// fmt.Printf("PL:%v\n", av.Value)
|
||||
|
PL = PL + av.Value |
||||
|
case "RI": |
||||
|
RI = RI + av.Value |
||||
|
case "CO": |
||||
|
CO = CO + av.Value |
||||
|
case "SH": |
||||
|
SH = SH + av.Value |
||||
|
case "ME": |
||||
|
ME = ME + av.Value |
||||
|
case "TW": |
||||
|
TW = TW + av.Value |
||||
|
case "IM": |
||||
|
IM = IM + av.Value |
||||
|
case "CF": |
||||
|
CF = CF + av.Value |
||||
|
case "SP": |
||||
|
SP = SP + av.Value |
||||
|
case "DR": |
||||
|
DR = DR + av.Value |
||||
|
default: |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
var itemScorePL Character |
||||
|
itemScorePL.Title = "PL" |
||||
|
itemScorePL.Attribute = "创新智多星" |
||||
|
itemScorePL.Value = PL |
||||
|
ScoreForEachItem = append(ScoreForEachItem, itemScorePL) |
||||
|
|
||||
|
var itemScoreRI Character |
||||
|
itemScoreRI.Title = "RI" |
||||
|
itemScoreRI.Attribute = "资源调查员" |
||||
|
itemScoreRI.Value = RI |
||||
|
ScoreForEachItem = append(ScoreForEachItem, itemScoreRI) |
||||
|
|
||||
|
var itemScoreCO Character |
||||
|
itemScoreCO.Title = "CO" |
||||
|
itemScoreCO.Attribute = "协调者" |
||||
|
itemScoreCO.Value = CO |
||||
|
ScoreForEachItem = append(ScoreForEachItem, itemScoreCO) |
||||
|
|
||||
|
var itemScoreSH Character |
||||
|
itemScoreSH.Title = "SH" |
||||
|
itemScoreSH.Attribute = "鞭策者" |
||||
|
itemScoreSH.Value = SH |
||||
|
ScoreForEachItem = append(ScoreForEachItem, itemScoreSH) |
||||
|
|
||||
|
var itemScoreME Character |
||||
|
itemScoreME.Title = "ME" |
||||
|
itemScoreME.Attribute = "监督评论员" |
||||
|
itemScoreME.Value = ME |
||||
|
ScoreForEachItem = append(ScoreForEachItem, itemScoreME) |
||||
|
|
||||
|
var itemScoreTW Character |
||||
|
itemScoreTW.Title = "TW" |
||||
|
itemScoreTW.Attribute = "凝聚者" |
||||
|
itemScoreTW.Value = TW |
||||
|
ScoreForEachItem = append(ScoreForEachItem, itemScoreTW) |
||||
|
|
||||
|
var itemScoreIM Character |
||||
|
itemScoreIM.Title = "IM" |
||||
|
itemScoreIM.Attribute = "实干家" |
||||
|
itemScoreIM.Value = IM |
||||
|
ScoreForEachItem = append(ScoreForEachItem, itemScoreIM) |
||||
|
|
||||
|
var itemScoreCF Character |
||||
|
itemScoreCF.Title = "CF" |
||||
|
itemScoreCF.Attribute = "善始善终者" |
||||
|
itemScoreCF.Value = CF |
||||
|
ScoreForEachItem = append(ScoreForEachItem, itemScoreCF) |
||||
|
|
||||
|
var itemScoreSP Character |
||||
|
itemScoreSP.Title = "SP" |
||||
|
itemScoreSP.Attribute = "专家" |
||||
|
itemScoreSP.Value = SP |
||||
|
ScoreForEachItem = append(ScoreForEachItem, itemScoreSP) |
||||
|
|
||||
|
var itemScoreDR Character |
||||
|
itemScoreDR.Title = "DR" |
||||
|
itemScoreDR.Attribute = "DR" |
||||
|
itemScoreDR.Value = DR |
||||
|
ScoreForEachItem = append(ScoreForEachItem, itemScoreDR) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2024-09-19 14:17:00 |
||||
|
@ 功能: 下载人格测试状态 |
||||
|
@ 参数 |
||||
|
|
||||
|
# |
||||
|
|
||||
|
@ 返回值 |
||||
|
|
||||
|
# |
||||
|
|
||||
|
@ 方法原型 |
||||
|
|
||||
|
# |
||||
|
*/ |
||||
|
func (a *ApiMethod) StatisticsPersonality(c *gin.Context) { |
||||
|
var requestData CharacterStatis |
||||
|
c.ShouldBindJSON(&requestData) |
||||
|
if requestData.Typekey == "" { |
||||
|
requestData.Typekey = "10000001" |
||||
|
} |
||||
|
|
||||
|
keywords := c.Query("keywords") |
||||
|
adminorg := c.Query("org") |
||||
|
typekey := c.Query("typekey") |
||||
|
types := c.Query("types") |
||||
|
|
||||
|
typesInt, _ := strconv.Atoi(types) |
||||
|
|
||||
|
var xgNumber []string |
||||
|
overall.CONSTANT_DB_Color.Model(&personalitycolor.Charcolortest{}).Distinct("`c_number`").Where("`c_class` = ?", typekey).Find(&xgNumber) |
||||
|
|
||||
|
var peopleList []modelshr.PersonArchives |
||||
|
goormDb := overall.CONSTANT_DB_HrInside.Model(&modelshr.PersonArchives{}).Select("`number`,`name`,`company`,`maindeparment`,`admin_org`").Where("`emp_type` BETWEEN 1 AND 10") |
||||
|
|
||||
|
if keywords != "undefined" && keywords != "" { |
||||
|
goormDb = goormDb.Where("`name` LIKE ? OR `number` LIKE ?", "%"+keywords+"%", "%"+keywords+"%") |
||||
|
} |
||||
|
if adminorg != "undefined" && adminorg != "0" && adminorg != "" { |
||||
|
adminorgInt, _ := strconv.ParseInt(adminorg, 10, 64) |
||||
|
var sunOrg publicmethod.GetOrgAllParent |
||||
|
sunOrg.GetOrgSun(adminorgInt) |
||||
|
sunOrg.Id = append(sunOrg.Id, adminorgInt) |
||||
|
if len(sunOrg.Id) > 0 { |
||||
|
goormDb = goormDb.Where("`admin_org` IN ?", sunOrg.Id) |
||||
|
} |
||||
|
} |
||||
|
err := goormDb.Find(&peopleList).Error |
||||
|
if err != nil || len(peopleList) < 1 { |
||||
|
c.String(c.Writer.Status(), "没有查询到数据") |
||||
|
return |
||||
|
} |
||||
|
// return
|
||||
|
var builder strings.Builder |
||||
|
builder.WriteString("\xEF\xBB\xBF") //写入UTF-8 BOM 防止乱码
|
||||
|
writer := csv.NewWriter(&builder) |
||||
|
if typesInt == 2 { |
||||
|
writer.Write([]string{"已完成测试人员名单"}) |
||||
|
} else { |
||||
|
writer.Write([]string{"未完成测试人员名单"}) |
||||
|
} |
||||
|
|
||||
|
writer.Write([]string{"序号", "工号", "姓名", "行政组织"}) |
||||
|
jibuqi := 0 |
||||
|
for _, v := range peopleList { |
||||
|
if typesInt == 2 { |
||||
|
if publicmethod.IsInTrue[string](v.Number, xgNumber) { |
||||
|
var scvBody []string |
||||
|
jibuqi++ |
||||
|
xuHao := strconv.Itoa(jibuqi) |
||||
|
scvBody = append(scvBody, xuHao) |
||||
|
scvBody = append(scvBody, v.Number) |
||||
|
scvBody = append(scvBody, v.Name) |
||||
|
scvBody = append(scvBody, jisuanOrg(v.Company, v.MainDeparment, v.AdminOrg)) |
||||
|
writer.Write(scvBody) |
||||
|
} |
||||
|
} else { |
||||
|
if !publicmethod.IsInTrue[string](v.Number, xgNumber) { |
||||
|
var scvBody []string |
||||
|
jibuqi++ |
||||
|
xuHao := strconv.Itoa(jibuqi) |
||||
|
scvBody = append(scvBody, xuHao) |
||||
|
scvBody = append(scvBody, v.Number) |
||||
|
scvBody = append(scvBody, v.Name) |
||||
|
scvBody = append(scvBody, jisuanOrg(v.Company, v.MainDeparment, v.AdminOrg)) |
||||
|
writer.Write(scvBody) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
writer.Flush() |
||||
|
fileName := fmt.Sprintf("未完成测试人员名单_%v.csv", publicmethod.GetUUid(1)) |
||||
|
if typesInt == 2 { |
||||
|
fileName = fmt.Sprintf("已完成测试人员名单_%v.csv", publicmethod.GetUUid(1)) |
||||
|
} |
||||
|
c.Writer.Header().Add("Content-type", "application/octet-stream") |
||||
|
c.Header("Content-Type", "application/vnd.ms-excel;charset=utf8") |
||||
|
c.Header("Content-Disposition", "attachment; filename="+url.PathEscape(fileName)) |
||||
|
// c.Header("Content-Disposition", "attachment; filename=团队角色盘点.csv")
|
||||
|
c.Header("Content-Transfer-Encoding", "binary") |
||||
|
c.Writer.Write([]byte(builder.String())) |
||||
|
|
||||
|
// for _, v := range peopleList {
|
||||
|
|
||||
|
// }
|
||||
|
|
||||
|
// org = GetOrgInfo(v.AdminOrg)
|
||||
|
// publicmethod.Result(0, xgNumber, c)
|
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2024-09-19 15:20:31 |
||||
|
@ 功能: 计算行政组织关系 |
||||
|
*/ |
||||
|
func jisuanOrg(company, deparment, org int64) string { |
||||
|
var orgList []string |
||||
|
if company != 0 { |
||||
|
var com modelshr.AdministrativeOrganization |
||||
|
// err := com.GetCont(map[string]interface{}{"`id`": company}, "`name`")
|
||||
|
err := com.RedisCont(company) |
||||
|
if err == nil { |
||||
|
orgList = append(orgList, com.Name) |
||||
|
} |
||||
|
} |
||||
|
if deparment != 0 && deparment != company { |
||||
|
var depam modelshr.AdministrativeOrganization |
||||
|
// err := depam.GetCont(map[string]interface{}{"`id`": deparment}, "`name`")
|
||||
|
err := depam.RedisCont(deparment) |
||||
|
if err == nil { |
||||
|
orgList = append(orgList, depam.Name) |
||||
|
} |
||||
|
} |
||||
|
if org != 0 && org != deparment && org != company { |
||||
|
var orgInfo modelshr.AdministrativeOrganization |
||||
|
// err := orgInfo.GetCont(map[string]interface{}{"`id`": org}, "`name`")
|
||||
|
err := orgInfo.RedisCont(org) |
||||
|
if err == nil { |
||||
|
orgList = append(orgList, orgInfo.Name) |
||||
|
} |
||||
|
} |
||||
|
if len(orgList) > 0 { |
||||
|
return strings.Join(orgList, "/") |
||||
|
} |
||||
|
return "" |
||||
|
} |
||||
@ -0,0 +1,52 @@ |
|||||
|
package personalitycolor |
||||
|
|
||||
|
import ( |
||||
|
"appPlatform/overall" |
||||
|
"strings" |
||||
|
) |
||||
|
|
||||
|
// 授权账户
|
||||
|
type Charcolortest struct { |
||||
|
Id int64 `json:"id" gorm:"primaryKey;column:c_id;type:bigint(20) unsigned;not null;comment:Id;index"` |
||||
|
Class int64 `json:"class" gorm:"column:c_class;type:bigint(20) unsigned;default:0;not null;comment:测试试卷类型"` |
||||
|
Types int `json:"types" gorm:"column:c_type;type:int(1) unsigned;default:1;not null;comment:1:内部测试;2:外部测试"` |
||||
|
Number string `json:"number" gorm:"column:c_number;type:varchar(10) unsigned;not null;comment:工号"` |
||||
|
Name string `json:"name" gorm:"column:c_name;type:varchar(50) unsigned;not null;comment:姓名"` |
||||
|
Department string `json:"department" gorm:"column:c_department;type:varchar(255) unsigned;not null;comment:部门"` |
||||
|
Tel string `json:"tel" gorm:"column:c_tel;type:varchar(50) unsigned;not null;comment:联系电话"` |
||||
|
Address string `json:"address" gorm:"column:c_address;type:varchar(255) unsigned;not null;comment:联系地址"` |
||||
|
UserJson string `json:"userJson" gorm:"column:c_user_json;type:text unsigned;comment:内部员工详细信息"` |
||||
|
TestJson string `json:"testJson" gorm:"column:c_test_json;type:mediumtext unsigned;comment:试卷答案"` |
||||
|
Time int64 `json:"addtime" gorm:"column:c_add_time;type:bigint(20) unsigned;default:0;not null;comment:写入时间"` |
||||
|
EiteTime int64 `json:"eitetime" gorm:"column:c_eite_time;type:bigint(20) unsigned;default:0;not null;comment:编辑时间"` |
||||
|
State int `json:"c_states" gorm:"column:c_states;type:int(1) unsigned;default:1;not null;comment:1:有效;2:无效"` |
||||
|
BranchName string `json:"branchName" gorm:"column:c_branch_name;type:varchar(255) unsigned;not null;comment:部门"` |
||||
|
} |
||||
|
|
||||
|
func (Position *Charcolortest) TableName() string { |
||||
|
return "charcolortest" |
||||
|
} |
||||
|
|
||||
|
// 编辑职务分类内容
|
||||
|
func (cont *Charcolortest) EiteCont(whereMap interface{}, saveData map[string]interface{}) (err error) { |
||||
|
err = overall.CONSTANT_DB_Color.Model(&cont).Where(whereMap).Updates(saveData).Error |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// 获取行政组织内容
|
||||
|
func (cont *Charcolortest) GetCont(whereMap interface{}, field ...string) (err error) { |
||||
|
gormDb := overall.CONSTANT_DB_Color.Model(&cont) |
||||
|
if len(field) > 0 { |
||||
|
fieldStr := strings.Join(field, ",") |
||||
|
gormDb = gormDb.Select(fieldStr) |
||||
|
} |
||||
|
gormDb = gormDb.Where(whereMap) |
||||
|
err = gormDb.First(&cont).Error |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// 根据条件获取总数
|
||||
|
func (cont *Charcolortest) CountCont(whereMap interface{}) (countId int64) { |
||||
|
overall.CONSTANT_DB_Color.Model(&cont).Where(whereMap).Count(&countId) |
||||
|
return |
||||
|
} |
||||
Loading…
Reference in new issue