You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

tech_converge_info.go 14 kB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. package models
  2. import (
  3. "strconv"
  4. "strings"
  5. "time"
  6. "code.gitea.io/gitea/modules/timeutil"
  7. "xorm.io/builder"
  8. )
  9. const (
  10. TechHide = 1
  11. TechShow = 2
  12. TechMigrating = 3
  13. TechMigrateFailed = 4
  14. )
  15. const DefaultTechApprovedStatus = TechShow
  16. type TechConvergeBaseInfo struct {
  17. ID int64 `xorm:"pk autoincr"`
  18. ProjectNumber string `xorm:"UNIQUE NOT NULL"` //项目立项编号
  19. ProjectName string //科技项目名称
  20. Institution string //项目承担单位
  21. ApplyYear int //申报年度
  22. Province string //所属省(省市)
  23. Category string //单位性质
  24. Recommend string //推荐单位
  25. Owner string //项目负责人
  26. Phone string //负责人电话
  27. Email string //负责人邮箱
  28. Contact string //项目联系人
  29. ContactPhone string //联系人电话
  30. ContactEmail string //联系人邮箱
  31. ExecuteMonth int //执行周期(月)
  32. ExecuteStartYear int //执行开始年份
  33. ExecuteEndYear int //执行结束年份
  34. ExecutePeriod string //执行期限
  35. Type string //项目类型
  36. StartUp string //启动会时间
  37. NumberTopic int
  38. Topic1 string
  39. Topic2 string
  40. Topic3 string
  41. Topic4 string
  42. Topic5 string
  43. Topic6 string
  44. Topic7 string
  45. AllInstitution string `xorm:"TEXT"`
  46. CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
  47. UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
  48. }
  49. func (t *TechConvergeBaseInfo) Brief() *TechConvergeBrief {
  50. return &TechConvergeBrief{
  51. ProjectNumber: t.ProjectNumber,
  52. ProjectName: t.ProjectName,
  53. Institution: t.Institution,
  54. AllInstitution: t.AllInstitution,
  55. }
  56. }
  57. func (t *TechConvergeBaseInfo) IsValidInstitution(institution string) bool {
  58. if t.AllInstitution == "" && t.Institution == "" {
  59. return false
  60. }
  61. allInstitution := make([]string, 0)
  62. if t.AllInstitution != "" {
  63. allInstitution = strings.Split(t.AllInstitution, ",")
  64. }
  65. if t.Institution != "" {
  66. allInstitution = append(allInstitution, t.Institution)
  67. }
  68. newInstitution := strings.Split(institution, ",")
  69. total := len(newInstitution)
  70. matched := 0
  71. for _, n := range newInstitution {
  72. for _, s := range allInstitution {
  73. if s == n {
  74. matched++
  75. break
  76. }
  77. }
  78. }
  79. if matched == total {
  80. return true
  81. }
  82. return false
  83. }
  84. type RepoConvergeInfo struct {
  85. ID int64 `xorm:"pk autoincr"`
  86. RepoID int64
  87. Url string
  88. BaseInfoID int64
  89. Institution string
  90. UID int64
  91. Status int
  92. CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
  93. UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
  94. User *User `xorm:"-"`
  95. Repo *Repository `xorm:"-"`
  96. BaseInfo *TechConvergeBaseInfo `xorm:"-"`
  97. }
  98. func (r *RepoConvergeInfo) InsertOrUpdate() error {
  99. if r.ID != 0 {
  100. _, err := x.ID(r.ID).Update(r)
  101. return err
  102. } else {
  103. _, err := x.InsertOne(r)
  104. return err
  105. }
  106. }
  107. func GetTechConvergeBaseInfoByProjectNumber(projectNumber string) (*TechConvergeBaseInfo, error) {
  108. tb := &TechConvergeBaseInfo{ProjectNumber: projectNumber}
  109. return getTechConvergeBaseInfo(tb)
  110. }
  111. func (baseInfo *TechConvergeBaseInfo) InsertOrUpdate() error {
  112. if baseInfo.ID != 0 {
  113. _, err := x.ID(baseInfo.ID).Update(baseInfo)
  114. return err
  115. } else {
  116. _, err := x.InsertOne(baseInfo)
  117. return err
  118. }
  119. }
  120. type ErrTechConvergeBaseInfoNotExist struct {
  121. ID string
  122. }
  123. func (err ErrTechConvergeBaseInfoNotExist) Error() string {
  124. return "tech.tech_not_exist"
  125. }
  126. func IsErrTechConvergeBaseInfoNotExist(err error) bool {
  127. _, ok := err.(ErrTechConvergeBaseInfoNotExist)
  128. return ok
  129. }
  130. func getTechConvergeBaseInfo(tb *TechConvergeBaseInfo) (*TechConvergeBaseInfo, error) {
  131. has, err := x.Get(tb)
  132. if err != nil {
  133. return nil, err
  134. } else if !has {
  135. if tb.ProjectNumber != "" {
  136. return nil, ErrTechConvergeBaseInfoNotExist{tb.ProjectNumber}
  137. } else {
  138. return nil, ErrTechConvergeBaseInfoNotExist{strconv.FormatInt(tb.ID, 10)}
  139. }
  140. }
  141. return tb, nil
  142. }
  143. func GetProjectNames() []string {
  144. var names []string
  145. x.Table("tech_converge_base_info").Distinct("project_name").Find(&names)
  146. return names
  147. }
  148. func GetSummitRepoIds() []int64 {
  149. var ids []int64
  150. x.Table("repo_converge_info").Cols("repo_id").Find(&ids)
  151. return ids
  152. }
  153. func GetTechRepoTopics(limit int) []string {
  154. repoIds := GetSummitRepoIds()
  155. if len(repoIds) == 0 {
  156. return []string{}
  157. }
  158. //select name, repo_count from topic a, repo_topic b
  159. //where a.id=b.topic_id and repo_id in (1,3) order by repo_count desc
  160. inCondition := "repo_id in ("
  161. const MaxINItems = 1000
  162. for i := 0; i < len(repoIds); i++ {
  163. if i == len(repoIds)-1 {
  164. inCondition += strconv.FormatInt(repoIds[i], 10)
  165. } else if (i+1)%MaxINItems == 0 {
  166. inCondition += strconv.FormatInt(repoIds[i], 10) + ") or repo_id in ("
  167. } else {
  168. inCondition += strconv.FormatInt(repoIds[i], 10) + ","
  169. }
  170. }
  171. inCondition += ")"
  172. sql := "select name, repo_count from topic a, repo_topic b where a.id=b.topic_id and (" + inCondition + ") order by repo_count desc"
  173. if limit > 0 {
  174. sql += "limit " + strconv.Itoa(limit)
  175. }
  176. result, err := x.QueryString(sql)
  177. if err != nil {
  178. return []string{}
  179. }
  180. var topics []string
  181. for _, record := range result {
  182. topics = append(topics, record["name"])
  183. }
  184. return topics
  185. }
  186. func GetProjectTypes() []string {
  187. sql := "SELECT COUNT(id) AS theCount, type from tech_converge_base_info GROUP BY type ORDER BY theCount DESC"
  188. result, err := x.QueryString(sql)
  189. if err != nil {
  190. return []string{}
  191. }
  192. var projectTypes []string
  193. for _, record := range result {
  194. projectTypes = append(projectTypes, record["type"])
  195. }
  196. return projectTypes
  197. }
  198. func GetApplyExecuteYears() ([]int, []int) {
  199. apply, executeStart, executeEnd := GetYearInfos()
  200. applyEnd := time.Now().Year()
  201. var applyArray []int
  202. var executeArray []int
  203. for i := apply; i <= applyEnd; i++ {
  204. applyArray = append(applyArray, i)
  205. }
  206. for i := executeStart; i <= executeEnd; i++ {
  207. executeArray = append(executeArray, i)
  208. }
  209. return applyArray, executeArray
  210. }
  211. func GetYearInfos() (int, int, int) {
  212. sql := "select min(apply_year) as apply_year,min(CASE WHEN execute_start_year != 0 THEN execute_start_year END) as execute_start_year,max(execute_end_year) as execute_end_year from tech_converge_base_info"
  213. result, err := x.QueryString(sql)
  214. if err != nil {
  215. return 2018, 2019, 2024
  216. }
  217. for _, record := range result {
  218. apply, _ := strconv.Atoi(record["apply_year"])
  219. executeStart, _ := strconv.Atoi(record["execute_start_year"])
  220. executeEnd, _ := strconv.Atoi(record["execute_end_year"])
  221. return apply, executeStart, executeEnd
  222. }
  223. return 2018, 2019, 2024
  224. }
  225. func GetAllInstitutions() []string {
  226. var names []string
  227. x.Table("tech_converge_base_info").Cols("all_institution").Find(&names)
  228. var allNames []string
  229. for _, name := range names {
  230. singleNames := strings.Split(name, ",")
  231. for _, singleName := range singleNames {
  232. if singleName != "" {
  233. if !contains(allNames, singleName) {
  234. allNames = append(allNames, singleName)
  235. }
  236. }
  237. }
  238. }
  239. return allNames
  240. }
  241. func contains(s []string, e string) bool {
  242. for _, a := range s {
  243. if a == e {
  244. return true
  245. }
  246. }
  247. return false
  248. }
  249. type SearchTechOpt struct {
  250. Q string //科技项目名称
  251. ProjectType string
  252. Institution string
  253. ApplyYear int
  254. ExecuteYear int
  255. OrderBy string
  256. ListOptions
  257. }
  258. type SearchRepoOpt struct {
  259. Q string //项目名称,简介
  260. ProjectName string
  261. Topic string
  262. Institution string
  263. OrderBy string
  264. ListOptions
  265. }
  266. type RepoWithInstitution struct {
  267. ID int64 `json:"id"`
  268. OwnerID int64 `json:"owner_id"`
  269. OwnerName string `json:"owner_name"`
  270. Name string `json:"name"`
  271. Alias string `json:"alias"`
  272. Topics []string `json:"topics"`
  273. Description string `json:"description"`
  274. Institution string `json:"institution"`
  275. UpdatedUnix timeutil.TimeStamp `json:"updated_unix"`
  276. }
  277. type TechRepoInfo struct {
  278. ID int64 `json:"id"`
  279. ProjectName string `json:"project_name"`
  280. Institution string `json:"institution"`
  281. Type string `json:"type"`
  282. ApplyYear int `json:"apply_year"`
  283. ExecutePeriod string `json:"execute_period"`
  284. AllInstitution string `json:"all_institution"`
  285. RepoCount int `json:"repo_numer"`
  286. Repos []*RepoWithInstitution
  287. }
  288. func SearchTechRepoInfo(opt SearchTechOpt) ([]*TechRepoInfo, int64, error) {
  289. sql := `select a.*,COALESCE(b.count,0) as repo_count, COALESCE(b.max,0) as max from tech_converge_base_info a left join
  290. (select base_info_id,count(id),max(updated_unix) from repo_converge_info where status=2 GROUP BY base_info_id ) b
  291. on a.id=b.base_info_id`
  292. totalSql := "select count(*) from (" + sql + ") c" + buildTechFilterCond(opt)
  293. total, err := x.SQL(totalSql).Count(new(TechConvergeBaseInfo))
  294. resultList := make([]*TechRepoInfo, 0)
  295. if err != nil {
  296. return resultList, total, err
  297. }
  298. resultSql := "select id,project_name, institution,type,apply_year,execute_period,all_institution,repo_count from (" +
  299. sql + ") c " + buildTechFilterCond(opt) + opt.OrderBy + " offset " + strconv.Itoa((opt.Page-1)*opt.PageSize) + " limit " + strconv.Itoa(opt.PageSize)
  300. resultMap, err := x.QueryInterface(resultSql)
  301. if err == nil {
  302. for _, record := range resultMap {
  303. resultList = append(resultList, &TechRepoInfo{
  304. ID: record["id"].(int64),
  305. ProjectName: record["project_name"].(string),
  306. Institution: record["institution"].(string),
  307. Type: record["type"].(string),
  308. ApplyYear: int(record["apply_year"].(int64)),
  309. ExecutePeriod: record["execute_period"].(string),
  310. AllInstitution: record["all_institution"].(string),
  311. RepoCount: int(record["repo_count"].(int64)),
  312. })
  313. }
  314. }
  315. loadRepoInfoForTech(resultList)
  316. return resultList, total, err
  317. }
  318. func buildTechFilterCond(opt SearchTechOpt) string {
  319. sql := ""
  320. if opt.Q != "" {
  321. sql += getWherePrefix(sql) + " project_name like '%" + opt.Q + "%'"
  322. }
  323. if opt.ProjectType != "" {
  324. sql += getWherePrefix(sql) + " type ='" + opt.ProjectType + "'"
  325. }
  326. if opt.ApplyYear != 0 {
  327. sql += getWherePrefix(sql) + " apply_year =" + strconv.Itoa(opt.ApplyYear)
  328. }
  329. if opt.Institution != "" {
  330. sql += getWherePrefix(sql) + " (all_institution like '%" + opt.Institution + ",%'" + " or all_institution like '%," + opt.Institution + "%'"
  331. }
  332. if opt.ExecuteYear != 0 {
  333. sql += getWherePrefix(sql) + " execute_start_year <=" + strconv.Itoa(opt.ExecuteYear) + " and execute_end_year >=" + strconv.Itoa(opt.ExecuteYear)
  334. }
  335. return sql
  336. }
  337. func getWherePrefix(sql string) string {
  338. if sql == "" {
  339. return " where "
  340. }
  341. return " and "
  342. }
  343. func loadRepoInfoForTech(list []*TechRepoInfo) {
  344. for _, techRepo := range list {
  345. techRepo.Repos = []*RepoWithInstitution{}
  346. if techRepo.RepoCount > 0 {
  347. var repoIds []int64
  348. x.Table("repo_converge_info").Cols("repo_id").Where("base_info_id=?", techRepo.ID).Desc("updated_unix").Find(&repoIds)
  349. resultMap, err := GetRepositoriesMapByIDs(repoIds)
  350. if err == nil {
  351. for _, repoId := range repoIds {
  352. repo, ok := resultMap[repoId]
  353. if ok {
  354. techRepo.Repos = append(techRepo.Repos, &RepoWithInstitution{
  355. ID: repo.ID,
  356. Institution: techRepo.Institution,
  357. OwnerID: repo.OwnerID,
  358. OwnerName: repo.OwnerName,
  359. Name: repo.Name,
  360. Alias: repo.Alias,
  361. Topics: repo.Topics,
  362. Description: repo.Description,
  363. UpdatedUnix: repo.UpdatedUnix,
  364. })
  365. }
  366. }
  367. }
  368. }
  369. }
  370. }
  371. type TechConvergeBrief struct {
  372. ProjectNumber string `json:"no"` //项目立项编号
  373. ProjectName string `json:"name"` //科技项目名称
  374. Institution string `json:"institution"` //项目承担单位
  375. AllInstitution string `json:"all_institution"`
  376. }
  377. type FindTechOpt struct {
  378. TechNo string
  379. ProjectName string
  380. Institution string
  381. }
  382. func FindTech(opt FindTechOpt) ([]*TechConvergeBaseInfo, error) {
  383. var cond = builder.NewCond()
  384. if opt.TechNo != "" {
  385. cond = cond.And(builder.Like{"project_number", opt.TechNo})
  386. }
  387. if opt.ProjectName != "" {
  388. cond = cond.And(builder.Like{"project_name", opt.ProjectName})
  389. }
  390. if opt.Institution != "" {
  391. cond = cond.And(builder.Like{"institution", opt.Institution}.Or(builder.Like{"all_institution", opt.Institution}))
  392. }
  393. r := make([]*TechConvergeBaseInfo, 0)
  394. err := x.Where(cond).OrderBy("updated_unix desc").Find(&r)
  395. if err != nil {
  396. return nil, err
  397. }
  398. return r, nil
  399. }
  400. func GetTechByTechNo(techNo string) (*TechConvergeBaseInfo, error) {
  401. var tech = &TechConvergeBaseInfo{}
  402. has, err := x.Where("project_number = ?", techNo).Get(tech)
  403. if err != nil {
  404. return nil, err
  405. } else if !has {
  406. return nil, ErrTechConvergeBaseInfoNotExist{}
  407. }
  408. return tech, nil
  409. }
  410. type GetRepoConvergeOpts struct {
  411. RepoId int64
  412. BaseInfoId int64
  413. Status []int
  414. }
  415. func GetRepoConverge(opts GetRepoConvergeOpts) ([]*RepoConvergeInfo, error) {
  416. r := make([]*RepoConvergeInfo, 0)
  417. cond := builder.NewCond()
  418. if opts.RepoId > 0 {
  419. cond = cond.And(builder.Eq{"repo_id": opts.RepoId})
  420. }
  421. if opts.BaseInfoId > 0 {
  422. cond = cond.And(builder.Eq{"base_info_id": opts.BaseInfoId})
  423. }
  424. if len(opts.Status) > 0 {
  425. cond = cond.And(builder.In("status", opts.Status))
  426. }
  427. err := x.Where(cond).Find(&r)
  428. if err != nil {
  429. return nil, err
  430. }
  431. return r, nil
  432. }
  433. func UpdateRepoConvergeStatus(id int64, status int) (int64, error) {
  434. return x.ID(id).Update(&RepoConvergeInfo{
  435. Status: status,
  436. })
  437. }