From a3e43080375e18a6399963f370db806cbfde397a Mon Sep 17 00:00:00 2001 From: pan <1029559041@qq.com> Date: Tue, 1 Jun 2021 01:16:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0accompanist=20compose=20ui?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E5=BA=93=20=E7=A4=BE=E5=9B=A2=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E8=B5=84=E6=96=99=E5=AE=A1=E6=A0=B8=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E9=98=B2=E8=BE=93=E5=85=A5=E6=B3=95=E9=81=AE=E6=8C=A1?= =?UTF-8?q?=20=E5=AE=8C=E5=96=84=E4=B8=AA=E4=BA=BA=E5=90=8D=E7=89=87?= =?UTF-8?q?=E9=80=BB=E8=BE=91=20=E7=A4=BE=E5=9B=A2=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E5=BA=95=E9=83=A8=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E6=9B=B4=E6=96=B0=20Http=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=B1=BB=E5=93=8D=E5=BA=94=E5=9B=9E=E8=B0=83=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E5=AE=8C=E5=96=84=20token=E7=AE=A1=E7=90=86=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E5=AE=8C=E5=96=84=20=E5=A2=9E=E5=8A=A0Vo=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E7=AE=A1=E7=90=86=20=E7=A4=BE=E5=9B=A2=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E5=AE=8C=E5=96=84=20=E7=A4=BE=E5=9B=A2?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E9=80=BB=E8=BE=91=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- background/src/main/AndroidManifest.xml | 18 + .../main/java/com/gyf/csams/InitActivity.kt | 8 +- .../gyf/csams/account/model/LoginViewModel.kt | 5 +- .../model/AssociationManagementViewModel.kt | 70 +-- .../main/model/AuditAssociationViewModel.kt | 81 +++ .../csams/main/model/BackgroundViewModel.kt | 11 + .../gyf/csams/main/model/CheckActViewModel.kt | 7 +- .../main/model/CheckQualityReportViewModel.kt | 20 +- .../com/gyf/csams/main/model/MainViewModel.kt | 42 -- .../main/model/ManagementOfficerModel.kt | 96 +--- .../csams/main/model/ManagerActViewModel.kt | 7 +- .../com/gyf/csams/main/model/MenuViewModel.kt | 3 +- .../gyf/csams/main/model/RenameViewModel.kt | 20 +- .../main/ui/AssociationManagementActivity.kt | 12 +- .../csams/main/ui/AuditAssociationActivity.kt | 310 ++++++++++++ .../com/gyf/csams/main/ui/CheckActActivity.kt | 13 +- .../main/ui/CheckQualityReportActivity.kt | 15 +- .../com/gyf/csams/main/ui/MainActivity.kt | 24 +- .../main/ui/ManagementOfficerActivity.kt | 18 +- .../gyf/csams/main/ui/ManagerActActivity.kt | 6 +- .../gyf/csams/main/ui/NotificationActivity.kt | 80 +++ .../com/gyf/csams/main/ui/RenameActivity.kt | 11 +- .../main/java/com/gyf/csams/uikit/Table.kt | 59 ++- background/src/main/res/values-en/strings.xml | 5 + background/src/main/res/values-zh/strings.xml | 5 + background/src/main/res/values/strings.xml | 5 + .../java/com/gyf/csams/ExampleUnitTest.kt | 13 + foreground/src/main/AndroidManifest.xml | 1 + .../main/java/com/gyf/csams/InitActivity.kt | 8 +- .../csams/account/model/AccountViewModel.kt | 44 +- .../gyf/csams/account/ui/AccountActivity.kt | 4 +- .../activity/model/ActivityDetailViewModel.kt | 49 +- .../activity/ui/ActivityDetailActivity.kt | 7 +- .../association/model/AssociationViewModel.kt | 10 +- .../csams/association/model/ExamViewModel.kt | 45 +- .../model/RegAssociationViewModel.kt | 141 ++++-- .../association/ui/AssociationActivity.kt | 4 +- .../gyf/csams/association/ui/ExamActivity.kt | 7 +- .../association/ui/RegAssociationActivity.kt | 115 ++++- .../com/gyf/csams/main/model/MainViewModel.kt | 211 +++----- .../com/gyf/csams/main/ui/MainActivity.kt | 39 +- .../message/model/ForegroundViewModel.kt | 11 + .../csams/message/ui/SysMessageActivity.kt | 9 +- .../main/java/com/gyf/csams/uikit/BaseView.kt | 2 - .../java/com/gyf/csams/uikit/ViewModel.kt | 10 +- .../main/java/com/gyf/csams/util/GsonUtil.kt | 8 +- .../java/com/gyf/csams/util/HttpCallback.kt | 6 +- foreground/src/main/res/values-en/strings.xml | 1 + foreground/src/main/res/values-zh/strings.xml | 1 + foreground/src/main/res/values/strings.xml | 1 + .../java/com/gyf/csams/ExampleUnitTest.kt | 8 +- lib/build.gradle.kts | 9 +- .../gyf/lib/model/AbstractLoginViewModel.kt | 53 +- .../java/com/gyf/lib/model/ApplyViewModel.kt | 7 +- .../java/com/gyf/lib/model/InitViewModel.kt | 20 +- .../java/com/gyf/lib/model/ScrollViewModel.kt | 7 +- .../com/gyf/lib}/model/SysMessageViewModel.kt | 61 ++- .../com/gyf/lib/service/MessageService.kt | 7 +- .../com/gyf/lib/uikit/AbstractInitActivity.kt | 10 +- .../main/java/com/gyf/lib/uikit/MainFrame.kt | 22 +- .../main/java/com/gyf/lib/uikit/Profile.kt | 22 +- lib/src/main/java/com/gyf/lib/util/Api.kt | 9 +- .../java/com/gyf/lib/util/BottomButton.kt | 20 +- .../main/java/com/gyf/lib/util/HttpUtil.kt | 25 +- .../main/java/com/gyf/lib/util/TokenUtil.kt | 40 +- lib/src/main/java/com/gyf/lib/util/Vo.kt | 477 ++++++++++++++++++ lib/src/main/java/com/gyf/lib/util/vo.kt | 27 - lib/src/main/res/values-en/strings.xml | 12 +- lib/src/main/res/values-zh/strings.xml | 12 +- lib/src/main/res/values/strings.xml | 12 +- 70 files changed, 1741 insertions(+), 817 deletions(-) create mode 100644 background/src/main/java/com/gyf/csams/main/model/AuditAssociationViewModel.kt create mode 100644 background/src/main/java/com/gyf/csams/main/model/BackgroundViewModel.kt delete mode 100644 background/src/main/java/com/gyf/csams/main/model/MainViewModel.kt create mode 100644 background/src/main/java/com/gyf/csams/main/ui/AuditAssociationActivity.kt create mode 100644 background/src/main/java/com/gyf/csams/main/ui/NotificationActivity.kt create mode 100644 foreground/src/main/java/com/gyf/csams/message/model/ForegroundViewModel.kt rename {foreground/src/main/java/com/gyf/csams/message => lib/src/main/java/com/gyf/lib}/model/SysMessageViewModel.kt (60%) create mode 100644 lib/src/main/java/com/gyf/lib/util/Vo.kt delete mode 100644 lib/src/main/java/com/gyf/lib/util/vo.kt diff --git a/background/src/main/AndroidManifest.xml b/background/src/main/AndroidManifest.xml index 5528c76..a4efbc5 100644 --- a/background/src/main/AndroidManifest.xml +++ b/background/src/main/AndroidManifest.xml @@ -4,6 +4,8 @@ + + + + + + + + + + + + + + + + diff --git a/background/src/main/java/com/gyf/csams/InitActivity.kt b/background/src/main/java/com/gyf/csams/InitActivity.kt index 46e03f5..14ed4d7 100644 --- a/background/src/main/java/com/gyf/csams/InitActivity.kt +++ b/background/src/main/java/com/gyf/csams/InitActivity.kt @@ -1,14 +1,20 @@ package com.gyf.csams import android.app.Activity +import com.google.gson.reflect.TypeToken import com.gyf.csams.account.ui.LoginActivity import com.gyf.csams.main.ui.MainActivity import com.gyf.lib.uikit.AbstractInitActivity import com.gyf.lib.util.AccountApi +import com.gyf.lib.util.ApiResponse +import com.gyf.lib.util.ManagerVo +import java.lang.reflect.Type -class InitActivity : AbstractInitActivity() { +class InitActivity : AbstractInitActivity() { override val main: Class = MainActivity::class.java override val login: Class = LoginActivity::class.java override val api: AccountApi = AccountApi.BackgroundToken + + override val typeToken: Type = object : TypeToken>() {}.type } \ No newline at end of file diff --git a/background/src/main/java/com/gyf/csams/account/model/LoginViewModel.kt b/background/src/main/java/com/gyf/csams/account/model/LoginViewModel.kt index 1aa1c2a..edddac8 100644 --- a/background/src/main/java/com/gyf/csams/account/model/LoginViewModel.kt +++ b/background/src/main/java/com/gyf/csams/account/model/LoginViewModel.kt @@ -9,8 +9,7 @@ import com.gyf.lib.uikit.FormStatus import com.gyf.lib.uikit.ValidStringForm import com.gyf.lib.util.AccountApi import com.gyf.lib.util.ClientType - -data class ManagerVo(val account: String, val password: String, val device: String) +import com.gyf.lib.util.ManagerLoginVo class LoginViewModel(application: Application) : AbstractLoginViewModel(application) { override val id = ValidStringForm(formDesc = "管理帐号", textLength = 8) @@ -25,7 +24,7 @@ class LoginViewModel(application: Application) : AbstractLoginViewModel(applicat override fun loginParam(): Any { val account = "${id.formValue.value}" val password = "${password.formValue.value}" - return ManagerVo( + return ManagerLoginVo( account = account, password = password, device = "${Build.MANUFACTURER} ${Build.MODEL}" diff --git a/background/src/main/java/com/gyf/csams/main/model/AssociationManagementViewModel.kt b/background/src/main/java/com/gyf/csams/main/model/AssociationManagementViewModel.kt index 7b5370d..0f12568 100644 --- a/background/src/main/java/com/gyf/csams/main/model/AssociationManagementViewModel.kt +++ b/background/src/main/java/com/gyf/csams/main/model/AssociationManagementViewModel.kt @@ -1,49 +1,12 @@ package com.gyf.csams.main.model import android.app.Application -import androidx.lifecycle.viewModelScope import com.gyf.lib.model.ScrollViewModel -import com.gyf.lib.util.randomChinese -import kotlinx.coroutines.launch +import com.gyf.lib.util.AssociationLevel +import com.gyf.lib.util.AssociationVo -/** - * 社团级别 - * - */ -enum class AssociationLevel { - A, - B, - C, - D -} -/** - * 所属院系 - * - */ -enum class AssociationFaculty(val desc: String, val range: IntRange) { - ForeignLanguageDept("外语系", 0..0), - CivilEngineeringDept("土木工程", 1..10), - SEM("经理管理学院", 11..20), - MechanicalEngineeringDept("机械工程", 21..30), - TransportationDept("交通运输", 31..40), - ArchitectureAndArts("建筑与艺术", 41..50), - ElectricalDept("电气", 51..60), - MaterialsDept("材料", 61..70), - MessageDept("信息", 71..80), - MathematicsDept("数理", 81..90), - GraduateStudent("研究生", 91..99) -} -/** - * 社团 - * - * @property name 社团名称 - */ -data class AssociationVo( - val associationId: Long, val name: String, val commander: String, - val faculty: AssociationFaculty, val level: AssociationLevel, val desc: String -) /** * 数据状态管理 @@ -59,22 +22,7 @@ class AssociationManagementViewModel(application: Application) : ScrollViewModel } override fun load() { - viewModelScope.launch { - _data.value?.apply { - repeat(initSize) { - add( - AssociationVo( - associationId = (0..65535L).random(), - name = randomChinese(5), - commander = randomChinese(3), - faculty = AssociationFaculty.values().random(), - level = AssociationLevel.values().random(), - desc = randomChinese(20) - ) - ) - } - } - } + TODO() } override fun loadMore(callback: (message: String) -> Unit) { @@ -82,18 +30,10 @@ class AssociationManagementViewModel(application: Application) : ScrollViewModel } /** - * TODO 更新社团级别 * * @param level */ - fun update(associationVo: AssociationVo, level: AssociationLevel) { - _data.value?.apply { - val i = indexOf(associationVo) - set(i, associationVo.copy(level = level)) - val new = mutableListOf() - new.addAll(this) - clear() - _data.postValue(new) - } + fun update(associationDto: AssociationVo, level: AssociationLevel) { + TODO("更新社团级别") } } \ No newline at end of file diff --git a/background/src/main/java/com/gyf/csams/main/model/AuditAssociationViewModel.kt b/background/src/main/java/com/gyf/csams/main/model/AuditAssociationViewModel.kt new file mode 100644 index 0000000..347dfdc --- /dev/null +++ b/background/src/main/java/com/gyf/csams/main/model/AuditAssociationViewModel.kt @@ -0,0 +1,81 @@ +package com.gyf.csams.main.model + +import android.app.Application +import androidx.lifecycle.viewModelScope +import com.google.gson.reflect.TypeToken +import com.gyf.lib.model.ScrollViewModel +import com.gyf.lib.util.* +import kotlinx.coroutines.launch + + +class AuditAssociationViewModel(application: Application) : ScrollViewModel( + application +) { + override val initSize: Int = 10 + + init { + load { } + } + + override fun load(callback: (message: String) -> Unit) { + viewModelScope.launch { + HttpClient.post( + Api.buildUrl(AssociationApi.Audit), HttpCallback>( + action = "获取审核列表", + onSuccess = { it -> + it.body?.let { + _data.postValue(it) + } + }, + typeToken = object : + TypeToken>>() {}.type + ), + jsonParam = OnlyToken(clientType = ClientType.Background) + ) + } + } + + override fun loadMore(callback: (message: String) -> Unit) { + TODO("Not yet implemented") + } + + + /** + * 受理注册资料 + * + * @param callback + */ + fun accept(regId: Int, isFirstAccept: Boolean, callback: (message: String) -> Unit) { + viewModelScope.launch { + HttpClient.post( + Api.buildUrl(AssociationApi.Accept), + HttpCallback(action = "受理社团注册资料", onSuccess = { + callback(it.message) + }, typeToken = object : TypeToken>() {}.type), + jsonParam = AcceptRegAssociation(regId = regId, isFirstAccept = isFirstAccept) + ) + } + } + + /** + * 提交审核结果 + * + * @param regId + * @param result + * @param callback + */ + fun check(regId: Int, cause: String, result: Boolean, callback: (message: String) -> Unit) { + viewModelScope.launch { + HttpClient.post( + Api.buildUrl(AssociationApi.Check), + HttpCallback(action = "提交审核结果", onSuccess = { + callback(it.message) + }, typeToken = object : TypeToken>() {}.type), + jsonParam = CheckRegVo( + regId = regId, result = result, + cause = cause + ) + ) + } + } +} \ No newline at end of file diff --git a/background/src/main/java/com/gyf/csams/main/model/BackgroundViewModel.kt b/background/src/main/java/com/gyf/csams/main/model/BackgroundViewModel.kt new file mode 100644 index 0000000..f691b3c --- /dev/null +++ b/background/src/main/java/com/gyf/csams/main/model/BackgroundViewModel.kt @@ -0,0 +1,11 @@ +package com.gyf.csams.main.model + +import android.app.Application +import com.gyf.lib.model.SysMessageViewModel +import com.gyf.lib.util.ClientType + +class BackgroundViewModel(application: Application) : SysMessageViewModel(application) { + override fun clientType(): ClientType { + return ClientType.Background + } +} \ No newline at end of file diff --git a/background/src/main/java/com/gyf/csams/main/model/CheckActViewModel.kt b/background/src/main/java/com/gyf/csams/main/model/CheckActViewModel.kt index ef4735c..f43d15f 100644 --- a/background/src/main/java/com/gyf/csams/main/model/CheckActViewModel.kt +++ b/background/src/main/java/com/gyf/csams/main/model/CheckActViewModel.kt @@ -3,17 +3,12 @@ package com.gyf.csams.main.model import android.app.Application import androidx.lifecycle.viewModelScope import com.gyf.lib.model.ApplyViewModel +import com.gyf.lib.util.ApplyActVo import com.gyf.lib.util.format import com.gyf.lib.util.randomChinese import com.gyf.lib.util.randomDateTime import kotlinx.coroutines.launch -data class ApplyActVo( - val activityName: String, val activityTime: String, - val location: String, val desc: String, - val size: Int -) - /** * 活动数据管理 diff --git a/background/src/main/java/com/gyf/csams/main/model/CheckQualityReportViewModel.kt b/background/src/main/java/com/gyf/csams/main/model/CheckQualityReportViewModel.kt index e6b0f27..06972a4 100644 --- a/background/src/main/java/com/gyf/csams/main/model/CheckQualityReportViewModel.kt +++ b/background/src/main/java/com/gyf/csams/main/model/CheckQualityReportViewModel.kt @@ -1,31 +1,13 @@ package com.gyf.csams.main.model import android.app.Application -import androidx.annotation.IntRange import androidx.lifecycle.viewModelScope import com.gyf.lib.model.ApplyViewModel +import com.gyf.lib.util.QualityReportVo import com.gyf.lib.util.randomChinese import kotlinx.coroutines.launch -const val MAX_SCORE = 5L - -/** - * 活动质量汇报单 - * - * @property applyName 申请人 - * @property activityName 活动名称 - * @property merit 优点 - * @property defect 缺点 - * @property score 星级评价 - */ -data class QualityReportVo( - val applyName: String, - val activityName: String, - val merit: String, - val defect: String, - @IntRange(from = 1L, to = MAX_SCORE) val score: Int -) /** * 活动质量汇报单评价 diff --git a/background/src/main/java/com/gyf/csams/main/model/MainViewModel.kt b/background/src/main/java/com/gyf/csams/main/model/MainViewModel.kt deleted file mode 100644 index 26f2166..0000000 --- a/background/src/main/java/com/gyf/csams/main/model/MainViewModel.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.gyf.csams.main.model - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import com.gyf.lib.uikit.PersonInfoVo -import com.gyf.lib.util.randomChinese - -/** - * 部长 - * - * @property name 姓名 - * @property duty 职务 - * @property headImg 头像 - * @property desc 个人简介 - */ -data class MinisterVo( - override val name: String, - override val duty: String, - override val headImg: String, - override val desc: String -) : PersonInfoVo() - -class MainViewModel : ViewModel() { - private val _person = MutableLiveData() - val person: LiveData = _person - - init { - loadInfo() - } - - private fun loadInfo() { - _person.postValue( - MinisterVo( - name = randomChinese(3), - duty = "总部长", - headImg = "", - desc = randomChinese(8) - ) - ) - } -} \ No newline at end of file diff --git a/background/src/main/java/com/gyf/csams/main/model/ManagementOfficerModel.kt b/background/src/main/java/com/gyf/csams/main/model/ManagementOfficerModel.kt index ff2fcb5..b2b428e 100644 --- a/background/src/main/java/com/gyf/csams/main/model/ManagementOfficerModel.kt +++ b/background/src/main/java/com/gyf/csams/main/model/ManagementOfficerModel.kt @@ -3,49 +3,14 @@ package com.gyf.csams.main.model import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.gyf.lib.util.randomChinese -import com.gyf.lib.util.randomNum -import com.orhanobut.logger.Logger -import kotlinx.coroutines.launch +import com.gyf.lib.util.AllOfficerVo +import com.gyf.lib.util.ManagerInfoVo enum class ColumnType { Text, DropMenu } -/** - * 职务 - * - * @property desc - */ -enum class Duty(val desc: String) { - Minister("部长"), - Manager("干事") -} - -/** - * 人员信息 - * - * @property name 名字 - * @property studentId 学号 - * @property mobile 手机号 - * @property duty 职务 - * @property counselor 导员 - */ -data class OfficerVo( - val name: String, - val studentId: String, - val mobile: String, - val duty: Duty, - val counselor: String -) - -data class AllOfficerVo( - val secretariat: MutableList, - val propaganda: MutableList, - val publicRelationsDepartment: MutableList -) /** * 部门干事数据状态管理 @@ -55,69 +20,20 @@ class ManagementOfficerModel : ViewModel() { private val _data = MutableLiveData() val data: LiveData = _data + init { load() } - private fun replace( - list: MutableList, - index: Int, - callback: (s: MutableList) -> Unit - ) { - val s = mutableListOf() - list[index] = list[index].copy(duty = Duty.Minister) - s.add(list[index]) - s.addAll(list.filter { officerVo -> officerVo != list[index] } - .map { officerVo -> officerVo.copy(duty = Duty.Manager) }) - callback(s) - } - - fun updateDuty(list: MutableList, index: Int) { - _data.value?.apply { - Logger.i("$secretariat") - when (list) { - secretariat -> replace(list = list, index = index) { - _data.postValue(copy(secretariat = it)) - } - propaganda -> replace(list = list, index = index) { - _data.postValue(copy(propaganda = it)) - } - publicRelationsDepartment -> replace(list = list, index = index) { - _data.postValue(copy(publicRelationsDepartment = it)) - } - } - - - } + fun updateDuty(list: MutableList, index: Int) { + TODO("更新职务") } /** - * TODO 加载部门成员 * */ private fun load() { - viewModelScope.launch { - val officerVoList = mutableListOf() - val baseSize = 3 - val peopleSize = 5 - repeat(peopleSize * baseSize) { - officerVoList.add( - OfficerVo( - name = randomChinese(3), studentId = randomNum(8), mobile = randomNum(11), - if (it % peopleSize == 0) Duty.Minister else Duty.Manager, counselor = "" - ) - ) - } - val all = officerVoList.chunked(peopleSize) - _data.postValue( - AllOfficerVo( - secretariat = all[0].toMutableList(), - propaganda = all[1].toMutableList(), - publicRelationsDepartment = all[2].toMutableList() - ) - ) - } - + TODO("加载部门成员") } } \ No newline at end of file diff --git a/background/src/main/java/com/gyf/csams/main/model/ManagerActViewModel.kt b/background/src/main/java/com/gyf/csams/main/model/ManagerActViewModel.kt index 10c9b96..f3180ea 100644 --- a/background/src/main/java/com/gyf/csams/main/model/ManagerActViewModel.kt +++ b/background/src/main/java/com/gyf/csams/main/model/ManagerActViewModel.kt @@ -1,17 +1,12 @@ package com.gyf.csams.main.model import android.app.Application -import androidx.annotation.IntRange import com.gyf.lib.model.ScrollViewModel +import com.gyf.lib.util.ActivityVo import com.gyf.lib.util.randomChinese import com.gyf.lib.util.randomDateTime import com.gyf.lib.util.randomNum -import java.util.* -data class ActivityVo( - val activityId: Long, val activityName: String, val association: String, - @IntRange(from = 1, to = MAX_SCORE) val score: Int, val activityTime: Date, val location: String -) /** * 活动信息数据管理 diff --git a/background/src/main/java/com/gyf/csams/main/model/MenuViewModel.kt b/background/src/main/java/com/gyf/csams/main/model/MenuViewModel.kt index b8c0591..53e7fc1 100644 --- a/background/src/main/java/com/gyf/csams/main/model/MenuViewModel.kt +++ b/background/src/main/java/com/gyf/csams/main/model/MenuViewModel.kt @@ -9,7 +9,8 @@ enum class MenuType(val desc: String, val clazz: Map "社团管理", mapOf( "社团信息管理" to AssociationManagementActivity::class.java, - "审核换名申请表" to RenameActivity::class.java + "审核社团换名" to RenameActivity::class.java, + "审核社团注册" to AuditAssociationActivity::class.java ), ), Act( diff --git a/background/src/main/java/com/gyf/csams/main/model/RenameViewModel.kt b/background/src/main/java/com/gyf/csams/main/model/RenameViewModel.kt index 4086745..73375c6 100644 --- a/background/src/main/java/com/gyf/csams/main/model/RenameViewModel.kt +++ b/background/src/main/java/com/gyf/csams/main/model/RenameViewModel.kt @@ -5,29 +5,19 @@ import androidx.lifecycle.viewModelScope import com.gyf.csams.R import com.gyf.lib.model.ScrollViewModel import com.gyf.lib.uikit.StringForm +import com.gyf.lib.util.RenameVo import com.gyf.lib.util.randomChinese import com.gyf.lib.util.randomNum import kotlinx.coroutines.launch -/** - * 换名申请表 - * - * @property studentId 学号 - * @property oldName 社团原名 - * @property newName 社团新名 - * @property reason 申请理由 - */ -data class RenameVo( - val studentId: String, - val oldName: String, - val newName: String, - val reason: String -) class RenameViewModel(application: Application) : ScrollViewModel(application) { val approverOrigin = - StringForm(formDesc = application.getString(R.string.approver_origin), textLength = 30) + StringForm( + formDesc = application.getString(R.string.first_approver_origin), + textLength = 30 + ) override val initSize: Int = 10 diff --git a/background/src/main/java/com/gyf/csams/main/ui/AssociationManagementActivity.kt b/background/src/main/java/com/gyf/csams/main/ui/AssociationManagementActivity.kt index aaa854c..3672ae5 100644 --- a/background/src/main/java/com/gyf/csams/main/ui/AssociationManagementActivity.kt +++ b/background/src/main/java/com/gyf/csams/main/ui/AssociationManagementActivity.kt @@ -16,10 +16,10 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel -import com.gyf.csams.main.model.AssociationLevel import com.gyf.csams.main.model.AssociationManagementViewModel import com.gyf.lib.uikit.Body import com.gyf.lib.uikit.MainBoxFrame +import com.gyf.lib.util.AssociationLevel /** * 社团管理 @@ -52,7 +52,7 @@ class AssociationManagementActivity : ComponentActivity() { horizontalArrangement = Arrangement.SpaceBetween ) { Text( - text = "$associationId", + text = "$id", style = MaterialTheme.typography.h6 ) Text( @@ -68,7 +68,9 @@ class AssociationManagementActivity : ComponentActivity() { verticalAlignment = Alignment.CenterVertically ) { Text( - text = commander, + text = "" + /**TODO 用户**/ + , style = MaterialTheme.typography.h5 ) Text( @@ -80,7 +82,7 @@ class AssociationManagementActivity : ComponentActivity() { expanded = true }) { Text( - text = level.name, + text = level?.name ?: "暂无评级", style = MaterialTheme.typography.h5 ) DropdownMenu( @@ -89,7 +91,7 @@ class AssociationManagementActivity : ComponentActivity() { AssociationLevel.values().forEach { DropdownMenuItem(onClick = { model.update( - associationVo = this@apply, + associationDto = this@apply, level = it ) expanded = false diff --git a/background/src/main/java/com/gyf/csams/main/ui/AuditAssociationActivity.kt b/background/src/main/java/com/gyf/csams/main/ui/AuditAssociationActivity.kt new file mode 100644 index 0000000..20ddfa1 --- /dev/null +++ b/background/src/main/java/com/gyf/csams/main/ui/AuditAssociationActivity.kt @@ -0,0 +1,310 @@ +package com.gyf.csams.main.ui + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.Image +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.* +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.ExperimentalComposeApi +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.core.view.WindowCompat +import androidx.lifecycle.viewmodel.compose.viewModel +import com.google.accompanist.coil.rememberCoilPainter +import com.google.accompanist.insets.ExperimentalAnimatedInsets +import com.google.accompanist.insets.navigationBarsWithImePadding +import com.gyf.csams.R +import com.gyf.csams.main.model.AuditAssociationViewModel +import com.gyf.csams.uikit.RowItem +import com.gyf.csams.uikit.TestTableImeSimple +import com.gyf.lib.uikit.* +import com.gyf.lib.util.* + +class AuditAssociationActivity : ComponentActivity() { + @ExperimentalMaterialApi + @ExperimentalAnimatedInsets + @ExperimentalComposeApi + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + WindowCompat.setDecorFitsSystemWindows(window, false) + setContent { + ImeBody { + val model: AuditAssociationViewModel = viewModel() + val data by model.data.observeAsState() + TestTableImeSimple( + title = R.string.association_reg_title + ) { + data?.forEach { + item { + RegisterForm(vo = it) + Spacer(modifier = Modifier.height(10.dp)) + } + } + } + } + } + } + + + @Composable + private fun CheckForm( + vo: DisposeRegInfoVo, + scaffoldModel: ScaffoldModel = viewModel(), + auditAssociationViewModel: AuditAssociationViewModel = viewModel(), + first: @Composable () -> Unit, + last: @Composable () -> Unit + ) { + val baseHeight = 50.dp + + (TokenManager.getOwnInfo() as? ManagerVo)?.let { it -> + var confirmDesc: Int? = null + var backDesc: Int? = null + var onConfirm: (() -> Unit)? = null + var onBack: (() -> Unit)? = null + val check: (result: Boolean, cause: StringForm) -> Unit = + { result: Boolean, cause: StringForm -> + scaffoldModel.update( + message = "确认${if (result) "上报" else "驳回"}?", + actionLabel = "确认" + ) { + auditAssociationViewModel.check( + regId = vo.log.id, + result = result, + cause = cause.formValue.value + ?: throw IllegalArgumentException("无法获取审核理由") + ) { + scaffoldModel.update(message = it, actionLabel = "刷新") { + auditAssociationViewModel.load { } + } + } + } + } + + val accept: (m: String, isFirstAccept: Boolean) -> Unit = + { m: String, isFirstAccept: Boolean -> + scaffoldModel.update("确认${m}?", actionLabel = "确认") { + auditAssociationViewModel.accept( + regId = vo.log.id, + isFirstAccept = isFirstAccept + ) { + scaffoldModel.update(message = it, actionLabel = "刷新") { + auditAssociationViewModel.load { } + } + } + } + } + + val doCheck: @Composable () -> Unit = { + val cause = ValidStringForm( + formDesc = "审核理由", + textLength = 20 + ) + val statusForm by cause.statusForm.observeAsState() + + onConfirm = { + if (statusForm == FormStatus.Empty) { + scaffoldModel.update("${cause.formDesc}不能为空", actionLabel = "知道了") + } else { + check(true, cause) + } + } + onBack = { + if (statusForm == FormStatus.Empty) { + scaffoldModel.update("${cause.formDesc}不能为空", actionLabel = "知道了") + } else { + check(false, cause) + } + } + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + BaseTextField( + modifier = Modifier.navigationBarsWithImePadding(), + form = cause + ) + } + } + + when { + //初审记录,负责人为空 等待初审 + vo.log.nextAudit == null && vo.log.manager == null -> { + if (it.duty == Duty.PamphaBhusal) { + confirmDesc = R.string.accept_btn + onConfirm = { accept("受理", true) } + } + first() + RowItem(key = R.string.first_approver_origin, value = "") + RowItem(key = R.string.first_result, value = "") + last() + RowItem(key = R.string.last_approver_origin, value = "") + RowItem(key = R.string.last_result, value = "") + RowItem( + modifier = Modifier.height(baseHeight), + key = R.string.audit_phases, value = "等待初审" + ) + } + //初审记录,负责人不为空 初审受理 + vo.log.nextAudit == null && vo.log.manager != null -> { + + first() + if (it.duty == Duty.PamphaBhusal) { + confirmDesc = R.string.reported_btn + backDesc = R.string.reject_btn + + doCheck() + } else { + RowItem(key = R.string.first_approver_origin, value = "") + } + RowItem(key = R.string.first_result, value = "") + last() + RowItem(key = R.string.last_approver_origin, value = "") + RowItem(key = R.string.last_result, value = "") + RowItem( + modifier = Modifier.height(baseHeight), + key = R.string.audit_phases, value = "初审受理" + ) + } + //初审记录,审核通过(上报) 等待复审 + vo.log.nextAudit != null && vo.log.nextAudit?.manager == null -> { + + if (it.duty == Duty.Teacher) { + confirmDesc = R.string.recheck_btn + onConfirm = { accept("复审", false) } + } + first() + RowItem(key = R.string.first_approver_origin, value = vo.log.cause) + RowItem(key = R.string.first_result, value = "通过") + last() + RowItem(key = R.string.last_approver_origin, value = "") + RowItem(key = R.string.last_result, value = "") + RowItem( + modifier = Modifier.height(baseHeight), + key = R.string.audit_phases, value = "等待复审" + ) + } + //复审记录,审核结果为空 复审受理 + vo.log.nextAudit != null && vo.log.nextAudit?.result == null -> { + first() + RowItem(key = R.string.first_approver_origin, value = vo.log.cause) + RowItem(key = R.string.first_result, value = "通过") + last() + if (it.duty == Duty.Teacher) { + confirmDesc = R.string.allow_btn + backDesc = R.string.reject_btn + doCheck() + } else { + RowItem(key = R.string.last_approver_origin, value = "") + } + RowItem(key = R.string.last_result, value = "") + RowItem( + modifier = Modifier.height(baseHeight), + key = R.string.audit_phases, value = "复审受理" + ) + } + else -> { + first() + RowItem(key = R.string.first_approver_origin, value = vo.log.cause) + RowItem( + key = R.string.first_result, value = when (vo.log.result) { + null -> "" + true -> "通过" + false -> "不通过" + } + ) + last() + RowItem( + key = R.string.last_approver_origin, + value = vo.log.nextAudit?.cause ?: "" + ) + RowItem( + key = R.string.last_result, value = when (vo.log.nextAudit?.result) { + null -> "" + true -> "通过" + false -> "不通过" + } + ) + RowItem( + modifier = Modifier.height(baseHeight), + key = R.string.audit_phases, value = "完成审核" + ) + } + } + + if (confirmDesc != null) { + BottomButton( + confirmDesc = confirmDesc, + backDesc = backDesc, + modifier = Modifier.fillMaxWidth(), + onBack = onBack + ) { + onConfirm?.let { it() } + } + } + } + } + + @Composable + private fun RegisterForm( + modifier: Modifier = Modifier, vo: DisposeRegInfoVo + ) { + Column( + modifier = modifier.border( + width = 1.dp, + color = MaterialTheme.colors.onBackground + ) + ) { + val baseHeight = 50.dp + + RowItem( + modifier = Modifier.height(baseHeight), + key = R.string.petitioner, + value = vo.log.user.name + ) + + RowItem( + modifier = Modifier.height(baseHeight), + key = R.string.association_name, + value = vo.name + ) + + RowItem( + modifier = Modifier.height(baseHeight), + key = R.string.association_desc, + value = vo.desc + ) + + RowItem( + modifier = Modifier.height(baseHeight * 3), + key = R.string.association_logo + ) { + //TODO 图片全屏显示 + val painter = + rememberCoilPainter("${com.gyf.lib.BuildConfig.SERVER_ADDRESS}/${vo.logo}") + Image(painter = painter, contentDescription = null) + } + + CheckForm(vo = vo, first = { + RowItem( + modifier = Modifier.height(baseHeight), + key = R.string.first_approver, + value = vo.log.manager?.name ?: "" + ) + }, last = { + RowItem( + modifier = Modifier.height(baseHeight), + key = R.string.last_approver, + value = vo.log.nextAudit?.manager?.name ?: "" + ) + }) + + } + } +} \ No newline at end of file diff --git a/background/src/main/java/com/gyf/csams/main/ui/CheckActActivity.kt b/background/src/main/java/com/gyf/csams/main/ui/CheckActActivity.kt index 5478d15..95ac2b5 100644 --- a/background/src/main/java/com/gyf/csams/main/ui/CheckActActivity.kt +++ b/background/src/main/java/com/gyf/csams/main/ui/CheckActActivity.kt @@ -13,13 +13,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel +import com.google.accompanist.insets.ExperimentalAnimatedInsets import com.gyf.csams.R -import com.gyf.csams.main.model.ApplyActVo import com.gyf.csams.main.model.CheckActViewModel import com.gyf.csams.uikit.RowItem import com.gyf.csams.uikit.TestTable import com.gyf.lib.uikit.BaseTextField import com.gyf.lib.uikit.ScaffoldModel +import com.gyf.lib.util.ApplyActVo import com.gyf.lib.util.BottomButton /** @@ -27,6 +28,7 @@ import com.gyf.lib.util.BottomButton * */ class CheckActActivity : ComponentActivity() { + @ExperimentalAnimatedInsets @ExperimentalComposeApi override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -69,11 +71,14 @@ class CheckActActivity : ComponentActivity() { value = "${vo.size}" ) RowItem( - modifier = Modifier.height(baseHeight), key = R.string.approver, value = "" + modifier = Modifier.height(baseHeight), key = R.string.first_approver, value = "" /**TODO 获取审批人**/ ) - RowItem(modifier = Modifier.height(baseHeight * 3), key = R.string.approver_origin) { - BaseTextField(modifier = Modifier.fillMaxSize(), form = model.approverOrigin) + RowItem( + modifier = Modifier.height(baseHeight * 3), + key = R.string.first_approver_origin + ) { + BaseTextField(modifier = Modifier.fillMaxSize(), form = model.approveOrigin) } val message = stringResource(id = R.string.not_impl_error) BottomButton( diff --git a/background/src/main/java/com/gyf/csams/main/ui/CheckQualityReportActivity.kt b/background/src/main/java/com/gyf/csams/main/ui/CheckQualityReportActivity.kt index ef09308..57070af 100644 --- a/background/src/main/java/com/gyf/csams/main/ui/CheckQualityReportActivity.kt +++ b/background/src/main/java/com/gyf/csams/main/ui/CheckQualityReportActivity.kt @@ -12,21 +12,23 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel +import com.google.accompanist.insets.ExperimentalAnimatedInsets import com.gyf.csams.R import com.gyf.csams.main.model.CheckQualityReportViewModel -import com.gyf.csams.main.model.MAX_SCORE -import com.gyf.csams.main.model.QualityReportVo import com.gyf.csams.uikit.RowItem import com.gyf.csams.uikit.TestTable import com.gyf.lib.uikit.BaseTextField import com.gyf.lib.uikit.ScaffoldModel import com.gyf.lib.util.BottomButton +import com.gyf.lib.util.MAX_SCORE +import com.gyf.lib.util.QualityReportVo /** * 审批质量报告单 * */ class CheckQualityReportActivity : ComponentActivity() { + @ExperimentalAnimatedInsets @ExperimentalComposeApi override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -86,11 +88,14 @@ class CheckQualityReportActivity : ComponentActivity() { } } RowItem( - modifier = Modifier.height(baseHeight), key = R.string.approver, value = "" + modifier = Modifier.height(baseHeight), key = R.string.first_approver, value = "" /**TODO 获取审批人**/ ) - RowItem(modifier = Modifier.height(baseHeight * 3), key = R.string.approver_origin) { - BaseTextField(modifier = Modifier.fillMaxSize(), form = model.approverOrigin) + RowItem( + modifier = Modifier.height(baseHeight * 3), + key = R.string.first_approver_origin + ) { + BaseTextField(modifier = Modifier.fillMaxSize(), form = model.approveOrigin) } val message = stringResource(id = R.string.not_impl_error) BottomButton( diff --git a/background/src/main/java/com/gyf/csams/main/ui/MainActivity.kt b/background/src/main/java/com/gyf/csams/main/ui/MainActivity.kt index f7cc5bf..e57e1bf 100644 --- a/background/src/main/java/com/gyf/csams/main/ui/MainActivity.kt +++ b/background/src/main/java/com/gyf/csams/main/ui/MainActivity.kt @@ -9,19 +9,18 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.OutlinedButton import androidx.compose.material.Text -import androidx.compose.runtime.getValue -import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.gyf.csams.R import com.gyf.csams.account.model.LoginViewModel -import com.gyf.csams.main.model.MainViewModel import com.gyf.csams.main.model.MenuType import com.gyf.lib.service.BaseActivity import com.gyf.lib.uikit.* import com.gyf.lib.util.ClientType +import com.gyf.lib.util.ManagerInfoVo +import com.gyf.lib.util.TokenManager class MainActivity : BaseActivity() { @@ -32,22 +31,33 @@ class MainActivity : BaseActivity() { setContent { Body { - val model: MainViewModel = viewModel() val loginViewModel: LoginViewModel = viewModel() val scaffoldModel: ScaffoldModel = viewModel() - val person by model.person.observeAsState() MainColumnFrame(background = { /*TODO*/ }) { - person?.let { + (TokenManager.getPersonInfo() as? ManagerInfoVo)?.let { Profile( modifier = Modifier .weight(0.3F) - .padding(10.dp), personInfoVo = it + .padding(10.dp), + personInfoVo = it ) } Column( modifier = Modifier.weight(0.7F), verticalArrangement = Arrangement.SpaceEvenly ) { + + OutlinedButton(onClick = { + startActivity( + Intent( + this@MainActivity, + NotificationActivity::class.java + ) + ) + }, modifier = Modifier.fillMaxWidth()) { + Text(text = "我的通知") + } + OutlinedButton(onClick = { startActivity(Intent(this@MainActivity, DepartmentActivity::class.java)) }, modifier = Modifier.fillMaxWidth()) { diff --git a/background/src/main/java/com/gyf/csams/main/ui/ManagementOfficerActivity.kt b/background/src/main/java/com/gyf/csams/main/ui/ManagementOfficerActivity.kt index 0c10c81..0da4b4b 100644 --- a/background/src/main/java/com/gyf/csams/main/ui/ManagementOfficerActivity.kt +++ b/background/src/main/java/com/gyf/csams/main/ui/ManagementOfficerActivity.kt @@ -21,14 +21,12 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.gyf.csams.R -import com.gyf.csams.main.model.Duty import com.gyf.csams.main.model.ManagementOfficerModel -import com.gyf.csams.main.model.MinisterVo -import com.gyf.csams.main.model.OfficerVo import com.gyf.lib.uikit.Body import com.gyf.lib.uikit.MainColumnFrame import com.gyf.lib.uikit.Profile import com.gyf.lib.uikit.ScaffoldModel +import com.gyf.lib.util.ManagerInfoVo import com.orhanobut.logger.Logger /** @@ -99,7 +97,7 @@ class ManagementOfficerActivity : ComponentActivity() { model: ManagementOfficerModel = viewModel(), scaffoldModel: ScaffoldModel = viewModel(), @StringRes id: Int, - officerVoList: MutableList, + officerVoList: MutableList, ) { Column( modifier = modifier @@ -124,19 +122,13 @@ class ManagementOfficerActivity : ComponentActivity() { .width(200.dp) .fillMaxHeight() .border(width = 1.dp, color = MaterialTheme.colors.onBackground), - personInfoVo = - MinisterVo( - name = it.value.name, - duty = it.value.duty.desc, - headImg = "", - desc = it.value.mobile - ) + personInfoVo = it.value ) { Logger.i("expanded=$expanded") Text( text = it.value.duty.desc, modifier = Modifier.clickable(onClick = { - if (it.value.duty.desc != Duty.Minister.desc) expanded = + if (it.value.duty.isOfficer()) expanded = true else scaffoldModel .update(message = context.getString(R.string.update_duty_error)) }) @@ -149,7 +141,7 @@ class ManagementOfficerActivity : ComponentActivity() { model.updateDuty(list = officerVoList, index = it.index) expanded = false }) { - Text(text = Duty.Minister.desc) + Text(text = it.value.duty.desc) } } } diff --git a/background/src/main/java/com/gyf/csams/main/ui/ManagerActActivity.kt b/background/src/main/java/com/gyf/csams/main/ui/ManagerActActivity.kt index 66017c9..f4c53fb 100644 --- a/background/src/main/java/com/gyf/csams/main/ui/ManagerActActivity.kt +++ b/background/src/main/java/com/gyf/csams/main/ui/ManagerActActivity.kt @@ -13,12 +13,13 @@ import androidx.compose.runtime.ExperimentalComposeApi import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp +import com.google.accompanist.insets.ExperimentalAnimatedInsets import com.gyf.csams.R -import com.gyf.csams.main.model.ActivityVo -import com.gyf.csams.main.model.MAX_SCORE import com.gyf.csams.main.model.ManagerActViewModel import com.gyf.csams.uikit.RowItem import com.gyf.csams.uikit.TestTable +import com.gyf.lib.util.ActivityVo +import com.gyf.lib.util.MAX_SCORE import com.gyf.lib.util.format /** @@ -26,6 +27,7 @@ import com.gyf.lib.util.format * */ class ManagerActActivity : ComponentActivity() { + @ExperimentalAnimatedInsets @ExperimentalComposeApi override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/background/src/main/java/com/gyf/csams/main/ui/NotificationActivity.kt b/background/src/main/java/com/gyf/csams/main/ui/NotificationActivity.kt new file mode 100644 index 0000000..0260864 --- /dev/null +++ b/background/src/main/java/com/gyf/csams/main/ui/NotificationActivity.kt @@ -0,0 +1,80 @@ +package com.gyf.csams.main.ui + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.Card +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.gyf.csams.main.model.BackgroundViewModel +import com.gyf.lib.uikit.Body +import com.gyf.lib.uikit.MainColumnFrame +import com.gyf.lib.util.NotificationVo +import com.gyf.lib.util.format +import java.util.* + +/** + * 通知 + * + */ +class NotificationActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContent { + Body { + val model: BackgroundViewModel = viewModel() + val data by model.data.observeAsState() + MainColumnFrame(background = { /*TODO*/ }) { + if (data?.size == 0) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + Text(text = "目前没有收到任何通知") + } + } + LazyColumn { + data?.forEach { + item { + MessageItem(content = it) + } + } + } + } + } + } + } + + @Composable + private fun MessageItem(modifier: Modifier = Modifier, content: NotificationVo) { + Card(modifier = modifier, backgroundColor = MaterialTheme.colors.background) { + Column(modifier = Modifier.padding(10.dp)) { + Text(text = content.title, style = MaterialTheme.typography.h5) + Spacer(modifier = Modifier.height(5.dp)) + + Card( + backgroundColor = MaterialTheme.colors.background, + modifier = Modifier + .fillMaxWidth() + .padding(10.dp) + ) { + Text(text = content.content) + } + + Spacer(modifier = Modifier.height(10.dp)) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { + Text(text = Date(content.createTime).format()) + } + } + } + } +} \ No newline at end of file diff --git a/background/src/main/java/com/gyf/csams/main/ui/RenameActivity.kt b/background/src/main/java/com/gyf/csams/main/ui/RenameActivity.kt index 27d3c37..9e53a51 100644 --- a/background/src/main/java/com/gyf/csams/main/ui/RenameActivity.kt +++ b/background/src/main/java/com/gyf/csams/main/ui/RenameActivity.kt @@ -13,17 +13,19 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel +import com.google.accompanist.insets.ExperimentalAnimatedInsets import com.gyf.csams.R import com.gyf.csams.main.model.RenameViewModel -import com.gyf.csams.main.model.RenameVo import com.gyf.csams.uikit.RowItem import com.gyf.csams.uikit.TestTable import com.gyf.lib.uikit.BaseTextField import com.gyf.lib.uikit.ScaffoldModel import com.gyf.lib.util.BottomButton +import com.gyf.lib.util.RenameVo class RenameActivity : ComponentActivity() { + @ExperimentalAnimatedInsets @ExperimentalComposeApi override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -63,10 +65,13 @@ class RenameActivity : ComponentActivity() { value = renameVo.reason ) RowItem( - modifier = Modifier.height(baseHeight), key = R.string.approver, value = "" + modifier = Modifier.height(baseHeight), key = R.string.first_approver, value = "" /**TODO 获取审批人**/ ) - RowItem(modifier = Modifier.height(baseHeight * 3), key = R.string.approver_origin) { + RowItem( + modifier = Modifier.height(baseHeight * 3), + key = R.string.first_approver_origin + ) { BaseTextField(modifier = Modifier.fillMaxSize(), form = model.approverOrigin) } val message = stringResource(id = R.string.not_impl_error) diff --git a/background/src/main/java/com/gyf/csams/uikit/Table.kt b/background/src/main/java/com/gyf/csams/uikit/Table.kt index 384f86a..1ab38d1 100644 --- a/background/src/main/java/com/gyf/csams/uikit/Table.kt +++ b/background/src/main/java/com/gyf/csams/uikit/Table.kt @@ -2,25 +2,27 @@ package com.gyf.csams.uikit import androidx.annotation.StringRes import androidx.compose.foundation.border +import androidx.compose.foundation.gestures.scrollBy import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.ExperimentalComposeApi -import androidx.compose.runtime.getValue +import androidx.compose.material.* +import androidx.compose.runtime.* import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel +import com.google.accompanist.insets.* import com.gyf.lib.model.ScrollViewModel import com.gyf.lib.uikit.Body import com.gyf.lib.uikit.MainColumnFrame + /** * 表格 * @@ -65,6 +67,53 @@ fun TestTable( } } +@ExperimentalAnimatedInsets +@ExperimentalMaterialApi +@Composable +fun TestTableImeSimple( + modifier: Modifier = Modifier, + @StringRes title: Int? = null, + content: LazyListScope.() -> Unit +) { + Column(modifier = modifier) { + title?.let { + Spacer(modifier = Modifier.height(20.dp)) + Row( + modifier = Modifier + .fillMaxWidth() + .border(width = 1.dp, color = MaterialTheme.colors.onBackground), + horizontalArrangement = Arrangement.Center, + ) { + Text( + text = stringResource(id = title), + style = MaterialTheme.typography.h4 + ) + } + } + val listState = rememberLazyListState() + + val insets = LocalWindowInsets.current + val imeBottom = with(LocalDensity.current) { insets.ime.bottom.toDp() } + LazyColumn( + modifier = Modifier.fillMaxSize(), + state = listState, + content = content + ) + LaunchedEffect(imeBottom) { + listState.scrollBy(imeBottom.value) + } + + } +} + +/** + * 表格行 + * + * @param modifier + * @param key + * @param value + * @param content + */ /** * 表格行 * diff --git a/background/src/main/res/values-en/strings.xml b/background/src/main/res/values-en/strings.xml index 1eed946..e8ec0f5 100644 --- a/background/src/main/res/values-en/strings.xml +++ b/background/src/main/res/values-en/strings.xml @@ -26,4 +26,9 @@ 活动编号 活动社团 活动地点 + 受理 + 通过 + 复审负责人 + 初审结果 + 复审结果 \ No newline at end of file diff --git a/background/src/main/res/values-zh/strings.xml b/background/src/main/res/values-zh/strings.xml index 1eed946..e8ec0f5 100644 --- a/background/src/main/res/values-zh/strings.xml +++ b/background/src/main/res/values-zh/strings.xml @@ -26,4 +26,9 @@ 活动编号 活动社团 活动地点 + 受理 + 通过 + 复审负责人 + 初审结果 + 复审结果 \ No newline at end of file diff --git a/background/src/main/res/values/strings.xml b/background/src/main/res/values/strings.xml index 1eed946..e8ec0f5 100644 --- a/background/src/main/res/values/strings.xml +++ b/background/src/main/res/values/strings.xml @@ -26,4 +26,9 @@ 活动编号 活动社团 活动地点 + 受理 + 通过 + 复审负责人 + 初审结果 + 复审结果 \ No newline at end of file diff --git a/background/src/test/java/com/gyf/csams/ExampleUnitTest.kt b/background/src/test/java/com/gyf/csams/ExampleUnitTest.kt index 8acd231..2829394 100644 --- a/background/src/test/java/com/gyf/csams/ExampleUnitTest.kt +++ b/background/src/test/java/com/gyf/csams/ExampleUnitTest.kt @@ -1,5 +1,8 @@ package com.gyf.csams +import com.google.gson.reflect.TypeToken +import com.gyf.lib.util.ApiResponse +import com.orhanobut.logger.Logger import org.junit.Assert.assertEquals import org.junit.Test @@ -13,4 +16,14 @@ class ExampleUnitTest { fun addition_isCorrect() { assertEquals(4, 2 + 2) } + + @Test + fun typeToken() { + initToken() + } + + inline fun initToken() { + val typeToken = object : TypeToken>() {}.type + Logger.i("typeToken=$typeToken") + } } \ No newline at end of file diff --git a/foreground/src/main/AndroidManifest.xml b/foreground/src/main/AndroidManifest.xml index 93cd004..8465d84 100644 --- a/foreground/src/main/AndroidManifest.xml +++ b/foreground/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="com.gyf.csams"> + diff --git a/foreground/src/main/java/com/gyf/csams/InitActivity.kt b/foreground/src/main/java/com/gyf/csams/InitActivity.kt index 11f50ad..d364379 100644 --- a/foreground/src/main/java/com/gyf/csams/InitActivity.kt +++ b/foreground/src/main/java/com/gyf/csams/InitActivity.kt @@ -1,14 +1,20 @@ package com.gyf.csams import android.app.Activity +import com.google.gson.reflect.TypeToken import com.gyf.csams.account.ui.AccountActivity import com.gyf.csams.main.ui.MainActivity import com.gyf.lib.uikit.AbstractInitActivity import com.gyf.lib.util.AccountApi +import com.gyf.lib.util.ApiResponse +import com.gyf.lib.util.UserVo +import java.lang.reflect.Type -class InitActivity : AbstractInitActivity() { +class InitActivity : AbstractInitActivity() { override val main: Class = MainActivity::class.java override val login: Class = AccountActivity::class.java override val api: AccountApi = AccountApi.ForegroundToken + + override val typeToken: Type = object : TypeToken>() {}.type } \ No newline at end of file diff --git a/foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt b/foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt index 3e7999e..fd11abd 100644 --- a/foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt +++ b/foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt @@ -10,7 +10,6 @@ import com.google.gson.reflect.TypeToken import com.gyf.csams.R import com.gyf.csams.account.ui.AccountActivity import com.gyf.csams.account.ui.AccountRoute -import com.gyf.csams.util.SimpleCallback import com.gyf.lib.model.AbstractLoginViewModel import com.gyf.lib.uikit.FormStatus import com.gyf.lib.uikit.ValidStringForm @@ -19,37 +18,14 @@ import com.orhanobut.logger.Logger import kotlinx.coroutines.Job import kotlinx.coroutines.launch -/** - * 响应自动生成密码 - * - * @property password - */ -data class UserResDto(val password: String) - -/** - * 构造登录、注册信息实体表单 - * - * @property studentId 学号 - * @property name 姓名 - */ -data class UserVo(val studentId: String, val name: String) - -/** - * 用户登陆表单 - * - * @property studentId 学号 - * @property password 密码 - * @property device 设备型号 - */ -data class UserLoginVo(val studentId: String, val password: String, val device: String) /** * 密码弹窗信息 * * @property message - * @property userResDto + * @property userPasswordVo */ -data class DialogMessage(val message: String, val userResDto: UserResDto?) +data class DialogMessage(val message: String, val userPasswordVo: UserPasswordVo?) /** * 注册表单 @@ -139,7 +115,7 @@ class AccountViewModel(application: Application) : AbstractLoginViewModel(applic val url = Api.buildUrl(AccountApi.CheckId) Logger.i("检测${id.formDesc},请求接口$url") HttpClient.get( - url, SimpleCallback( + url, HttpCallback( action = "${id.formDesc}重复检测", onSuccess = { if (it.body == true) { @@ -150,7 +126,7 @@ class AccountViewModel(application: Application) : AbstractLoginViewModel(applic checkForm() }, onFail = { Logger.e(it) }, - type = object : TypeToken>() {}.type + typeToken = object : TypeToken>() {}.type ), mapOf("studentId" to "${id.formValue.value}") ) } @@ -188,22 +164,22 @@ class AccountViewModel(application: Application) : AbstractLoginViewModel(applic val url = Api.buildUrl(AccountApi.Register) Logger.i("开始$regBtnDesc,请求接口:$url") HttpClient.post( - url, SimpleCallback( + url, HttpCallback( action = regBtnDesc, onSuccess = { _dialogMsg.postValue( DialogMessage( message = it.message, - userResDto = it.body + userPasswordVo = it.body ) ) }, onFail = onFail, - type = object : TypeToken>() {}.type + typeToken = object : TypeToken>() {}.type ), - jsonParam = UserVo( - studentId = "${id.formValue.value}", - name = "${name.formValue.value}" + jsonParam = UserRegVo( + studentId = id.formValue.value ?: throw IllegalArgumentException("学号为空"), + name = name.formValue.value ?: throw IllegalArgumentException("姓名为空") ) ) resetForm() diff --git a/foreground/src/main/java/com/gyf/csams/account/ui/AccountActivity.kt b/foreground/src/main/java/com/gyf/csams/account/ui/AccountActivity.kt index 7babd1e..56d3be5 100644 --- a/foreground/src/main/java/com/gyf/csams/account/ui/AccountActivity.kt +++ b/foreground/src/main/java/com/gyf/csams/account/ui/AccountActivity.kt @@ -41,7 +41,7 @@ class AccountActivity : ComponentActivity() { super.onCreate(savedInstanceState) setContent { - TestBody { nav, scaffoldState -> + NavBody { nav, scaffoldState -> NavHost(navController = nav, startDestination = AccountRoute.Login.name) { composable(AccountRoute.Login.name) { Account( @@ -241,7 +241,7 @@ class AccountActivity : ComponentActivity() { private fun RegisterDialog(accountViewModel: AccountViewModel = viewModel()) { val dialogMsg: DialogMessage? by accountViewModel.dialogMsg.observeAsState(null) - val message = dialogMsg?.userResDto?.password + val message = dialogMsg?.userPasswordVo?.password if (message?.isNotEmpty() == true) { PasswordDialog(message = message) } diff --git a/foreground/src/main/java/com/gyf/csams/activity/model/ActivityDetailViewModel.kt b/foreground/src/main/java/com/gyf/csams/activity/model/ActivityDetailViewModel.kt index 89f3f9a..5e91c8a 100644 --- a/foreground/src/main/java/com/gyf/csams/activity/model/ActivityDetailViewModel.kt +++ b/foreground/src/main/java/com/gyf/csams/activity/model/ActivityDetailViewModel.kt @@ -10,13 +10,9 @@ import com.gyf.csams.uikit.ActivityDetailMenu import com.gyf.csams.uikit.TopMenuInterface import com.gyf.lib.model.ScrollViewModel import com.gyf.lib.uikit.ValidStringForm -import com.gyf.lib.util.NOT_IMPL_TIP -import com.gyf.lib.util.randomChinese -import com.gyf.lib.util.randomDateTime -import com.gyf.lib.util.randomNum +import com.gyf.lib.util.* import com.orhanobut.logger.Logger import kotlinx.coroutines.launch -import java.util.* /** * 活动详情菜单通用状态 @@ -27,21 +23,6 @@ class ActivityDetailViewModel : ViewModel(), TopMenuInterface = _currentMenu } -/** - * TODO - * - * @property associationName 社团名字 - * @property activityName 活动名 - * @property activityTime 活动时间 - * @property activityLocation 活动地点 - * @property activityDesc 活动介绍 - */ -data class ActivityDetailVo( - val associationName: String, val activityName: String, - val activityTime: Date, val activityLocation: String, - val activityDesc: String -) - /** * 活动信息 @@ -91,23 +72,6 @@ class ActivityInfoViewModel : ViewModel() { } -/** - * 图片 - * @property name 文件名 - * @property size 文件大小 - * @property url 文件路径 - * @property md5 文件hash - * @property createTime 文件创建时间 - * @property studentId 文件上传人 - */ -data class ActivityPhotoVo( - val name: String, - val size: Long, - val url: String, - val md5: String, - val createTime: Date, - val studentId: String -) /** * 活动相册数据状态管理 @@ -179,12 +143,6 @@ class ActivityPhotoViewModel(application: Application) : } } -data class ActivityMemberVo(val studentId: String, val name: String) - -data class ActivityMembersVo( - val organizer: ActivityMemberVo, - val participant: MutableList? -) class ActivityMemberViewModel(application: Application) : ScrollViewModel(application) { @@ -245,11 +203,6 @@ class ActivityMemberViewModel(application: Application) : } } -data class BBSVo(val studentId: String, val name: String, val createTime: Date, val content: String) - -class T - - class BBSCommentModel : AbstractComment() { override val newContent = ValidStringForm(formDesc = "评论内容", textLength = 80) diff --git a/foreground/src/main/java/com/gyf/csams/activity/ui/ActivityDetailActivity.kt b/foreground/src/main/java/com/gyf/csams/activity/ui/ActivityDetailActivity.kt index 081e727..ded884c 100644 --- a/foreground/src/main/java/com/gyf/csams/activity/ui/ActivityDetailActivity.kt +++ b/foreground/src/main/java/com/gyf/csams/activity/ui/ActivityDetailActivity.kt @@ -24,9 +24,12 @@ import com.gyf.csams.R import com.gyf.csams.activity.model.* import com.gyf.csams.uikit.* import com.gyf.lib.uikit.MainColumnFrame +import com.gyf.lib.uikit.NavBody import com.gyf.lib.uikit.ScaffoldModel import com.gyf.lib.uikit.ShowSnackbar -import com.gyf.lib.uikit.TestBody +import com.gyf.lib.util.ActivityMemberVo +import com.gyf.lib.util.ActivityPhotoVo +import com.gyf.lib.util.BBSVo import com.gyf.lib.util.format /** @@ -41,7 +44,7 @@ class ActivityDetailActivity : ComponentActivity() { setContent { - TestBody { nav, scaffoldState -> + NavBody { nav, scaffoldState -> val model: ActivityDetailViewModel = viewModel() val currentMenuName by model.currentMenu.observeAsState(ActivityDetailMenu.startMenu) Column { diff --git a/foreground/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt b/foreground/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt index 68c66b1..58cbad0 100644 --- a/foreground/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt +++ b/foreground/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt @@ -9,7 +9,10 @@ import com.gyf.csams.uikit.AssociationMenu import com.gyf.csams.uikit.TopMenuInterface import com.gyf.lib.model.ScrollViewModel import com.gyf.lib.uikit.StringForm +import com.gyf.lib.util.HistoryActVo +import com.gyf.lib.util.MemberVo import com.gyf.lib.util.NOT_IMPL_TIP +import com.gyf.lib.util.OngoingActVo import com.orhanobut.logger.Logger import kotlinx.coroutines.launch @@ -42,8 +45,6 @@ class AssociationViewModel : ViewModel(), TopMenuInterface { } -data class MemberVo(val name: String) - /** * 社团会员 * @@ -111,16 +112,11 @@ class MemberViewModel(application: Application) : ScrollViewModel(appl } } - -data class OngoingActVo(val name: String) - class OngoingActViewModel : ViewModel() { private val _act = MutableLiveData() val act: LiveData = _act } -data class HistoryActVo(val name: String) - /** * 历史活动 diff --git a/foreground/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt b/foreground/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt index d2d88be..1afaea2 100644 --- a/foreground/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt +++ b/foreground/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt @@ -6,7 +6,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.gyf.lib.model.ScrollViewModel import com.gyf.lib.uikit.StringForm -import com.gyf.lib.util.NOT_IMPL_TIP +import com.gyf.lib.util.* import kotlinx.coroutines.launch import kotlin.random.Random @@ -22,49 +22,6 @@ enum class ExamActivityType(val menuName: String) { JOIN_Association("入团申请表") } -/** - * 题型 - * - */ -enum class ExamType(val type: String) { - //选择题 - CQ("选择题"), - - //开放题 - OQ("开放题") -} - -sealed class Exam { - abstract val examType: ExamType - abstract val question: StringForm -} - - -/** - * 开放题 - * - * @property examType 题型描述 - * @property question 问题 - */ -data class OpenQuestionsVo( - override val examType: ExamType = ExamType.OQ, override val question: StringForm - -) : Exam() - -/** - * 选择题 - * - * @property examType 题型描述 - * @property answers 答案 - * @property rightAnswer 正确答案 - * @property question 问题 - */ -data class ChoiceQuestionVo( - override val examType: ExamType = ExamType.CQ, - val answers: List, - val rightAnswer: Int, - override val question: StringForm -) : Exam() /** diff --git a/foreground/src/main/java/com/gyf/csams/association/model/RegAssociationViewModel.kt b/foreground/src/main/java/com/gyf/csams/association/model/RegAssociationViewModel.kt index 63c8ed7..5bae642 100644 --- a/foreground/src/main/java/com/gyf/csams/association/model/RegAssociationViewModel.kt +++ b/foreground/src/main/java/com/gyf/csams/association/model/RegAssociationViewModel.kt @@ -1,31 +1,40 @@ package com.gyf.csams.association.model import android.app.Application +import android.graphics.Bitmap import android.net.Uri +import androidx.core.graphics.drawable.toBitmap import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope +import coil.imageLoader +import coil.request.ImageRequest import com.google.gson.reflect.TypeToken import com.gyf.csams.MainApplication -import com.gyf.csams.util.SimpleCallback +import com.gyf.lib.BuildConfig import com.gyf.lib.uikit.FormStatus import com.gyf.lib.uikit.ValidStringForm import com.gyf.lib.util.* import com.orhanobut.logger.Logger import kotlinx.coroutines.launch import java.io.File +import java.io.FileOutputStream import java.io.InputStream -data class RegAssociationVo(val name: String, val desc: String, val fileId: Int, val token: Token) +class TestStringForm(formDesc: String, textLength: Int) : ValidStringForm(formDesc, textLength) { + + fun setValue(value: String) { + _formValue.postValue(value) + } +} class RegAssociationViewModel(application: Application) : AndroidViewModel(application) { val frameDesc = "社团注册资料" - val name = ValidStringForm(formDesc = "社团名称", textLength = 5) - val desc = ValidStringForm(formDesc = "社团简介", textLength = 30) - + val name = TestStringForm(formDesc = "社团名称", textLength = 5) + val desc = TestStringForm(formDesc = "社团简介", textLength = 30) private val _picture = MutableLiveData() val picture: LiveData = _picture @@ -33,10 +42,17 @@ class RegAssociationViewModel(application: Application) : AndroidViewModel(appli private val _fileId = MutableLiveData() val fileId: LiveData = _fileId + private val _checkInfo = MutableLiveData() + val checkInfo: LiveData = _checkInfo + val picturePlaceHolder = "请上传图片" val errorPicture = "图片加载失败,请联系管理员" + init { + read() + } + fun setPicture(uri: Uri) { _picture.value = uri } @@ -49,40 +65,84 @@ class RegAssociationViewModel(application: Application) : AndroidViewModel(appli throw IllegalArgumentException(UNKNOW_ERROR) } + /** + * 加载历史提交的注册资料,可能为空 + * + */ + private fun read() { + viewModelScope.launch { + HttpClient.post( + Api.buildUrl(AssociationApi.Read), + HttpCallback(action = "加载历史注册资料", onSuccess = { it -> + it.body?.let { it -> + name.setValue(it.name) + desc.setValue(it.desc) + _checkInfo.postValue(it) + val context = getApplication() + val request = ImageRequest.Builder(context) + .data("${BuildConfig.SERVER_ADDRESS}/${it.logo}") + .target( + onSuccess = { result -> + + it.logo.split("/").apply { + File.createTempFile(last(), null, context.cacheDir).apply { + Logger.d("文件路径:${absolutePath}") + FileOutputStream(this).use { + result.toBitmap().compress( + Bitmap.CompressFormat.JPEG, + 100, + it + ) + } + } + .apply { + Logger.i("读取缓存图片") + setPicture(Uri.fromFile(this)) + _fileId.postValue(it.fileId) + } + + } + } + ) + .build() + context.imageLoader.enqueue(request) + } + }, + typeToken = object : TypeToken>() {}.type + ), + jsonParam = OnlyToken(clientType = ClientType.Foreground) + ) + } + } + fun uploadPhoto(callback: (value: String) -> Unit) { getInputSteam()?.readBytes()?.apply { - val token = TokenManager.token - if (token != null) { - - viewModelScope.launch { - val context = getApplication() - - runCatching { - val cacheFile = File(context.cacheDir, "${System.currentTimeMillis()}") - cacheFile.writeBytes(this@apply) - - HttpClient.uploadFile( - Api.buildUrl(AssociationApi.Logo), - SimpleCallback>("上传图片", onSuccess = { - Logger.i(it.message) - callback(it.message) - it.body?.let { - _fileId.postValue(it.first()) - } - - }, onFail = { - Logger.e(it) - callback("图片上传失败") - }, type = object : TypeToken>>() {}.type), - token = token, - fileList = arrayOf(cacheFile) - ) - } + viewModelScope.launch { + val context = getApplication() + + runCatching { + val cacheFile = File(context.cacheDir, "${System.currentTimeMillis()}") + cacheFile.writeBytes(this@apply) + + HttpClient.uploadFile( + Api.buildUrl(AssociationApi.Logo), + HttpCallback>("上传图片", onSuccess = { + Logger.i(it.message) + callback(it.message) + it.body?.let { + _fileId.postValue(it.first()) + } + + }, onFail = { + Logger.e(it) + callback("图片上传失败") + }, typeToken = object : TypeToken>>() {}.type), + fileList = arrayOf(cacheFile) + ) } - } else { - callback(UNKNOW_ERROR) } + } } @@ -94,15 +154,14 @@ class RegAssociationViewModel(application: Application) : AndroidViewModel(appli fun register(callback: (value: String) -> Unit) { val nameValue = name.formValue.value val descValue = desc.formValue.value - val token = TokenManager.token val fileId = _fileId.value - if (token != null && nameValue != null && descValue != null && fileId != null && + if (nameValue != null && descValue != null && fileId != null && name.statusForm.value == FormStatus.Valid && desc.statusForm.value == FormStatus.Valid ) { viewModelScope.launch { HttpClient.post( Api.buildUrl(AssociationApi.Register), - SimpleCallback("注册社团", onSuccess = { + HttpCallback("注册社团", onSuccess = { Logger.i(it.message) callback(it.message) name.clean() @@ -110,13 +169,13 @@ class RegAssociationViewModel(application: Application) : AndroidViewModel(appli _picture.postValue(null) }, onFail = { Logger.e(it) - }, object : TypeToken>() {}.type), + }, typeToken = object : TypeToken>() {}.type), jsonParam = - RegAssociationVo( + AssociationRegVo( name = nameValue, desc = descValue, - token = token, - fileId = fileId + fileId = fileId, + id = checkInfo.value?.id ) ) } diff --git a/foreground/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt b/foreground/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt index 2309d6d..429f03b 100644 --- a/foreground/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt +++ b/foreground/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt @@ -31,6 +31,8 @@ import com.gyf.csams.activity.ui.ApplyActActivity import com.gyf.csams.association.model.* import com.gyf.csams.uikit.* import com.gyf.lib.uikit.* +import com.gyf.lib.util.HistoryActVo +import com.gyf.lib.util.MemberVo import com.gyf.lib.util.randomChinese import com.orhanobut.logger.Logger @@ -44,7 +46,7 @@ class AssociationActivity : ComponentActivity() { super.onCreate(savedInstanceState) setContent { - TestBody { nav, scaffoldState -> + NavBody { nav, scaffoldState -> val context = LocalContext.current as AssociationActivity val model: AssociationViewModel = viewModel() val currentMenuName: AssociationMenu by model.currentMenu.observeAsState( diff --git a/foreground/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt b/foreground/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt index 03bec82..e384a64 100644 --- a/foreground/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt +++ b/foreground/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt @@ -19,7 +19,9 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.gyf.csams.R -import com.gyf.csams.association.model.* +import com.gyf.csams.association.model.ANSWER_SIZE +import com.gyf.csams.association.model.ExamActivityType +import com.gyf.csams.association.model.ExamViewModel import com.gyf.csams.uikit.Background import com.gyf.csams.uikit.BackgroundImage import com.gyf.lib.uikit.BaseTextField @@ -27,6 +29,9 @@ import com.gyf.lib.uikit.Body import com.gyf.lib.uikit.MainColumnFrame import com.gyf.lib.uikit.ScaffoldModel import com.gyf.lib.util.BottomButton +import com.gyf.lib.util.ChoiceQuestionVo +import com.gyf.lib.util.Exam +import com.gyf.lib.util.OpenQuestionsVo /** diff --git a/foreground/src/main/java/com/gyf/csams/association/ui/RegAssociationActivity.kt b/foreground/src/main/java/com/gyf/csams/association/ui/RegAssociationActivity.kt index 82cc1bd..d2f1529 100644 --- a/foreground/src/main/java/com/gyf/csams/association/ui/RegAssociationActivity.kt +++ b/foreground/src/main/java/com/gyf/csams/association/ui/RegAssociationActivity.kt @@ -24,6 +24,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat import androidx.lifecycle.viewmodel.compose.viewModel @@ -33,8 +36,11 @@ import com.gyf.csams.uikit.Background import com.gyf.csams.uikit.BackgroundImage import com.gyf.lib.uikit.* import com.gyf.lib.util.BottomButton +import com.gyf.lib.util.CheckStatus import com.gyf.lib.util.ImageUtil +import com.gyf.lib.util.format import com.orhanobut.logger.Logger +import java.util.* /** @@ -57,6 +63,7 @@ class RegAssociationActivity : ComponentActivity() { .weight(0.1F) ) Title() + Tip() Name() Desc( modifier = Modifier @@ -76,11 +83,13 @@ class RegAssociationActivity : ComponentActivity() { val name by model.name.statusForm.observeAsState() val desc by model.name.statusForm.observeAsState() val fileId by model.fileId.observeAsState() + val checkInfo by model.checkInfo.observeAsState() BottomButton( modifier = Modifier.fillMaxWidth(), enabled = name == FormStatus.Valid && desc == FormStatus.Valid && fileId != null, - confirmDesc = R.string.reg_btn - ) { + confirmDesc = if (checkInfo != null) R.string.reg_again_btn else R.string.reg_btn, + + ) { model.register { scaffoldModel.update(message = it, actionLabel = "返回") { finish() @@ -88,10 +97,50 @@ class RegAssociationActivity : ComponentActivity() { } } Spacer(modifier = Modifier.weight(0.05F)) + } + } + + } + } + + @Composable + private fun Tip(model: RegAssociationViewModel = viewModel()) { + val checkInfo by model.checkInfo.observeAsState() + checkInfo?.let { + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { + when (val status = it.checkStatus) { + CheckStatus.Finish -> Text(buildAnnotatedString { + withStyle(style = MaterialTheme.typography.h5.toParagraphStyle()) { + append("您于${Date(it.applyTime).format()}提交的${model.frameDesc}审核不通过原因如下:\n") + } + withStyle( + style = MaterialTheme.typography.h6.copy(color = MaterialTheme.colors.error) + .toParagraphStyle() + ) { + append("初审意见:${it.firstCause}\n") + it.lastCause?.let { + append("复审意见:${it}") + } + } + }) + else -> { + Text( + text = status.desc, style = + MaterialTheme.typography.h5.copy(color = MaterialTheme.colors.primary) + ) } } + } + } + + } + + @Preview + @Composable + private fun TestPreview9() { + Text(text = "123", color = MaterialTheme.colors.error) } @@ -187,30 +236,36 @@ class RegAssociationActivity : ComponentActivity() { bitmap = it, contentDescription = null ) } - Column( - modifier = Modifier.fillMaxHeight(), - verticalArrangement = Arrangement.SpaceEvenly - ) { - IconButton(onClick = { - loadPicture() - }) { - Image( - painter = painterResource(id = R.drawable.ic_exchange_rate), - contentDescription = null - ) - } - IconButton(onClick = { - scaffoldModel.update("确认上传此图片?", actionLabel = "确定") { - Logger.i("开始上传") - model.uploadPhoto { - scaffoldModel.update(message = it) + val checkInfo by model.checkInfo.observeAsState() + if (checkInfo == null || checkInfo?.checkStatus == CheckStatus.Finish) { + Column( + modifier = Modifier.fillMaxHeight(), + verticalArrangement = Arrangement.SpaceEvenly + ) { + IconButton(onClick = { + loadPicture() + }) { + Image( + painter = painterResource(id = R.drawable.ic_exchange_rate), + contentDescription = null + ) + } + IconButton(onClick = { + scaffoldModel.update("确认上传此图片?", actionLabel = "确定") { + Logger.i("开始上传") + model.uploadPhoto { + scaffoldModel.update( + message = it, + actionLabel = "关闭提示" + ) + } } + }) { + Image( + painter = painterResource(id = R.drawable.ic_upload), + contentDescription = null + ) } - }) { - Image( - painter = painterResource(id = R.drawable.ic_upload), - contentDescription = null - ) } } } @@ -245,7 +300,11 @@ class RegAssociationActivity : ComponentActivity() { */ @Composable private fun Name(model: RegAssociationViewModel = viewModel()) { - BaseTextField(form = model.name, singeLine = true, modifier = Modifier.fillMaxWidth()) + val checkInfo by model.checkInfo.observeAsState() + BaseTextField( + form = model.name, singeLine = true, modifier = Modifier.fillMaxWidth(), + readOnly = checkInfo?.checkStatus != CheckStatus.Finish + ) } /** @@ -254,7 +313,11 @@ class RegAssociationActivity : ComponentActivity() { */ @Composable private fun Desc(model: RegAssociationViewModel = viewModel(), modifier: Modifier) { - BaseTextField(form = model.desc, modifier = modifier) + val checkInfo by model.checkInfo.observeAsState() + BaseTextField( + form = model.desc, modifier = modifier, + readOnly = checkInfo?.checkStatus != CheckStatus.Finish + ) } } diff --git a/foreground/src/main/java/com/gyf/csams/main/model/MainViewModel.kt b/foreground/src/main/java/com/gyf/csams/main/model/MainViewModel.kt index ce19116..d3b25d9 100644 --- a/foreground/src/main/java/com/gyf/csams/main/model/MainViewModel.kt +++ b/foreground/src/main/java/com/gyf/csams/main/model/MainViewModel.kt @@ -3,12 +3,9 @@ package com.gyf.csams.main.model import android.app.Application import androidx.lifecycle.* import com.google.gson.reflect.TypeToken -import com.gyf.csams.account.model.UserVo import com.gyf.csams.uikit.AbstractComment -import com.gyf.csams.util.SimpleCallback import com.gyf.lib.model.ScrollViewModel import com.gyf.lib.uikit.FormStatus -import com.gyf.lib.uikit.PersonInfoVo import com.gyf.lib.uikit.StringForm import com.gyf.lib.uikit.ValidStringForm import com.gyf.lib.util.* @@ -17,9 +14,6 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch -data class LeaveMessageFormatVo(val message: String, val user: UserVo) - - class NotificationViewModel(application: Application) : AndroidViewModel(application) { private val _count = MutableLiveData() @@ -35,24 +29,21 @@ class NotificationViewModel(application: Application) : AndroidViewModel(applica */ private fun count() { viewModelScope.launch { - TokenManager.token?.let { - HttpClient.post( - url = Api.buildUrl(NotificationApi.Count), - SimpleCallback(action = "未读通知计数", onSuccess = { - it.body?.let { - _count.postValue(it) - } - Logger.i(it.message) - }, onFail = { - Logger.e(it) - }, type = object : TypeToken>() {}.type), - jsonParam = NotificationDto( - receiverId = it.id, - receiverClient = ClientType.Foreground, - token = it - ) + HttpClient.post( + url = Api.buildUrl(NotificationApi.Count), + HttpCallback(action = "未读通知计数", onSuccess = { + it.body?.let { + _count.postValue(it) + } + Logger.i(it.message) + }, onFail = { + Logger.e(it) + }, typeToken = object : TypeToken>() {}.type), + jsonParam = NotificationDto( + receiverId = TokenManager.getToken().id, + receiverClient = ClientType.Foreground, ) - } + ) } } } @@ -87,32 +78,25 @@ class MarqueeViewModel : AbstractComment() { * @param callback */ override fun send(callback: (message: String) -> Unit) { - TokenManager.token.let { - if (it != null) { - viewModelScope.launch { - HttpClient.post(url = Api.buildUrl(MainApi.LeaveMessage), - SimpleCallback( - action = "发送留言", onSuccess = { - if (it.body == true) { - callback("留言发送成功") - newContent.clean() - loadMessage(callback) - } else { - callback("留言发送失败") - } - }, onFail = { - callback("留言发送失败") - }, type = object : TypeToken>() {}.type - ), - jsonParam = LeaveMessageVo( - message = newContent.formValue.value ?: "", - token = it - ) - ) - } - } else { - callback(UNKNOW_ERROR) - } + viewModelScope.launch { + HttpClient.post(url = Api.buildUrl(MainApi.LeaveMessage), + HttpCallback( + action = "发送留言", onSuccess = { + if (it.body == true) { + callback("留言发送成功") + newContent.clean() + loadMessage(callback) + } else { + callback("留言发送失败") + } + }, onFail = { + callback("留言发送失败") + }, typeToken = object : TypeToken>() {}.type + ), + jsonParam = LeaveMessageVo( + message = newContent.formValue.value ?: "" + ) + ) } } @@ -121,16 +105,22 @@ class MarqueeViewModel : AbstractComment() { viewModelScope.launch { HttpClient.post( Api.buildUrl(MainApi.GetMessage), - SimpleCallback>(action = "获取留言", onSuccess = { + HttpCallback>( + action = "获取留言", + onSuccess = { // callback(it.message) - Logger.i(it.message) - it.body?.let { - _marqueeTexts.postValue(it) - } - }, onFail = { - Logger.e(it) - callback("留言获取失败") - }, type = object : TypeToken>>() {}.type), + Logger.i(it.message) + it.body?.let { + _marqueeTexts.postValue(it) + } + }, + onFail = { + Logger.e(it) + callback("留言获取失败") + }, + typeToken = object : + TypeToken>>() {}.type + ), jsonParam = OnlyToken(clientType = ClientType.Foreground) ) } @@ -153,67 +143,47 @@ class MarqueeViewModel : AbstractComment() { } - -/** - * 社团 - * - * @property name 社团名称 - */ -data class AssociationListVo(val name: String) - -data class LeaveMessageVo(val message: String, val token: Token) - /** * 社团列表 * */ -class ListViewModel(application: Application) : ScrollViewModel(application) { +class ListViewModel(application: Application) : ScrollViewModel(application) { val name = StringForm(formDesc = "社团名称", textLength = 5) val desc = StringForm(formDesc = "社团简介", textLength = 10) - //社团列表加载数量 - val associationListSize = 10 - - //社团列表 - private val _associationList = MutableLiveData>(mutableListOf()) - val associationListVo: LiveData> = _associationList - val searchDesc = "搜索" - - /** - * TODO 社团检索 - * - * @param callback - */ - fun search(callback: (value: String) -> Unit) { - Logger.i("搜索条件[社团名称:${name.formValue.value},社团简介:${desc.formValue.value}]") - callback(NOT_IMPL_TIP) - } - override val initSize: Int = 10 init { - load() - + load {} } /** * 加载社团列表 * */ - override fun load() { + override fun load(callback: (message: String) -> Unit) { viewModelScope.launch { - _associationList.value?.apply { - repeat( - 10 - ) { - add(AssociationListVo(name = "社团${_associationList.value?.size}")) - } - - } - Logger.i("初始化社团列表size=${_associationList.value?.size}") + HttpClient.post( + Api.buildUrl(AssociationApi.List), + HttpCallback>( + action = "加载社团列表", + onSuccess = { + it.body?.let { + _data.postValue(it) + } + callback(it.message) + }, + typeToken = object : + TypeToken>>() {}.type + ), + jsonParam = SearchAssociationVo( + name = name.formValue.value ?: "", + desc = desc.formValue.value ?: "" + ) + ) } } @@ -222,41 +192,10 @@ class ListViewModel(application: Application) : ScrollViewModel Unit) { - viewModelScope.launch { - _associationList.value?.apply { - val list = mutableListOf() - list.addAll(this) - list.apply { - repeat(10) { - add(AssociationListVo(name = "社团${size}")) - } - } - Logger.i("t.size=${size}") - _associationList.postValue(list) - Logger.i("加载更多社团size=${_associationList.value?.size}") - callback("成功加载更多社团") - } - } + TODO(NOT_IMPL_TIP) } } -/** - * 我的信息 - * - * @property studentId 学号 - * @property name 姓名 - * @property duty 职务 - * @property headImg 头像 - * @property desc 个人简介 - */ -data class InfoVo( - val studentId: String, - override val name: String, - override val duty: String, - override val headImg: String, - override val desc: String -) : PersonInfoVo() - /** * 个人中心 @@ -268,8 +207,6 @@ class CenterViewModel : ViewModel() { val myLikeActivity = "我点赞的社团活动" val myCollectActivity = "我收藏的社团活动" - private val _info = MutableLiveData() - val info: LiveData = _info init { load() @@ -277,13 +214,7 @@ class CenterViewModel : ViewModel() { private fun load() { viewModelScope.launch { - _info.value = InfoVo( - studentId = randomNum(), - name = randomChinese(3), - duty = randomChinese(3), - headImg = "", - desc = randomChinese(10) - ) + TODO() } } diff --git a/foreground/src/main/java/com/gyf/csams/main/ui/MainActivity.kt b/foreground/src/main/java/com/gyf/csams/main/ui/MainActivity.kt index 7f67775..7df1617 100644 --- a/foreground/src/main/java/com/gyf/csams/main/ui/MainActivity.kt +++ b/foreground/src/main/java/com/gyf/csams/main/ui/MainActivity.kt @@ -33,8 +33,7 @@ import com.gyf.csams.message.ui.MessageActivity import com.gyf.csams.uikit.* import com.gyf.lib.service.BaseActivity import com.gyf.lib.uikit.* -import com.gyf.lib.util.ClientType -import com.gyf.lib.util.randomChinese +import com.gyf.lib.util.* /** @@ -51,7 +50,7 @@ class MainActivity : BaseActivity() { setContent { val imageViewModel: ImageViewModel = viewModel() - TestBody { nav, scaffoldState -> + NavBody { nav, scaffoldState -> NavHost(navController = nav, startDestination = MainMenu.Main.name) { composable(MainMenu.Main.name) { Main(navController = nav) @@ -94,16 +93,11 @@ class MainActivity : BaseActivity() { mainMenu = MainMenu.Center, nav = navController ) { - val info by model.info.observeAsState() - - info?.let { - Profile( - modifier = Modifier - .weight(0.3F) - .padding(10.dp), - personInfoVo = it - ) - } + Profile( + modifier = Modifier + .weight(0.3F) + .padding(10.dp) + ) Column( @@ -193,7 +187,11 @@ class MainActivity : BaseActivity() { mainMenu = MainMenu.List, nav = navController ) { - RegisterAssociation() + val memberVo: AssociationMemberVo? = + (TokenManager.getOwnInfo() as? UserVo)?.associationMemberVo + if (memberVo == null) { + RegisterAssociation() + } AssociationSearch() AssociationListBody() } @@ -233,7 +231,7 @@ class MainActivity : BaseActivity() { model: ListViewModel = viewModel(), scaffoldModel: ScaffoldModel = viewModel() ) { - val associationListList: MutableList? by model.associationListVo.observeAsState() + val associationListList: MutableList? by model.data.observeAsState() val listState = rememberLazyListState() LazyColumn(state = listState) { @@ -267,13 +265,13 @@ class MainActivity : BaseActivity() { } } - if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.associationListSize / 2 - 1) { + if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) { model.loadMore { scaffoldModel.update(message = it) } } } @Composable - private fun Association(associationListVo: AssociationListVo) { + private fun Association(associationListVo: AssociationVo) { val context = LocalContext.current Card(modifier = Modifier.clickable(onClick = { context.startActivity( @@ -307,7 +305,6 @@ class MainActivity : BaseActivity() { model: ListViewModel = viewModel(), scaffoldModel: ScaffoldModel = viewModel() ) { - Card(modifier = Modifier.padding(horizontal = 50.dp, vertical = 10.dp)) { Column { @@ -329,7 +326,11 @@ class MainActivity : BaseActivity() { modifier = Modifier.fillMaxWidth() ) { OutlinedButton( - onClick = { model.search { scaffoldModel.update(message = it) } }, + onClick = { + model.load { + scaffoldModel.update(message = it) + } + }, modifier = Modifier.width(100.dp) ) { Text(text = model.searchDesc) diff --git a/foreground/src/main/java/com/gyf/csams/message/model/ForegroundViewModel.kt b/foreground/src/main/java/com/gyf/csams/message/model/ForegroundViewModel.kt new file mode 100644 index 0000000..213ce69 --- /dev/null +++ b/foreground/src/main/java/com/gyf/csams/message/model/ForegroundViewModel.kt @@ -0,0 +1,11 @@ +package com.gyf.csams.message.model + +import android.app.Application +import com.gyf.lib.model.SysMessageViewModel +import com.gyf.lib.util.ClientType + +class ForegroundViewModel(application: Application) : SysMessageViewModel(application) { + override fun clientType(): ClientType { + return ClientType.Foreground + } +} \ No newline at end of file diff --git a/foreground/src/main/java/com/gyf/csams/message/ui/SysMessageActivity.kt b/foreground/src/main/java/com/gyf/csams/message/ui/SysMessageActivity.kt index bad91f8..3b7316f 100644 --- a/foreground/src/main/java/com/gyf/csams/message/ui/SysMessageActivity.kt +++ b/foreground/src/main/java/com/gyf/csams/message/ui/SysMessageActivity.kt @@ -18,12 +18,17 @@ import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel -import com.gyf.csams.message.model.* +import com.gyf.csams.message.model.ForegroundViewModel +import com.gyf.csams.message.model.MessageType import com.gyf.csams.uikit.Background import com.gyf.csams.uikit.BackgroundImage import com.gyf.csams.uikit.TextTopAppBar +import com.gyf.lib.model.ActCheckContent +import com.gyf.lib.model.JoinContent +import com.gyf.lib.model.RenameContent import com.gyf.lib.uikit.Body import com.gyf.lib.uikit.MainColumnFrame +import com.gyf.lib.util.NotificationVo import com.gyf.lib.util.format import java.util.* @@ -54,7 +59,7 @@ class SysMessageActivity : ComponentActivity() { @Composable private fun MessageList( modifier: Modifier = Modifier, - model: SysMessageViewModel = viewModel() + model: ForegroundViewModel = viewModel() ) { val listState = rememberLazyListState() val list by model.data.observeAsState() diff --git a/foreground/src/main/java/com/gyf/csams/uikit/BaseView.kt b/foreground/src/main/java/com/gyf/csams/uikit/BaseView.kt index 51c3582..4b22214 100644 --- a/foreground/src/main/java/com/gyf/csams/uikit/BaseView.kt +++ b/foreground/src/main/java/com/gyf/csams/uikit/BaseView.kt @@ -23,7 +23,6 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -591,7 +590,6 @@ fun MainContent() { .padding(32.dp), verticalArrangement = Arrangement.spacedBy(24.dp) ) { - var textState by remember { mutableStateOf(TextFieldValue()) } val localFocusManager = LocalFocusManager.current val focusRequester = FocusRequester() diff --git a/foreground/src/main/java/com/gyf/csams/uikit/ViewModel.kt b/foreground/src/main/java/com/gyf/csams/uikit/ViewModel.kt index 23b5e63..f3014f4 100644 --- a/foreground/src/main/java/com/gyf/csams/uikit/ViewModel.kt +++ b/foreground/src/main/java/com/gyf/csams/uikit/ViewModel.kt @@ -8,11 +8,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.google.gson.reflect.TypeToken import com.gyf.csams.R -import com.gyf.csams.util.SimpleCallback -import com.gyf.lib.util.Api -import com.gyf.lib.util.HttpClient -import com.gyf.lib.util.ImageUtil -import com.gyf.lib.util.MainApi +import com.gyf.lib.util.* import com.orhanobut.logger.Logger import kotlinx.coroutines.Job import kotlinx.coroutines.delay @@ -57,7 +53,7 @@ class ImageViewModel(application: Application) : AndroidViewModel(application) { HttpClient.get( url = urlPath, - SimpleCallback>("获取轮播图", onSuccess = { + HttpCallback>("获取轮播图", onSuccess = { _imageUrls.postValue(it.body) var index = 0 _imageUrls.value?.apply { @@ -81,7 +77,7 @@ class ImageViewModel(application: Application) : AndroidViewModel(application) { Logger.e("无法从接口地址:${urlPath}获取图片url列表") _error.postValue(it) defaultLoad() - }, type = object : TypeToken>() {}.type) + }, typeToken = object : TypeToken>>() {}.type) ) }.apply { start() diff --git a/foreground/src/main/java/com/gyf/csams/util/GsonUtil.kt b/foreground/src/main/java/com/gyf/csams/util/GsonUtil.kt index bb35c32..47c6e63 100644 --- a/foreground/src/main/java/com/gyf/csams/util/GsonUtil.kt +++ b/foreground/src/main/java/com/gyf/csams/util/GsonUtil.kt @@ -2,8 +2,14 @@ package com.gyf.csams.util import com.google.gson.* import com.google.gson.reflect.TypeToken -import com.gyf.csams.association.model.* +import com.gyf.csams.association.model.ANSWER_SIZE +import com.gyf.csams.association.model.ANSWER_TEXT_LENGTH +import com.gyf.csams.association.model.QUESTION_TEXT_LENGTH import com.gyf.lib.uikit.StringForm +import com.gyf.lib.util.ChoiceQuestionVo +import com.gyf.lib.util.Exam +import com.gyf.lib.util.ExamType +import com.gyf.lib.util.OpenQuestionsVo import java.lang.reflect.Type class OpenQuestionsVoSerializer : JsonSerializer { diff --git a/foreground/src/main/java/com/gyf/csams/util/HttpCallback.kt b/foreground/src/main/java/com/gyf/csams/util/HttpCallback.kt index 6cf0235..49122ba 100644 --- a/foreground/src/main/java/com/gyf/csams/util/HttpCallback.kt +++ b/foreground/src/main/java/com/gyf/csams/util/HttpCallback.kt @@ -2,8 +2,8 @@ package com.gyf.csams.util import com.google.gson.Gson import com.google.gson.GsonBuilder -import com.gyf.csams.association.model.Exam import com.gyf.lib.util.ApiResponse +import com.gyf.lib.util.Exam import com.gyf.lib.util.HttpCallback import java.lang.reflect.Type @@ -14,9 +14,9 @@ import java.lang.reflect.Type * @property action * @property onSuccess * @property onFail - * @property type + */ -class SimpleCallback( +class ExamCallback( private val action: String, private val onSuccess: (res: ApiResponse) -> Unit, private val onFail: (error: String) -> Unit, diff --git a/foreground/src/main/res/values-en/strings.xml b/foreground/src/main/res/values-en/strings.xml index f9f4b66..3583d49 100644 --- a/foreground/src/main/res/values-en/strings.xml +++ b/foreground/src/main/res/values-en/strings.xml @@ -15,4 +15,5 @@ 入学年份(四位)+班级代码(两位)+学生代码(两位) 同学您好\n 欢迎使用 + 再次申请 \ No newline at end of file diff --git a/foreground/src/main/res/values-zh/strings.xml b/foreground/src/main/res/values-zh/strings.xml index f9f4b66..3583d49 100644 --- a/foreground/src/main/res/values-zh/strings.xml +++ b/foreground/src/main/res/values-zh/strings.xml @@ -15,4 +15,5 @@ 入学年份(四位)+班级代码(两位)+学生代码(两位) 同学您好\n 欢迎使用 + 再次申请 \ No newline at end of file diff --git a/foreground/src/main/res/values/strings.xml b/foreground/src/main/res/values/strings.xml index 3730508..36dbfa6 100644 --- a/foreground/src/main/res/values/strings.xml +++ b/foreground/src/main/res/values/strings.xml @@ -15,4 +15,5 @@ 入学年份(四位)+班级代码(两位)+学生代码(两位) 同学您好\n 欢迎使用 + 再次申请 \ No newline at end of file diff --git a/foreground/src/test/java/com/gyf/csams/ExampleUnitTest.kt b/foreground/src/test/java/com/gyf/csams/ExampleUnitTest.kt index 87a7a5c..1d75841 100644 --- a/foreground/src/test/java/com/gyf/csams/ExampleUnitTest.kt +++ b/foreground/src/test/java/com/gyf/csams/ExampleUnitTest.kt @@ -2,6 +2,7 @@ package com.gyf.csams import com.google.gson.Gson import com.google.gson.reflect.TypeToken +import com.gyf.lib.uikit.StringForm import com.gyf.lib.util.ApiResponse import com.gyf.lib.util.randomChinese import org.junit.Assert.assertEquals @@ -39,9 +40,12 @@ class ExampleUnitTest { repeat(100) { println(randomChinese()) } + } -// println(java.time.format.DateTimeFormatter.ISO_INSTANT -// .format(java.time.Instant.ofEpochMilli(1532358895000))) + @Test + fun testFind() { + val s = StringForm(formDesc = "", textLength = 3) + println("${s.formValue.value}") } @Test diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 3da2b89..05334b4 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -54,12 +54,13 @@ dependencies { //生命周期组件版本 val lifecycle_version = "2.3.1" //https://developer.android.com/topic/libraries/architecture/workmanager/basics?hl=zh-cn - val work_version = "2.5.0" val room_version = "2.3.0" - // Kotlin + coroutines - api("androidx.work:work-runtime-ktx:$work_version") - + val accompanist_version = "0.10.0" + //https://github.com/google/accompanist + api("com.google.accompanist:accompanist-insets:$accompanist_version") + api("com.google.accompanist:accompanist-systemuicontroller:$accompanist_version") + api("com.google.accompanist:accompanist-coil:$accompanist_version") /** * 针对最新的平台功能和 API 调整应用,同时还支持旧设备。 * https://developer.android.com/jetpack/androidx/releases/core diff --git a/lib/src/main/java/com/gyf/lib/model/AbstractLoginViewModel.kt b/lib/src/main/java/com/gyf/lib/model/AbstractLoginViewModel.kt index 14211d6..8891b86 100644 --- a/lib/src/main/java/com/gyf/lib/model/AbstractLoginViewModel.kt +++ b/lib/src/main/java/com/gyf/lib/model/AbstractLoginViewModel.kt @@ -30,7 +30,7 @@ abstract class AbstractLoginViewModel(application: Application) : AndroidViewMod /** * 完成登录状态 */ - private val _finishLogin = MutableLiveData() + protected val _finishLogin = MutableLiveData() val finishLogin: LiveData = _finishLogin abstract fun checkForm(): Boolean @@ -55,9 +55,9 @@ abstract class AbstractLoginViewModel(application: Application) : AndroidViewMod val id = "${id.formValue.value}" val password = "${password.formValue.value}" Logger.i("使用账号:$id,密码:$password 进行登录") - HttpClient.post( - url, - HttpCallback( + + val call = when (clientType) { + ClientType.Background -> HttpCallback( action = loginDesc, onSuccess = { Logger.i(it.message) @@ -66,16 +66,40 @@ abstract class AbstractLoginViewModel(application: Application) : AndroidViewMod it.body?.let { val db = AppDatabase.getInstance(context) viewModelScope.launch { - TokenManager.token = it - db?.tokenDao()?.save(token = it) + TokenManager.init(it) + db?.tokenDao()?.save(token = it.token) }.invokeOnCompletion { _finishLogin.postValue(true) } } }, onFail = { callback(it) }, - type = object : TypeToken>() {}.type - ), + typeToken = object : TypeToken>() {}.type + ) + ClientType.Foreground -> HttpCallback( + action = loginDesc, + onSuccess = { + Logger.i(it.message) + callback(it.message) + val context = getApplication().applicationContext + it.body?.let { + val db = AppDatabase.getInstance(context) + viewModelScope.launch { + TokenManager.init(it) + db?.tokenDao()?.save(token = it.token) + }.invokeOnCompletion { + _finishLogin.postValue(true) + } + } + }, + onFail = { callback(it) }, + typeToken = object : TypeToken>() {}.type + ) + } + + HttpClient.post( + url, + call, jsonParam = loginParam() ) } else { @@ -91,8 +115,7 @@ abstract class AbstractLoginViewModel(application: Application) : AndroidViewMod * @param callback */ fun logout(context: Activity, callback: (message: String) -> Unit) { - TokenManager.token?.let { - Logger.i("帐号${it.id}将要退出登录") + viewModelScope.launch { HttpClient.post( Api.buildUrl(AccountApi.Logout), @@ -112,16 +135,16 @@ abstract class AbstractLoginViewModel(application: Application) : AndroidViewMod ) ) } - TokenManager.token = null + TokenManager.clear() } } callback(it.message) - }, onFail = { callback("退出登陆失败") }, - type = object : TypeToken>() {}.type + }, + onFail = { callback("退出登陆失败") }, + typeToken = object : TypeToken>() {}.type ), - jsonParam = OnlyToken(token = it, clientType = clientType) + jsonParam = OnlyToken(clientType = clientType) ) - } } } } \ No newline at end of file diff --git a/lib/src/main/java/com/gyf/lib/model/ApplyViewModel.kt b/lib/src/main/java/com/gyf/lib/model/ApplyViewModel.kt index 68c138b..6f8454f 100644 --- a/lib/src/main/java/com/gyf/lib/model/ApplyViewModel.kt +++ b/lib/src/main/java/com/gyf/lib/model/ApplyViewModel.kt @@ -5,6 +5,9 @@ import com.gyf.lib.R import com.gyf.lib.uikit.StringForm abstract class ApplyViewModel(application: Application) : ScrollViewModel(application) { - val approverOrigin = - StringForm(formDesc = application.getString(R.string.approver_origin), textLength = 30) + val approveOrigin = + StringForm( + formDesc = application.getString(R.string.first_approver_origin), + textLength = 30 + ) } \ No newline at end of file diff --git a/lib/src/main/java/com/gyf/lib/model/InitViewModel.kt b/lib/src/main/java/com/gyf/lib/model/InitViewModel.kt index 5c2d119..d7e4633 100644 --- a/lib/src/main/java/com/gyf/lib/model/InitViewModel.kt +++ b/lib/src/main/java/com/gyf/lib/model/InitViewModel.kt @@ -9,6 +9,7 @@ import com.google.gson.reflect.TypeToken import com.gyf.lib.util.* import com.orhanobut.logger.Logger import kotlinx.coroutines.launch +import java.lang.reflect.Type class InitViewModel(application: Application) : AndroidViewModel(application) { /** @@ -17,7 +18,6 @@ class InitViewModel(application: Application) : AndroidViewModel(application) { private val _isNetWorkWorking = MutableLiveData() val isNetWorkWorking: LiveData = _isNetWorkWorking - init { checkServer() } @@ -32,7 +32,7 @@ class InitViewModel(application: Application) : AndroidViewModel(application) { }, onFail = { Logger.e(it) _isNetWorkWorking.postValue(false) - }, type = object : TypeToken>() {}.type) + }, typeToken = object : TypeToken>() {}.type) ) } @@ -41,7 +41,10 @@ class InitViewModel(application: Application) : AndroidViewModel(application) { /** * 查询本地是否有且只有一个用户token,如果有则自动登录 */ - fun hasOnlyUserToken(onSuccess: () -> Unit, onFail: () -> Unit, api: AccountApi) { + fun hasOnlyUserToken( + onSuccess: () -> Unit, onFail: () -> Unit, api: AccountApi, + typeToken: Type + ) { viewModelScope.launch { val context = getApplication() val db = AppDatabase.getInstance(context) @@ -53,14 +56,12 @@ class InitViewModel(application: Application) : AndroidViewModel(application) { Logger.i("${action}api=$url") HttpClient.post( url, - HttpCallback( + HttpCallback( action = action, onSuccess = { it -> it.body?.let { Logger.i("token校验结果:${it}") - if (it) { - TokenManager.token = currentToken - } + TokenManager.init(it) onSuccess() } @@ -68,11 +69,10 @@ class InitViewModel(application: Application) : AndroidViewModel(application) { onFail = { Logger.e(it) onFail() - }, - type = object : TypeToken>() {}.type - ), + }, typeToken = typeToken), jsonParam = currentToken ) + } else if (tokenList != null && tokenList.size > 1) { //TODO 实现切换历史登录帐号 diff --git a/lib/src/main/java/com/gyf/lib/model/ScrollViewModel.kt b/lib/src/main/java/com/gyf/lib/model/ScrollViewModel.kt index c99f054..f31ae21 100644 --- a/lib/src/main/java/com/gyf/lib/model/ScrollViewModel.kt +++ b/lib/src/main/java/com/gyf/lib/model/ScrollViewModel.kt @@ -11,8 +11,13 @@ abstract class ScrollViewModel(application: Application) : AndroidViewModel(a abstract val initSize: Int + //加载列表 - abstract fun load() + @Deprecated("") + open fun load() { + } + + open fun load(callback: (message: String) -> Unit) {} //加载更多数据 abstract fun loadMore(callback: (message: String) -> Unit) diff --git a/foreground/src/main/java/com/gyf/csams/message/model/SysMessageViewModel.kt b/lib/src/main/java/com/gyf/lib/model/SysMessageViewModel.kt similarity index 60% rename from foreground/src/main/java/com/gyf/csams/message/model/SysMessageViewModel.kt rename to lib/src/main/java/com/gyf/lib/model/SysMessageViewModel.kt index de7aa97..c046f38 100644 --- a/foreground/src/main/java/com/gyf/csams/message/model/SysMessageViewModel.kt +++ b/lib/src/main/java/com/gyf/lib/model/SysMessageViewModel.kt @@ -1,12 +1,10 @@ -package com.gyf.csams.message.model +package com.gyf.lib.model import android.app.Application import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.google.gson.reflect.TypeToken -import com.gyf.csams.util.SimpleCallback -import com.gyf.lib.model.ScrollViewModel import com.gyf.lib.util.* import com.orhanobut.logger.Logger import kotlinx.coroutines.launch @@ -19,8 +17,6 @@ enum class SystemType(val desc: String) { } -data class NotificationVo(val title: String, val content: String, val id: Int, val createTime: Long) - /** * 通知内容 * @@ -82,7 +78,8 @@ data class RenameContent( * 系统通知数据状态管理 * */ -class SysMessageViewModel(application: Application) : ScrollViewModel(application) { +abstract class SysMessageViewModel(application: Application) : + ScrollViewModel(application) { val title = "系统通知" override val initSize: Int = 10 @@ -90,43 +87,43 @@ class SysMessageViewModel(application: Application) : ScrollViewModel() val currentPage: LiveData = _currentPage + abstract fun clientType(): ClientType + init { load() } + /** *加载通知列表 * */ - override fun load() { + final override fun load() { viewModelScope.launch { - TokenManager.token?.let { it -> - HttpClient.post( - Api.buildUrl(NotificationApi.List), - SimpleCallback>( - action = "获取通知列表", - onSuccess = { - it.body?.let { - _data.postValue(it) - } - Logger.i(it.message) - }, - onFail = { - Logger.e(it) - }, - type = object : - TypeToken>>() {}.type - ), - jsonParam = NotificationDto( - receiverId = it.id, - receiverClient = ClientType.Foreground, - token = it, page = PageDto( - currentPage = _currentPage.value ?: 1, - pageSize = initSize - ) + HttpClient.post( + Api.buildUrl(NotificationApi.List), + HttpCallback>( + action = "获取通知列表", + onSuccess = { + it.body?.let { + _data.postValue(it) + } + Logger.i(it.message) + }, + onFail = { + Logger.e(it) + }, + typeToken = object : + TypeToken>>() {}.type + ), + jsonParam = NotificationDto( + receiverId = TokenManager.getToken().id, + receiverClient = clientType(), page = PageDto( + currentPage = _currentPage.value ?: 1, + pageSize = initSize ) ) - } + ) } } diff --git a/lib/src/main/java/com/gyf/lib/service/MessageService.kt b/lib/src/main/java/com/gyf/lib/service/MessageService.kt index 0fd9f00..316e0e6 100644 --- a/lib/src/main/java/com/gyf/lib/service/MessageService.kt +++ b/lib/src/main/java/com/gyf/lib/service/MessageService.kt @@ -32,13 +32,11 @@ class MessageService : JobIntentService() { } override fun onHandleWork(intent: Intent) { - TokenManager.token?.let { it -> HttpClient.postAsync>( url = Api.buildUrl(NotificationApi.Pull), jsonParam = NotificationDto( - receiverId = it.id, - receiverClient = clientType, - token = it + receiverId = TokenManager.getToken().id, + receiverClient = clientType ), type = object : TypeToken>>() {}.type )?.let { it1 -> @@ -57,7 +55,6 @@ class MessageService : JobIntentService() { notify(it.id, builder.build()) } } - } } } } \ No newline at end of file diff --git a/lib/src/main/java/com/gyf/lib/uikit/AbstractInitActivity.kt b/lib/src/main/java/com/gyf/lib/uikit/AbstractInitActivity.kt index 9e67730..fe51c67 100644 --- a/lib/src/main/java/com/gyf/lib/uikit/AbstractInitActivity.kt +++ b/lib/src/main/java/com/gyf/lib/uikit/AbstractInitActivity.kt @@ -12,12 +12,14 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.gyf.lib.BuildConfig import com.gyf.lib.model.InitViewModel import com.gyf.lib.util.AccountApi +import com.gyf.lib.util.OwnInfoVo import com.orhanobut.logger.Logger import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import java.lang.reflect.Type -abstract class AbstractInitActivity : ComponentActivity() { +abstract class AbstractInitActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -49,13 +51,15 @@ abstract class AbstractInitActivity : ComponentActivity() { abstract val api: AccountApi + abstract val typeToken: Type + private fun init(initViewModel: InitViewModel) { //后台检查token - initViewModel.hasOnlyUserToken(onSuccess = { + initViewModel.hasOnlyUserToken(onSuccess = { startActivity(Intent(this, main)) }, onFail = { startActivity(Intent(this, login)) - }, api = api) + }, api = api, typeToken = typeToken) GlobalScope.launch { delay(1000) finish() diff --git a/lib/src/main/java/com/gyf/lib/uikit/MainFrame.kt b/lib/src/main/java/com/gyf/lib/uikit/MainFrame.kt index 6120a9e..494261f 100644 --- a/lib/src/main/java/com/gyf/lib/uikit/MainFrame.kt +++ b/lib/src/main/java/com/gyf/lib/uikit/MainFrame.kt @@ -8,6 +8,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController +import com.google.accompanist.insets.ExperimentalAnimatedInsets +import com.google.accompanist.insets.ProvideWindowInsets import com.gyf.lib.uikit.theme.CSAMSTheme @@ -157,9 +159,24 @@ fun Body(content: @Composable () -> Unit) { } } +@ExperimentalAnimatedInsets +@Composable +fun ImeBody(content: @Composable () -> Unit) { + CSAMSTheme { + ProvideWindowInsets(windowInsetsAnimationsEnabled = true) { + Surface(color = MaterialTheme.colors.background) { + val scaffoldState = rememberScaffoldState() + Scaffold(scaffoldState = scaffoldState) { + content() + ShowSnackbar(scaffoldState = scaffoldState) + } + } + } + } +} @Composable -fun TestBody(content: @Composable (nav: NavHostController, scaffoldState: ScaffoldState) -> Unit) { +fun NavBody(content: @Composable (nav: NavHostController, scaffoldState: ScaffoldState) -> Unit) { CSAMSTheme { Surface(color = MaterialTheme.colors.background) { val navController = rememberNavController() @@ -170,4 +187,5 @@ fun TestBody(content: @Composable (nav: NavHostController, scaffoldState: Scaffo } } } -} \ No newline at end of file +} + diff --git a/lib/src/main/java/com/gyf/lib/uikit/Profile.kt b/lib/src/main/java/com/gyf/lib/uikit/Profile.kt index faed256..fadc00e 100644 --- a/lib/src/main/java/com/gyf/lib/uikit/Profile.kt +++ b/lib/src/main/java/com/gyf/lib/uikit/Profile.kt @@ -12,21 +12,23 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp -import com.gyf.lib.util.ImageUtil +import com.gyf.lib.util.* -abstract class PersonInfoVo { - abstract val name: String - abstract val duty: String - abstract val headImg: String - abstract val desc: String -} - @Composable fun Profile( modifier: Modifier, - personInfoVo: PersonInfoVo, - duty: @Composable () -> Unit = { Text(text = personInfoVo.duty) } + personInfoVo: PersonInfoVo = TokenManager.getOwnInfo(), + duty: @Composable () -> Unit = { + Text( + text = when (personInfoVo) { + is UserVo -> personInfoVo.manager?.duty?.desc ?: "----" + is ManagerVo -> personInfoVo.duty.desc + is ManagerInfoVo -> personInfoVo.duty.desc + else -> throw IllegalArgumentException("个人信息类型错误:${personInfoVo}") + } + ) + } ) { var headImg: ImageBitmap? by remember { mutableStateOf(null) diff --git a/lib/src/main/java/com/gyf/lib/util/Api.kt b/lib/src/main/java/com/gyf/lib/util/Api.kt index 8caf4b2..6ed85a3 100644 --- a/lib/src/main/java/com/gyf/lib/util/Api.kt +++ b/lib/src/main/java/com/gyf/lib/util/Api.kt @@ -33,7 +33,6 @@ enum class AccountApi(val path: String) : UrlPath { //后台登陆 BackgroundLogin("/login/${ClientType.Background.name.toLowerCase(Locale.ROOT)}"), - //前台令牌校验 ForegroundToken("${ForegroundLogin.path}/token"), @@ -74,8 +73,12 @@ enum class MainApi(val path: String) : UrlPath { */ enum class AssociationApi(val path: String) : UrlPath { Logo("/uploadLogo"), - Register("/register"); - + Register("/register"), + Accept("/accept"), + List("/list"), + Check("/check"), + Audit("/audit"), + Read("/read"); override fun build(): String { return "/api/association${this.path}" diff --git a/lib/src/main/java/com/gyf/lib/util/BottomButton.kt b/lib/src/main/java/com/gyf/lib/util/BottomButton.kt index 6f32556..ee725d7 100644 --- a/lib/src/main/java/com/gyf/lib/util/BottomButton.kt +++ b/lib/src/main/java/com/gyf/lib/util/BottomButton.kt @@ -22,7 +22,8 @@ fun BottomButton( modifier: Modifier = Modifier, enabled: Boolean = true, @StringRes confirmDesc: Int = R.string.confirm_btn, - @StringRes backDesc: Int = R.string.back_btn, + @StringRes backDesc: Int? = R.string.back_btn, + onBack: (() -> Unit)? = null, onConfirm: () -> Unit ) { val context = LocalContext.current as Activity @@ -34,11 +35,16 @@ fun BottomButton( ) { Text(text = stringResource(id = confirmDesc)) } - Spacer(modifier = Modifier.width(10.dp)) - OutlinedButton(onClick = { - context.onBackPressed() - }, modifier = Modifier.background(color = MaterialTheme.colors.secondary)) { - Text(text = stringResource(id = backDesc)) + + if (backDesc != null) { + Spacer(modifier = Modifier.width(10.dp)) + OutlinedButton(onClick = { + if (onBack == null) context.onBackPressed() else onBack() + }, modifier = Modifier.background(color = MaterialTheme.colors.secondary)) { + Text(text = stringResource(id = backDesc)) + } } + } -} \ No newline at end of file +} + diff --git a/lib/src/main/java/com/gyf/lib/util/HttpUtil.kt b/lib/src/main/java/com/gyf/lib/util/HttpUtil.kt index a75e57f..6d2cfa0 100644 --- a/lib/src/main/java/com/gyf/lib/util/HttpUtil.kt +++ b/lib/src/main/java/com/gyf/lib/util/HttpUtil.kt @@ -1,6 +1,7 @@ package com.gyf.lib.util import com.google.gson.Gson +import com.google.gson.JsonSyntaxException import com.orhanobut.logger.Logger import okhttp3.* import okhttp3.MediaType.Companion.toMediaType @@ -116,8 +117,9 @@ object HttpClient { * @param url * @param callback */ - fun uploadFile(url: String, callback: Callback, token: Token, vararg fileList: File) { + fun uploadFile(url: String, callback: Callback, vararg fileList: File) { Logger.i("request url=$url") + val token = TokenManager.getToken() val body = MultipartBody.Builder() .addFormDataPart("id", token.id.toString()) .addFormDataPart("token", token.token) @@ -155,9 +157,9 @@ interface GsonBuilderInterface { open class HttpCallback( private val action: String, - private val onSuccess: (res: ApiResponse) -> Unit, - private val onFail: (error: String) -> Unit, - private val type: Type + private val onSuccess: (res: ApiResponse) -> Unit = { Logger.i(it.message) }, + private val onFail: (error: String) -> Unit = { Logger.e(it) }, + private val typeToken: Type ) : Callback, GsonBuilderInterface { override val gson: Gson = Gson() @@ -178,11 +180,18 @@ open class HttpCallback( val body = response.body if (body != null && body.contentType()?.subtype == "json") { val jsonRes = body.string() - Logger.json(jsonRes) - val res: ApiResponse = gson.fromJson(jsonRes, type) - Logger.i("json解析成功:$res") + Logger.i(jsonRes) + try { + val res: ApiResponse = gson.fromJson(jsonRes, typeToken) + onSuccess(res) + } catch (e: JsonSyntaxException) { + Logger.e(e, "json反序列化成${typeToken}失败") + onFail("json反序列化成${typeToken}失败") + } catch (e: Exception) { + Logger.e(e, "发生未知错误") + onFail("发生未知错误") + } - onSuccess(res) } else { onFail("${action}失败,请联系管理员") Logger.e("无法解析${action}请求响应数据:,响应码:${response.code},${response.body}") diff --git a/lib/src/main/java/com/gyf/lib/util/TokenUtil.kt b/lib/src/main/java/com/gyf/lib/util/TokenUtil.kt index 484c1c9..08f2431 100644 --- a/lib/src/main/java/com/gyf/lib/util/TokenUtil.kt +++ b/lib/src/main/java/com/gyf/lib/util/TokenUtil.kt @@ -17,16 +17,11 @@ data class Token( ) abstract class ClientBaseVo { - abstract val token: Token + val token: Token = TokenManager.getToken() abstract val clientType: ClientType } -abstract class BaseToken { - abstract val token: Token -} - data class OnlyToken( - override val token: Token = TokenManager.token ?: throw IllegalArgumentException("无法获取token"), override val clientType: ClientType ) : ClientBaseVo() @@ -46,8 +41,39 @@ interface TokenDao { } object TokenManager { - var token: Token? = null + private var ownInfo: OwnInfoVo? = null + private lateinit var personInfo: PersonInfoVo + + fun init(ownInfo: OwnInfoVo) { + this.ownInfo = ownInfo + when (ownInfo) { + is ManagerVo -> this.personInfo = ManagerInfoVo( + duty = ownInfo.duty, + name = ownInfo.name, + headImg = ownInfo.headImg, + desc = ownInfo.desc + ) + is UserVo -> this.personInfo = + UserInfoVo(name = ownInfo.name, headImg = ownInfo.headImg, desc = ownInfo.desc) + else -> throw IllegalArgumentException("token失败") + } + } + + fun clear() { + ownInfo = null + } + fun getOwnInfo(): OwnInfoVo { + return ownInfo ?: throw IllegalArgumentException("token没有初始化,非法调用") + } + + fun getPersonInfo(): PersonInfoVo { + return personInfo + } + + fun getToken(): Token { + return ownInfo?.token ?: throw IllegalArgumentException("token没有初始化,非法调用") + } } diff --git a/lib/src/main/java/com/gyf/lib/util/Vo.kt b/lib/src/main/java/com/gyf/lib/util/Vo.kt new file mode 100644 index 0000000..4a61966 --- /dev/null +++ b/lib/src/main/java/com/gyf/lib/util/Vo.kt @@ -0,0 +1,477 @@ +package com.gyf.lib.util + +import androidx.annotation.IntRange +import com.gyf.lib.uikit.StringForm +import java.util.* + +/** + * 一般信息 + * + */ +abstract class PersonInfoVo { + abstract val name: String + abstract val headImg: String? + abstract val desc: String +} + + +enum class Duty(val desc: String, val level: Int) { + + Teacher("老师", 1), + PamphaBhusal("总部长", 2), + SecretaryOfTheMinister("秘书部部长", 3), + PropagandaDepartment("宣传部部长", 3), + LiaisonMinister("外联部部长", 3), + SecretaryDepartmentOfficer("秘书部干事", 4), + PublicityDepartmentOfficer("宣传部干事", 4), + LiaisonOfficer("外联部干事", 4); + + + /** + * 是否是部门部长 + * + */ + fun isMinister(): Boolean { + return minister.contains(this) + } + + fun isOfficer(): Boolean { + return officer.contains(this) + } + +} + +private val minister = + arrayOf(Duty.SecretaryOfTheMinister, Duty.LiaisonMinister, Duty.PropagandaDepartment) +private val officer = + arrayOf(Duty.SecretaryDepartmentOfficer, Duty.PublicityDepartmentOfficer, Duty.LiaisonOfficer) + +/** + * 个人信息 + * + */ +abstract class OwnInfoVo : PersonInfoVo() { + abstract val token: Token +} + +data class ManagerInfoVo( + val duty: Duty, + override val name: String, + override val headImg: String?, + override val desc: String +) : PersonInfoVo() + +data class UserInfoVo( + override val name: String, + override val headImg: String?, + override val desc: String +) : PersonInfoVo() + + +/** + * 管理员个人信息 + * + * @property account 管理员账号 + * @property name 姓名 + * @property duty 职务 + * @property headImg 头像 + * @property desc 个人简介 + */ +data class ManagerVo( + val account: String, + val duty: Duty, + override val token: Token, + override val name: String, + override val headImg: String?, + override val desc: String +) : OwnInfoVo() + + +/** + * 用户个人信息 + * + * @property studentId 学号 + * @property name 姓名 + * @property headImg 头像 + * @property desc 个人简介 + */ +data class UserVo( + val studentId: String, + val manager: ManagerVo? = null, + override val token: Token, + override val name: String, + override val headImg: String?, + override val desc: String, + val associationMemberVo: AssociationMemberVo? +) : OwnInfoVo() + +data class PageDto(val currentPage: Long, val pageSize: Int = 10) + +data class NotificationDto( + val receiverId: Int, + val receiverClient: ClientType, + val page: PageDto? = null, + override val clientType: ClientType = receiverClient +) : ClientBaseVo() + +data class UserRegVo(val studentId: String, val name: String) + +/** + * 客户端类型 + * + */ +enum class ClientType { + //前台 + Foreground, + + //后台 + Background +} + + +data class NotificationVo(val title: String, val content: String, val id: Int, val createTime: Long) + + +/** + * 响应自动生成密码 + * + * @property password + */ +data class UserPasswordVo(val password: String) + + +/** + * 用户登陆表单 + * + * @property studentId 学号 + * @property password 密码 + * @property device 设备型号 + */ +data class UserLoginVo(val studentId: String, val password: String, val device: String) + + +/** + * + * @property associationName 社团名字 + * @property activityName 活动名 + * @property activityTime 活动时间 + * @property activityLocation 活动地点 + * @property activityDesc 活动介绍 + */ +data class ActivityDetailVo( + val associationName: String, val activityName: String, + val activityTime: Date, val activityLocation: String, + val activityDesc: String +) + + +data class ActivityMemberVo(val studentId: String, val name: String) + +/** + * 活动成员 + * + * @property organizer + * @property participant + */ +data class ActivityMembersVo( + val organizer: ActivityMemberVo, + val participant: MutableList? +) + + +/** + * 图片 + * @property name 文件名 + * @property size 文件大小 + * @property url 文件路径 + * @property md5 文件hash + * @property createTime 文件创建时间 + * @property studentId 文件上传人 + */ +data class ActivityPhotoVo( + val name: String, + val size: Long, + val url: String, + val md5: String, + val createTime: Date, + val studentId: String +) + +const val MAX_SCORE = 5L + +data class ActivityVo( + val activityId: Long, val activityName: String, val association: String, + @IntRange(from = 1, to = MAX_SCORE) val score: Int, val activityTime: Date, val location: String +) + + +data class AllOfficerVo( + val secretariat: MutableList, + val propaganda: MutableList, + val publicRelationsDepartment: MutableList +) + + +data class ApplyActVo( + val activityName: String, val activityTime: String, + val location: String, val desc: String, + val size: Int +) + +data class LeaveMessageVo( + val message: String, + override val clientType: ClientType = ClientType.Foreground +) : ClientBaseVo() + +/** + * 社团级别 + * + */ +enum class AssociationLevel { + A, + B, + C, + D +} + +/** + * 所属院系 + * + */ +enum class AssociationFaculty(val desc: String, val range: kotlin.ranges.IntRange) { + ForeignLanguageDept("外语系", 0..0), + CivilEngineeringDept("土木工程", 1..10), + SEM("经理管理学院", 11..20), + MechanicalEngineeringDept("机械工程", 21..30), + TransportationDept("交通运输", 31..40), + ArchitectureAndArts("建筑与艺术", 41..50), + ElectricalDept("电气", 51..60), + MaterialsDept("材料", 61..70), + MessageDept("信息", 71..80), + MathematicsDept("数理", 81..90), + GraduateStudent("研究生", 91..99) +} + +abstract class BaseAssociationVo { + abstract val id: Int + abstract val name: String + abstract val desc: String + abstract val logo: String + abstract val faculty: AssociationFaculty + abstract val level: AssociationLevel? +} + +/** + * 社团列表 + * + */ +class AssociationVo( + override val id: Int, + override val name: String, + override val desc: String, + override val logo: String, + override val faculty: AssociationFaculty, + override val level: AssociationLevel? +) : BaseAssociationVo() + +//审核状态 +enum class CheckStatus(val desc: String) { + WaitFirst("等待初审"), + AcceptFirst("初审受理"), + WaitLast("等待复审"), + AcceptLast("复审受理"), + Finish("审核完成") +} + +data class AssociationMemberVo( + val association: AssociationVo, + val isHead: Boolean +) + +//用户社团 +data class AssociationCheckVo( + override val id: Int, + override val name: String, + override val desc: String, + override val logo: String, + override val faculty: AssociationFaculty, + override val level: AssociationLevel?, + val checkStatus: CheckStatus, + val applyTime: Long, + val firstCause: String, + val lastCause: String?, + val fileId: Int +) : BaseAssociationVo() + +/** + * 搜索社团 + * + * @property name + * @property desc + * @property clientType + */ +data class SearchAssociationVo( + val name: String, val desc: String, + override val clientType: ClientType = ClientType.Foreground +) : ClientBaseVo() + + +data class BBSVo(val studentId: String, val name: String, val createTime: Date, val content: String) + + +/** + * 题型 + * + */ +enum class ExamType(val type: String) { + //选择题 + CQ("选择题"), + + //开放题 + OQ("开放题") +} + +abstract class Exam { + abstract val examType: ExamType + abstract val question: StringForm +} + + +/** + * 选择题 + * + * @property examType 题型描述 + * @property answers 答案 + * @property rightAnswer 正确答案 + * @property question 问题 + */ +data class ChoiceQuestionVo( + override val examType: ExamType = ExamType.CQ, + val answers: List, + val rightAnswer: Int, + override val question: StringForm +) : Exam() + + +data class HistoryActVo(val name: String) + + +/** + * 开放题 + * + * @property examType 题型描述 + * @property question 问题 + */ +data class OpenQuestionsVo( + override val examType: ExamType = ExamType.OQ, override val question: StringForm +) : Exam() + + +data class LeaveMessageFormatVo(val message: String, val user: UserInfoVo) + + +data class ManagerLoginVo(val account: String, val password: String, val device: String) + + +data class MemberVo(val name: String) + +data class OngoingActVo(val name: String) + +/** + * 活动质量汇报单 + * + * @property applyName 申请人 + * @property activityName 活动名称 + * @property merit 优点 + * @property defect 缺点 + * @property score 星级评价 + */ +data class QualityReportVo( + val applyName: String, + val activityName: String, + val merit: String, + val defect: String, + @IntRange(from = 1L, to = MAX_SCORE) val score: Int +) + +/** + * 社团注册资料表单 + * + * @property name + * @property desc + * @property fileId + */ +data class AssociationRegVo( + val id: Int?, val name: String, val desc: String, val fileId: Int, + override val clientType: ClientType = ClientType.Foreground +) : ClientBaseVo() + +/** + * 社团注册审核记录 + * + */ +data class DisposeRegInfoVo( + val name: String, + val desc: String, + val logo: String, + val log: AuditLoggingVo +) + +/** + * 通用审核记录 + * + * @property id + * @property user + * @property applyTime + * @property manager + * @property acceptTime + * @property cause + * @property result + * @property auditTime + * @property nextAudit + */ +data class AuditLoggingVo( + val id: Int, val user: UserInfoVo, val applyTime: Long, val manager: ManagerInfoVo?, + val acceptTime: Long?, val cause: String?, val result: Boolean?, + val auditTime: Long?, val nextAudit: AuditLoggingVo? +) + +/** + * 社团注册资料受理 + * + * @property regId + * @property clientType + */ +data class AcceptRegAssociation( + val regId: Int, + val isFirstAccept: Boolean, + override val clientType: ClientType = ClientType.Background +) : ClientBaseVo() + +/** + * 社团注册资料审核 + * + * @property regId + * @property result + * @property cause + * @property clientType + */ +data class CheckRegVo( + val regId: Int, val result: Boolean, val cause: String, + override val clientType: ClientType = ClientType.Background +) : ClientBaseVo() + +/** + * 换名申请表 + * + * @property studentId 学号 + * @property oldName 社团原名 + * @property newName 社团新名 + * @property reason 申请理由 + */ +data class RenameVo( + val studentId: String, + val oldName: String, + val newName: String, + val reason: String +) \ No newline at end of file diff --git a/lib/src/main/java/com/gyf/lib/util/vo.kt b/lib/src/main/java/com/gyf/lib/util/vo.kt deleted file mode 100644 index 4b5e8d6..0000000 --- a/lib/src/main/java/com/gyf/lib/util/vo.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.gyf.lib.util - - -data class NotificationVo(val title: String, val content: String, val id: Int) - -data class PageDto(val currentPage: Long, val pageSize: Int = 10) - -data class NotificationDto( - val receiverId: Int, - val receiverClient: ClientType, - override val token: Token, - val page: PageDto? = null, - override val clientType: ClientType = receiverClient -) : ClientBaseVo() - - -/** - * 客户端类型 - * - */ -enum class ClientType { - //前台 - Foreground, - - //后台 - Background -} \ No newline at end of file diff --git a/lib/src/main/res/values-en/strings.xml b/lib/src/main/res/values-en/strings.xml index 45a448e..1d82610 100644 --- a/lib/src/main/res/values-en/strings.xml +++ b/lib/src/main/res/values-en/strings.xml @@ -17,9 +17,17 @@ 社团原名 社团新名 申请理由 - 审批人 - 审核理由 + 初审负责人 + 初审意见 抱歉此功能尚未开放 活动质量汇报单 登录 + 社团注册资料 + 社团简介 + 社团logo + 社团名称 + 审核结果 + 复审 + 审核阶段 + 复审意见 \ No newline at end of file diff --git a/lib/src/main/res/values-zh/strings.xml b/lib/src/main/res/values-zh/strings.xml index 45a448e..1d82610 100644 --- a/lib/src/main/res/values-zh/strings.xml +++ b/lib/src/main/res/values-zh/strings.xml @@ -17,9 +17,17 @@ 社团原名 社团新名 申请理由 - 审批人 - 审核理由 + 初审负责人 + 初审意见 抱歉此功能尚未开放 活动质量汇报单 登录 + 社团注册资料 + 社团简介 + 社团logo + 社团名称 + 审核结果 + 复审 + 审核阶段 + 复审意见 \ No newline at end of file diff --git a/lib/src/main/res/values/strings.xml b/lib/src/main/res/values/strings.xml index 45a448e..1d82610 100644 --- a/lib/src/main/res/values/strings.xml +++ b/lib/src/main/res/values/strings.xml @@ -17,9 +17,17 @@ 社团原名 社团新名 申请理由 - 审批人 - 审核理由 + 初审负责人 + 初审意见 抱歉此功能尚未开放 活动质量汇报单 登录 + 社团注册资料 + 社团简介 + 社团logo + 社团名称 + 审核结果 + 复审 + 审核阶段 + 复审意见 \ No newline at end of file