答辩测试版

master
pan 4 years ago
parent 61113b6f5a
commit acb519df85
  1. 2
      background/src/main/AndroidManifest.xml
  2. 6
      background/src/main/java/com/gyf/csams/account/model/LoginViewModel.kt
  3. 49
      background/src/main/java/com/gyf/csams/main/model/AssociationManagementViewModel.kt
  4. 2
      background/src/main/java/com/gyf/csams/main/model/AuditActViewModel.kt
  5. 2
      background/src/main/java/com/gyf/csams/main/model/AuditAssociationViewModel.kt
  6. 25
      background/src/main/java/com/gyf/csams/main/model/AuditRenameViewModel.kt
  7. 3
      background/src/main/java/com/gyf/csams/main/model/BaseAuditViewModel.kt
  8. 4
      background/src/main/java/com/gyf/csams/main/model/CheckQualityReportViewModel.kt
  9. 50
      background/src/main/java/com/gyf/csams/main/model/ManagementOfficerModel.kt
  10. 19
      background/src/main/java/com/gyf/csams/main/model/ManagerActViewModel.kt
  11. 17
      background/src/main/java/com/gyf/csams/main/model/MenuViewModel.kt
  12. 46
      background/src/main/java/com/gyf/csams/main/model/RenameViewModel.kt
  13. 13
      background/src/main/java/com/gyf/csams/main/ui/AssociationManagementActivity.kt
  14. 87
      background/src/main/java/com/gyf/csams/main/ui/AuditRenameActivity.kt
  15. 45
      background/src/main/java/com/gyf/csams/main/ui/DepartmentActivity.kt
  16. 11
      background/src/main/java/com/gyf/csams/main/ui/MainActivity.kt
  17. 5
      background/src/main/java/com/gyf/csams/main/ui/ManagementOfficerActivity.kt
  18. 87
      background/src/main/java/com/gyf/csams/main/ui/RenameActivity.kt
  19. 9
      background/src/main/java/com/gyf/csams/uikit/CheckForm.kt
  20. 2
      foreground/src/main/AndroidManifest.xml
  21. 12
      foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt
  22. 2
      foreground/src/main/java/com/gyf/csams/account/ui/AccountActivity.kt
  23. 6
      foreground/src/main/java/com/gyf/csams/activity/model/ActivityDetailViewModel.kt
  24. 31
      foreground/src/main/java/com/gyf/csams/activity/model/ApplyActViewModel.kt
  25. 25
      foreground/src/main/java/com/gyf/csams/activity/ui/ApplyActActivity.kt
  26. 8
      foreground/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt
  27. 109
      foreground/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt
  28. 8
      foreground/src/main/java/com/gyf/csams/association/model/RegAssociationViewModel.kt
  29. 87
      foreground/src/main/java/com/gyf/csams/association/model/RenameViewModel.kt
  30. 72
      foreground/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt
  31. 105
      foreground/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt
  32. 99
      foreground/src/main/java/com/gyf/csams/association/ui/ReNameActivity.kt
  33. 195
      foreground/src/main/java/com/gyf/csams/association/ui/RenameActivity.kt
  34. 2
      foreground/src/main/java/com/gyf/csams/main/model/MainViewModel.kt
  35. 145
      foreground/src/main/java/com/gyf/csams/main/ui/MainActivity.kt
  36. 19
      foreground/src/main/java/com/gyf/csams/uikit/BaseView.kt
  37. 92
      foreground/src/main/java/com/gyf/csams/uikit/ViewModel.kt
  38. 8
      foreground/src/main/java/com/gyf/csams/util/GsonUtil.kt
  39. 2
      foreground/src/main/java/com/gyf/csams/util/HttpCallback.kt
  40. 2
      foreground/src/test/java/com/gyf/csams/ExampleUnitTest.kt
  41. 1
      lib/build.gradle.kts
  42. 15
      lib/src/main/java/com/gyf/lib/uikit/BaseTextField.kt
  43. 36
      lib/src/main/java/com/gyf/lib/util/Api.kt
  44. 1
      lib/src/test/java/com/gyf/lib/ExampleUnitTest.kt

@ -39,7 +39,7 @@
<!--菜单--> <!--菜单-->
<activity android:name=".main.ui.MenuActivity" /> <activity android:name=".main.ui.MenuActivity" />
<!--社团换名--> <!--社团换名-->
<activity android:name=".main.ui.RenameActivity" /> <activity android:name=".main.ui.AuditRenameActivity" />
<!--活动管理--> <!--活动管理-->
<activity android:name=".main.ui.ManagerActActivity" /> <activity android:name=".main.ui.ManagerActActivity" />
<!--审核社团注册--> <!--审核社团注册-->

@ -23,11 +23,9 @@ class LoginViewModel(application: Application) : AbstractLoginViewModel(applicat
} }
override fun loginParam(): Any { override fun loginParam(): Any {
val account = "${id.formValue.value}"
val password = "${password.formValue.value}"
return ManagerLoginVo( return ManagerLoginVo(
account = account, account = id.getValue(),
password = password, password = password.getValue(),
device = "${Build.MANUFACTURER} ${Build.MODEL}" device = "${Build.MANUFACTURER} ${Build.MODEL}"
) )
} }

@ -1,9 +1,13 @@
package com.gyf.csams.main.model package com.gyf.csams.main.model
import android.app.Application import android.app.Application
import com.gyf.csams.module.AssociationLevel import androidx.lifecycle.viewModelScope
import com.gyf.csams.module.AssociationVo import com.google.gson.reflect.TypeToken
import com.gyf.csams.module.*
import com.gyf.lib.model.ScrollViewModel import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.util.*
import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch
/** /**
@ -13,25 +17,50 @@ import com.gyf.lib.model.ScrollViewModel
class AssociationManagementViewModel(application: Application) : ScrollViewModel<AssociationVo>( class AssociationManagementViewModel(application: Application) : ScrollViewModel<AssociationVo>(
application application
) { ) {
override val initSize: Int = 10
init { init {
load() load()
} }
fun load() { fun load() {
TODO("数据状态管理") viewModelScope.launch {
} HttpClient.post(
url = Api.buildUrl(AssociationApi.ListAll),
fun loadMore(callback: (message: String) -> Unit) { callback = HttpCallback<MutableList<AssociationVo>>(action = "加载社团",
TODO("Not yet implemented") onSuccess = { it ->
it.body?.let {
_data.postValue(it)
}
},
typeToken = object :
TypeToken<ApiResponse<MutableList<AssociationVo>>>() {}.type
),
jsonParam = OnlyToken(clientType = ClientType.Background)
)
}
} }
/** /**
* *
* @param level * @param level
*/ */
fun update(associationDto: AssociationVo, level: AssociationLevel) { fun update(
TODO("更新社团级别") associationVo: AssociationVo,
level: AssociationLevel,
callback: (m: String) -> Unit
) {
Logger.i("社团:${associationVo.name}")
HttpClient.post(url = Api.buildUrl(AssociationApi.Update),
callback = HttpCallback<Boolean>(action = "社团等级更新",
onSuccess = {
callback(it.message)
}, typeToken = object : TypeToken<ApiResponse<Boolean>>() {}.type
),
jsonParam = UpdateAssociationVo(
associationVo = associationVo.copy(level = level),
token = TokenManager.getToken(),
clientType = ClientType.Background
)
)
} }
} }

@ -21,7 +21,7 @@ class AuditActViewModel(application: Application) : BaseAuditViewModel<AuditActV
object : TypeToken<ApiResponse<MutableList<AuditActVo>>>() {}.type object : TypeToken<ApiResponse<MutableList<AuditActVo>>>() {}.type
init { init {
load { } load()
} }

@ -20,7 +20,7 @@ class AuditAssociationViewModel(application: Application) : BaseAuditViewModel<A
object : TypeToken<ApiResponse<MutableList<AuditAssociationVo>>>() {}.type object : TypeToken<ApiResponse<MutableList<AuditAssociationVo>>>() {}.type
init { init {
load { } load()
} }

@ -0,0 +1,25 @@
package com.gyf.csams.main.model
import android.app.Application
import com.google.gson.reflect.TypeToken
import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.AuditRenameVo
import com.gyf.lib.util.AssociationApi
import com.gyf.lib.util.UrlPath
import java.lang.reflect.Type
class AuditRenameViewModel(application: Application) :
BaseAuditViewModel<AuditRenameVo>(application) {
override val auditApi: UrlPath = AssociationApi.RenameAudit
override val acceptApi: UrlPath = AssociationApi.RenameAccept
override val checkApi: UrlPath = AssociationApi.RenameCheck
override val typeToken: Type =
object : TypeToken<ApiResponse<MutableList<AuditRenameVo>>>() {}.type
init {
load()
}
}

@ -22,9 +22,8 @@ abstract class BaseAuditViewModel<T : AuditVo>(application: Application) :
/** /**
* 加载审核记录 * 加载审核记录
* *
* @param callback
*/ */
fun load(callback: (message: String) -> Unit) { fun load() {
viewModelScope.launch { viewModelScope.launch {
HttpClient.post( HttpClient.post(
Api.buildUrl(auditApi), HttpCallback<MutableList<T>>( Api.buildUrl(auditApi), HttpCallback<MutableList<T>>(

@ -38,8 +38,4 @@ class CheckQualityReportViewModel(application: Application) : ApplyViewModel<Qua
} }
} }
} }
fun loadMore(callback: (message: String) -> Unit) {
TODO("Not yet implemented")
}
} }

@ -3,8 +3,15 @@ package com.gyf.csams.main.model
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.csams.module.AllOfficerVo import com.gyf.csams.module.AllOfficerVo
import com.gyf.csams.module.ManagerInfoVo import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.ClientType
import com.gyf.csams.module.ManagerDutySumVo
import com.gyf.lib.util.*
import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch
enum class ColumnType { enum class ColumnType {
@ -21,20 +28,53 @@ class ManagementOfficerModel : ViewModel() {
private val _data = MutableLiveData<AllOfficerVo>() private val _data = MutableLiveData<AllOfficerVo>()
val data: LiveData<AllOfficerVo> = _data val data: LiveData<AllOfficerVo> = _data
//部门概况
private val _simpleData = MutableLiveData<ManagerDutySumVo>()
val simpleData: LiveData<ManagerDutySumVo> = _simpleData
init { init {
load() load()
} }
fun updateDuty(list: MutableList<ManagerInfoVo>, index: Int) { //TODO 更新职务
TODO("更新职务") fun updateDuty() {
Logger.i("更新职务")
} }
/** /**
* *加载部门概况
*/ */
private fun load() { private fun load() {
TODO("加载部门成员") viewModelScope.launch {
HttpClient.post(url = Api.buildUrl(AccountApi.Load),
callback = HttpCallback<ManagerDutySumVo>(action = "加载部门概况", onSuccess =
{ it ->
it.body?.let {
_simpleData.postValue(it)
}
}, typeToken = object : TypeToken<ApiResponse<ManagerDutySumVo>>() {}.type
),
jsonParam = OnlyToken(clientType = ClientType.Background)
)
}
}
/**
* 加载部门详情
*
*/
fun loadDetail() {
viewModelScope.launch {
HttpClient.post(
url = Api.buildUrl(AccountApi.LoadDetail),
callback = HttpCallback<AllOfficerVo>(action = "加载部门详情", onSuccess = { it ->
it.body?.let {
_data.postValue(it)
}
}, typeToken = object : TypeToken<ApiResponse<AllOfficerVo>>() {}.type),
jsonParam = OnlyToken(clientType = ClientType.Background)
)
}
} }
} }

@ -1,8 +1,12 @@
package com.gyf.csams.main.model package com.gyf.csams.main.model
import android.app.Application import android.app.Application
import com.google.gson.reflect.TypeToken
import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.ClientType
import com.gyf.csams.module.ManagerActVo import com.gyf.csams.module.ManagerActVo
import com.gyf.lib.model.ScrollViewModel import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.util.*
/** /**
@ -20,10 +24,17 @@ class ManagerActViewModel(application: Application) : ScrollViewModel<ManagerAct
} }
fun load() { fun load() {
TODO("活动信息管理") HttpClient.post(url = Api.buildUrl(ActivityApi.ListAll),
callback = HttpCallback<MutableList<ManagerActVo>>(action = "查看活动信息",
onSuccess = { it ->
it.body.let {
_data.postValue(it)
}
}, typeToken = object : TypeToken<ApiResponse<MutableList<ManagerActVo>>>() {}.type
),
jsonParam = OnlyToken(clientType = ClientType.Background)
)
} }
fun loadMore(callback: (message: String) -> Unit) {
TODO("Not yet implemented")
}
} }

@ -1,29 +1,22 @@
package com.gyf.csams.main.model package com.gyf.csams.main.model
import android.app.Activity import android.app.Activity
import androidx.lifecycle.ViewModel import com.gyf.csams.main.ui.*
import com.gyf.csams.main.ui.AuditActActivity
import com.gyf.csams.main.ui.AuditAssociationActivity
import com.gyf.csams.main.ui.RenameActivity
enum class MenuType(val desc: String, val clazz: Map<String, Class<out Activity>>) { enum class MenuType(val desc: String, val clazz: Map<String, Class<out Activity>>) {
Association( Association(
"社团管理", "社团管理",
mapOf( mapOf(
// TODO "社团信息管理" to AssociationManagementActivity::class.java, "社团信息管理" to AssociationManagementActivity::class.java,
"审核社团换名" to RenameActivity::class.java, "审核社团换名" to AuditRenameActivity::class.java,
"审核社团注册" to AuditAssociationActivity::class.java "审核社团注册" to AuditAssociationActivity::class.java
), ),
), ),
Act( Act(
"活动管理", mapOf( "活动管理", mapOf(
"审核社团活动" to AuditActActivity::class.java, "审核社团活动" to AuditActActivity::class.java,
// TODO "审核质量报告单" to CheckQualityReportActivity::class.java, "审核质量报告单" to CheckQualityReportActivity::class.java,
// "查看社团活动" to ManagerActActivity::class.java "查看社团活动" to ManagerActActivity::class.java
) )
) )
} }
class MenuViewModel : ViewModel() {
}

@ -1,46 +0,0 @@
package com.gyf.csams.main.model
import android.app.Application
import androidx.lifecycle.viewModelScope
import com.gyf.csams.R
import com.gyf.csams.module.RenameVo
import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.util.randomChinese
import com.gyf.lib.util.randomNum
import kotlinx.coroutines.launch
class RenameViewModel(application: Application) : ScrollViewModel<RenameVo>(application) {
val approverOrigin =
StringForm(
formDesc = application.getString(R.string.first_approver_origin),
textLength = 30
)
override val initSize: Int = 10
init {
load()
}
fun load() {
viewModelScope.launch {
_data.value?.apply {
repeat(initSize) {
add(
RenameVo(
studentId = randomNum(8),
oldName = randomChinese(5),
newName = randomChinese(5),
reason = randomChinese(10)
)
)
}
}
}
}
}

@ -20,6 +20,7 @@ import com.gyf.csams.main.model.AssociationManagementViewModel
import com.gyf.csams.module.AssociationLevel import com.gyf.csams.module.AssociationLevel
import com.gyf.lib.uikit.Body import com.gyf.lib.uikit.Body
import com.gyf.lib.uikit.MainBoxFrame import com.gyf.lib.uikit.MainBoxFrame
import com.gyf.lib.uikit.ScaffoldModel
/** /**
* 社团管理 * 社团管理
@ -85,15 +86,23 @@ class AssociationManagementActivity : ComponentActivity() {
text = level?.name ?: "暂无评级", text = level?.name ?: "暂无评级",
style = MaterialTheme.typography.h5 style = MaterialTheme.typography.h5
) )
val scaffoldModel: ScaffoldModel = viewModel()
DropdownMenu( DropdownMenu(
expanded = expanded, expanded = expanded,
onDismissRequest = { /*TODO*/ }) { onDismissRequest = { /*TODO*/ }) {
AssociationLevel.values().forEach { AssociationLevel.values().forEach {
DropdownMenuItem(onClick = { DropdownMenuItem(onClick = {
model.update( model.update(
associationDto = this@apply, associationVo = this@apply,
level = it level = it
) ) {
scaffoldModel.update(
message = it,
actionLabel = "刷新"
) {
model.load()
}
}
expanded = false expanded = false
}) { }) {
Text(text = it.name) Text(text = it.name)

@ -0,0 +1,87 @@
package com.gyf.csams.main.ui
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.material.ExperimentalMaterialApi
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.lifecycle.viewmodel.compose.viewModel
import com.google.accompanist.insets.ExperimentalAnimatedInsets
import com.gyf.csams.R
import com.gyf.csams.main.model.AuditRenameViewModel
import com.gyf.csams.module.AuditRenameVo
import com.gyf.csams.uikit.CheckForm
import com.gyf.csams.uikit.RowItem
import com.gyf.csams.uikit.TestTable
import com.gyf.csams.uikit.TestTableImeSimple
import com.gyf.lib.uikit.ImeBody
class AuditRenameActivity : ComponentActivity() {
@ExperimentalMaterialApi
@ExperimentalAnimatedInsets
@ExperimentalComposeApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TestTable(clazz = AuditRenameViewModel::class.java, title = R.string.rename_form) {
RenameForm(vo = it)
}
ImeBody {
val model: AuditRenameViewModel = viewModel()
val data by model.data.observeAsState()
TestTableImeSimple(
title = R.string.rename_form
) {
data?.forEach {
item {
RenameForm(vo = it)
CheckForm<AuditRenameVo, AuditRenameViewModel>(vo = it)
Spacer(modifier = Modifier.height(10.dp))
}
}
}
}
}
}
@Composable
private fun RenameForm(
modifier: Modifier = Modifier,
vo: AuditRenameVo
) {
Column(modifier = modifier) {
val baseHeight = 50.dp
RowItem(
modifier = Modifier.height(baseHeight),
key = R.string.petitioner,
value = vo.audit.user.name
)
RowItem(
modifier = Modifier.height(baseHeight),
key = R.string.oldname,
value = vo.associationVo.name
)
RowItem(
modifier = Modifier.height(baseHeight),
key = R.string.newname,
value = vo.renameVo.newName
)
RowItem(
modifier = Modifier.height(baseHeight * 3),
key = R.string.reason_for_application,
value = vo.renameVo.cause
)
}
}
}

@ -10,11 +10,15 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
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.R
import com.gyf.csams.main.model.ManagementOfficerModel
import com.gyf.csams.module.ManagerDutyVo
import com.gyf.lib.uikit.Body import com.gyf.lib.uikit.Body
import com.gyf.lib.uikit.MainColumnFrame import com.gyf.lib.uikit.MainColumnFrame
@ -29,6 +33,7 @@ class DepartmentActivity : ComponentActivity() {
setContent { setContent {
Body { Body {
val model: ManagementOfficerModel = viewModel()
MainColumnFrame(background = { /*TODO*/ }) { MainColumnFrame(background = { /*TODO*/ }) {
val weight = 0.1F val weight = 0.1F
val departWeight = 0.2F val departWeight = 0.2F
@ -92,19 +97,28 @@ class DepartmentActivity : ComponentActivity() {
} }
val simpleData by model.simpleData.observeAsState()
simpleData?.let {
DepartmentItem(modifier = Modifier.weight(weight = departWeight),
id = R.string.secretariat,
onClick = { dialogContent = R.string.secretariat },
managerDutyVo = it.secretariat
)
Spacer(modifier = Modifier.weight(space))
DepartmentItem(modifier = Modifier.weight(weight = departWeight),
id = R.string.propaganda_department,
onClick = { dialogContent = R.string.propaganda_department },
managerDutyVo = it.propaganda
)
Spacer(modifier = Modifier.weight(space))
DepartmentItem(modifier = Modifier.weight(weight = departWeight),
id = R.string.public_relations_department,
onClick = { dialogContent = R.string.public_relations_department },
managerDutyVo = it.publicRelationsDepartment
)
Spacer(modifier = Modifier.weight(space))
}
DepartmentItem(modifier = Modifier.weight(weight = departWeight),
id = R.string.secretariat,
onClick = { dialogContent = R.string.secretariat })
Spacer(modifier = Modifier.weight(space))
DepartmentItem(modifier = Modifier.weight(weight = departWeight),
id = R.string.propaganda_department,
onClick = { dialogContent = R.string.propaganda_department })
Spacer(modifier = Modifier.weight(space))
DepartmentItem(modifier = Modifier.weight(weight = departWeight),
id = R.string.public_relations_department,
onClick = { dialogContent = R.string.public_relations_department })
Spacer(modifier = Modifier.weight(space))
} }
} }
} }
@ -114,7 +128,8 @@ class DepartmentActivity : ComponentActivity() {
private fun DepartmentItem( private fun DepartmentItem(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@StringRes id: Int, @StringRes id: Int,
onClick: () -> Unit onClick: () -> Unit,
managerDutyVo: ManagerDutyVo
) { ) {
Row( Row(
modifier = modifier modifier = modifier
@ -141,13 +156,13 @@ class DepartmentActivity : ComponentActivity() {
.fillMaxHeight(), .fillMaxHeight(),
verticalArrangement = Arrangement.SpaceBetween verticalArrangement = Arrangement.SpaceBetween
) { ) {
RowItem(text = "部门部长:") RowItem(text = "部门部长:${managerDutyVo.manager.name}")
OutlinedButton(modifier = Modifier.fillMaxWidth(), onClick = { OutlinedButton(modifier = Modifier.fillMaxWidth(), onClick = {
startActivity(Intent(applicationContext, ManagementOfficerActivity::class.java)) startActivity(Intent(applicationContext, ManagementOfficerActivity::class.java))
}) { }) {
Text(text = stringResource(id = R.string.management_officer)) Text(text = stringResource(id = R.string.management_officer))
} }
RowItem(text = "部门总人数:") RowItem(text = "部门总人数:${managerDutyVo.people}")
} }
} }
} }

@ -59,12 +59,11 @@ class MainActivity : BaseActivity() {
Text(text = "我的通知") Text(text = "我的通知")
} }
// TODO 部门管理 OutlinedButton(onClick = {
// OutlinedButton(onClick = { startActivity(Intent(this@MainActivity, DepartmentActivity::class.java))
// startActivity(Intent(this@MainActivity, DepartmentActivity::class.java)) }, modifier = Modifier.fillMaxWidth()) {
// }, modifier = Modifier.fillMaxWidth()) { Text(text = stringResource(id = R.string.department_management))
// Text(text = stringResource(id = R.string.department_management)) }
// }
OutlinedButton(onClick = { OutlinedButton(onClick = {
startActivity( startActivity(
Intent( Intent(

@ -41,6 +41,7 @@ class ManagementOfficerActivity : ComponentActivity() {
MainColumnFrame(background = { /*TODO*/ }) { MainColumnFrame(background = { /*TODO*/ }) {
val weight = 1 / 3F val weight = 1 / 3F
val model: ManagementOfficerModel = viewModel() val model: ManagementOfficerModel = viewModel()
model.loadDetail()
val data by model.data.observeAsState() val data by model.data.observeAsState()
Logger.i("$data") Logger.i("$data")
data?.apply { data?.apply {
@ -79,7 +80,7 @@ class ManagementOfficerActivity : ComponentActivity() {
model: ManagementOfficerModel = viewModel(), model: ManagementOfficerModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel(), scaffoldModel: ScaffoldModel = viewModel(),
@StringRes id: Int, @StringRes id: Int,
officerVoList: MutableList<ManagerInfoVo>, officerVoList: List<ManagerInfoVo>,
) { ) {
Column( Column(
modifier = modifier modifier = modifier
@ -119,7 +120,7 @@ class ManagementOfficerActivity : ComponentActivity() {
expanded = expanded, expanded = expanded,
onDismissRequest = { /*TODO*/ }) { onDismissRequest = { /*TODO*/ }) {
DropdownMenuItem(onClick = { DropdownMenuItem(onClick = {
model.updateDuty(list = officerVoList, index = it.index) model.updateDuty()
expanded = false expanded = false
}) { }) {
Text(text = it.value.duty.desc) Text(text = it.value.duty.desc)

@ -1,87 +0,0 @@
package com.gyf.csams.main.ui
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ExperimentalComposeApi
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.module.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
class RenameActivity : ComponentActivity() {
@ExperimentalAnimatedInsets
@ExperimentalComposeApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TestTable(clazz = RenameViewModel::class.java, title = R.string.rename_form) {
RenameForm(renameVo = it)
}
}
}
@Composable
private fun RenameForm(
modifier: Modifier = Modifier, model: RenameViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel(), renameVo: RenameVo
) {
Column(modifier = modifier) {
val baseHeight = 50.dp
RowItem(
modifier = Modifier.height(baseHeight),
key = R.string.petitioner,
value = renameVo.studentId
)
RowItem(
modifier = Modifier.height(baseHeight),
key = R.string.oldname,
value = renameVo.oldName
)
RowItem(
modifier = Modifier.height(baseHeight),
key = R.string.newname,
value = renameVo.newName
)
RowItem(
modifier = Modifier.height(baseHeight * 3),
key = R.string.reason_for_application,
value = renameVo.reason
)
RowItem(
modifier = Modifier.height(baseHeight), key = R.string.first_approver, value = ""
/**TODO 获取审批人**/
)
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)
BottomButton(
confirmDesc = R.string.reported_btn, backDesc = R.string.reject_btn,
modifier = Modifier.fillMaxWidth()
) {
scaffoldModel.update(message = message)
}
}
}
}

@ -92,11 +92,10 @@ inline fun <reified VO : AuditVo, reified M : BaseAuditViewModel<VO>> CheckForm(
model.check( model.check(
auditId = vo.audit.id, auditId = vo.audit.id,
result = result, result = result,
cause = cause.formValue.value cause = cause.getValue()
?: throw IllegalArgumentException("无法获取审核理由")
) { ) {
scaffoldModel.update(message = it, actionLabel = "刷新") { scaffoldModel.update(message = it, actionLabel = "刷新") {
model.load { } model.load()
} }
} }
} }
@ -109,7 +108,7 @@ inline fun <reified VO : AuditVo, reified M : BaseAuditViewModel<VO>> CheckForm(
auditId = vo.audit.id auditId = vo.audit.id
) { ) {
scaffoldModel.update(message = it, actionLabel = "刷新") { scaffoldModel.update(message = it, actionLabel = "刷新") {
model.load { } model.load()
} }
} }
} }
@ -166,7 +165,7 @@ inline fun <reified VO : AuditVo, reified M : BaseAuditViewModel<VO>> CheckForm(
) )
} }
//初审记录,负责人不为空 初审受理 //初审记录,负责人不为空 初审受理
vo.audit.nextAudit == null && vo.audit.manager != null -> { vo.audit.nextAudit == null && vo.audit.manager != null && vo.audit.result == null -> {
first() first()
if (it.duty == Duty.PamphaBhusal) { if (it.duty == Duty.PamphaBhusal) {

@ -67,7 +67,7 @@
<activity android:name=".association.ui.AssociationActivity" /> <activity android:name=".association.ui.AssociationActivity" />
<!--社团重命名主界面--> <!--社团重命名主界面-->
<activity android:name=".association.ui.ReNameActivity" /> <activity android:name=".association.ui.RenameActivity" />
<!--题库界面--> <!--题库界面-->
<activity android:name=".association.ui.ExamActivity" /> <activity android:name=".association.ui.ExamActivity" />

@ -132,18 +132,16 @@ class AccountViewModel(application: Application) : AbstractLoginViewModel(applic
}, },
onFail = { Logger.e(it) }, onFail = { Logger.e(it) },
typeToken = object : TypeToken<ApiResponse<Boolean>>() {}.type typeToken = object : TypeToken<ApiResponse<Boolean>>() {}.type
), mapOf("studentId" to "${id.formValue.value}") ), mapOf("studentId" to id.getValue())
) )
} }
} }
} }
override fun loginParam(): Any { override fun loginParam(): Any {
val studentId = "${id.formValue.value}"
val password = "${password.formValue.value}"
return UserLoginVo( return UserLoginVo(
studentId = studentId, studentId = id.getValue(),
password = password, password = password.getValue(),
device = "${Build.MANUFACTURER} ${Build.MODEL}" device = "${Build.MANUFACTURER} ${Build.MODEL}"
) )
} }
@ -183,8 +181,8 @@ class AccountViewModel(application: Application) : AbstractLoginViewModel(applic
typeToken = object : TypeToken<ApiResponse<String>>() {}.type typeToken = object : TypeToken<ApiResponse<String>>() {}.type
), ),
jsonParam = UserRegVo( jsonParam = UserRegVo(
studentId = id.formValue.value ?: throw IllegalArgumentException("学号为空"), studentId = id.getValue(),
name = name.formValue.value ?: throw IllegalArgumentException("姓名为空") name = name.getValue()
) )
) )
resetForm() resetForm()

@ -218,7 +218,7 @@ class AccountActivity : ComponentActivity() {
color = MaterialTheme.colors.error color = MaterialTheme.colors.error
) )
) { ) {
append(accountViewModel.id.formValue.value ?: "") append(accountViewModel.id.getValue())
} }
append(accountViewModel.registered) append(accountViewModel.registered)
}) })

@ -112,8 +112,7 @@ class ActivityPhotoViewModel(application: Application) :
), ),
params = mapOf( params = mapOf(
"activityId" to "$activityId", "activityId" to "$activityId",
"name" to (name.formValue.value "name" to name.getValue()
?: throw IllegalArgumentException("照片名字为空"))
), ),
fileList = arrayOf(cacheFile) fileList = arrayOf(cacheFile)
) )
@ -172,8 +171,7 @@ class BBSCommentModel : AbstractComment() {
), ),
jsonParam = jsonParam =
SendBBSVo( SendBBSVo(
content = newContent.formValue.value content = newContent.getValue(),
?: throw IllegalArgumentException("评论内容为空"),
token = TokenManager.getToken(), token = TokenManager.getToken(),
activityId = activityId ?: throw IllegalArgumentException("活动id没有初始化") activityId = activityId ?: throw IllegalArgumentException("活动id没有初始化")
) )

@ -83,7 +83,7 @@ class ApplyActViewModel(application: Application) : AndroidViewModel(application
val checkInfo: LiveData<ApiResponse<ActivityCheckVo>> = _checkInfo val checkInfo: LiveData<ApiResponse<ActivityCheckVo>> = _checkInfo
init { init {
read { } read()
} }
val city = val city =
@ -587,13 +587,8 @@ class ApplyActViewModel(application: Application) : AndroidViewModel(application
* *
*/ */
fun apply(callback: (message: String) -> Unit) { fun apply(callback: (message: String) -> Unit) {
val activityName = activityName.formValue.value ?: throw IllegalArgumentException("活动名称为空")
val activityDate = activityDate.formValue.value ?: throw IllegalArgumentException("活动日期为空")
val activityTime = activityTime.formValue.value ?: throw IllegalArgumentException("活动时间为空")
val activityDesc = activityDesc.formValue.value ?: throw IllegalArgumentException("活动介绍为空")
val activitySize = activitySize.formValue.value ?: throw IllegalArgumentException("活动规模为空")
val activityAddress =
activityAddress.formValue.value ?: throw IllegalArgumentException("活动地点为空")
val associationId = (TokenManager.getOwnInfo() as? UserVo)?.associationVo?.associationId val associationId = (TokenManager.getOwnInfo() as? UserVo)?.associationVo?.associationId
?: throw IllegalArgumentException("社团id为空") ?: throw IllegalArgumentException("社团id为空")
viewModelScope.launch { viewModelScope.launch {
@ -608,12 +603,12 @@ class ApplyActViewModel(application: Application) : AndroidViewModel(application
jsonParam = ActivityApplyVo( jsonParam = ActivityApplyVo(
associationId = associationId, associationId = associationId,
activityVo = ActivityVo( activityVo = ActivityVo(
activityName = activityName, activityName = activityName.getValue(),
activityTime = "$activityDate $activityTime".toDate().time, activityTime = "${activityDate.getValue()} ${activityTime.getValue()}".toDate().time,
activityAddress = activityAddress, activityAddress = activityAddress.getValue(),
activityDesc = activityDesc, activityDesc = activityDesc.getValue(),
activitySize = activitySize.toInt(), activitySize = activitySize.getValue().toInt(),
activityId = _checkInfo.value?.body?.activityId activityId = _checkInfo.value?.body?.activityVo?.activityId
), ),
token = TokenManager.getToken() token = TokenManager.getToken()
) )
@ -627,10 +622,12 @@ class ApplyActViewModel(application: Application) : AndroidViewModel(application
* *
* @param callback * @param callback
*/ */
private fun read(callback: (message: String) -> Unit) { private fun read() {
viewModelScope.launch { viewModelScope.launch {
HttpClient.post(url = Api.buildUrl(ActivityApi.Read), HttpClient.post(
HttpCallback<ActivityCheckVo>(action = "查看活动申请书审核进度", url = Api.buildUrl(ActivityApi.Read),
HttpCallback<ActivityCheckVo>(
action = "查看活动申请书审核进度",
onSuccess = { it -> onSuccess = { it ->
_checkInfo.postValue(it) _checkInfo.postValue(it)
it.body?.activityVo?.let { it.body?.activityVo?.let {

@ -13,8 +13,11 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.runtime.* import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
@ -197,14 +200,14 @@ class ApplyActActivity : AppCompatActivity() {
) )
} }
Spacer(modifier = Modifier.weight(0.05F)) Spacer(modifier = Modifier.weight(0.05F))
val activityName = model.activityName.statusForm.observeAsState() val activityName by model.activityName.statusForm.observeAsState()
val activityDate = model.activityDate.statusForm.observeAsState() val activityDate by model.activityDate.statusForm.observeAsState()
val activityTime = model.activityTime.statusForm.observeAsState() val activityTime by model.activityTime.statusForm.observeAsState()
val activityDesc = model.activityDesc.statusForm.observeAsState() val activityDesc by model.activityDesc.statusForm.observeAsState()
val activitySize = model.activitySize.statusForm.observeAsState() val activitySize by model.activitySize.statusForm.observeAsState()
BottomButton( BottomButton(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
enabled = check( enabled = checkForm(
activityName, activityName,
activityDate, activityDate,
activityTime, activityTime,
@ -234,14 +237,6 @@ class ApplyActActivity : AppCompatActivity() {
return flag == true return flag == true
} }
private fun check(vararg arrayOfStates: State<FormStatus?>): Boolean {
arrayOfStates.forEach {
if (it.value != FormStatus.Valid) {
return false
}
}
return true
}
@Composable @Composable
private fun SelectIcon(modifier: Modifier = Modifier) { private fun SelectIcon(modifier: Modifier = Modifier) {

@ -21,6 +21,10 @@ class AssociationViewModel : ViewModel(), TopMenuInterface<AssociationMenu> {
override val _currentMenu: MutableLiveData<AssociationMenu> = MutableLiveData() override val _currentMenu: MutableLiveData<AssociationMenu> = MutableLiveData()
override val currentMenu: LiveData<AssociationMenu> = _currentMenu override val currentMenu: LiveData<AssociationMenu> = _currentMenu
private val _dropDownMenuResult = MutableLiveData<String?>()
val dropDownMenuResult: LiveData<String?> = _dropDownMenuResult
/** /**
* 下拉菜单状态 * 下拉菜单状态
*/ */
@ -30,6 +34,10 @@ class AssociationViewModel : ViewModel(), TopMenuInterface<AssociationMenu> {
private val _associationVo = MutableLiveData<AssociationMainVo>() private val _associationVo = MutableLiveData<AssociationMainVo>()
val associationVo: LiveData<AssociationMainVo> = _associationVo val associationVo: LiveData<AssociationMainVo> = _associationVo
fun update(message: String?) {
_dropDownMenuResult.postValue(message)
}
fun load(id: Int) { fun load(id: Int) {
viewModelScope.launch { viewModelScope.launch {
HttpClient.post( HttpClient.post(

@ -3,11 +3,9 @@ package com.gyf.csams.association.model
import android.app.Application import android.app.Application
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.gyf.csams.module.ChoiceQuestionVo
import com.gyf.csams.module.Exam
import com.gyf.csams.module.ExamType
import com.gyf.lib.model.ScrollViewModel import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.uikit.StringForm import com.gyf.lib.uikit.StringForm
import com.gyf.lib.uikit.ValidStringForm
import com.gyf.lib.util.NOT_IMPL_TIP import com.gyf.lib.util.NOT_IMPL_TIP
/** /**
@ -41,6 +39,61 @@ const val ANSWER_SIZE = 4
const val ANSWER_TEXT_LENGTH = 15 const val ANSWER_TEXT_LENGTH = 15
/**
* 题型
*
*/
enum class ExamType(val type: String) {
//选择题
CQ("选择题"),
//开放题
OQ("开放题")
}
abstract class Exam {
abstract val examType: ExamType
//**TODO 题目反序列化
abstract val question: String?
abstract val _question: StringForm?
}
/**
* 选择题
*
* @property examType 题型描述
* @property answers 答案
* @property rightAnswer 正确答案
* @property question 问题
* TODO 题目反序列化
*/
data class ChoiceQuestionVo(
val id: Int? = null,
override val examType: ExamType = ExamType.CQ,
val _answers: MutableList<StringForm> = mutableListOf(),
val answers: List<String> = ('A'..'D').map { "选项${it}" }.toList(),
val rightAnswer: Int,
override val question: String? = null,
override val _question: StringForm?,
) : Exam()
/**
* 开放题
*
* @property examType 题型描述
* @property question 问题
* TODO 题目反序列化
*/
data class OpenQuestionsVo(
override val examType: ExamType = ExamType.OQ,
override val question: String? = null,
override val _question: StringForm?
) : Exam()
/** /**
* 题库状态管理 * 题库状态管理
* *
@ -54,9 +107,6 @@ class ExamViewModel(application: Application) : ScrollViewModel<Exam>(applicatio
val actionLabel = "确定" val actionLabel = "确定"
override val initSize = 10
private val _newExam: MutableLiveData<Exam> = MutableLiveData(createExam(ExamType.CQ)) private val _newExam: MutableLiveData<Exam> = MutableLiveData(createExam(ExamType.CQ))
val newExam: LiveData<Exam> = _newExam val newExam: LiveData<Exam> = _newExam
@ -64,9 +114,7 @@ class ExamViewModel(application: Application) : ScrollViewModel<Exam>(applicatio
load() load()
} }
fun createQuestion(): StringForm {
return StringForm(formDesc = "问题", textLength = QUESTION_TEXT_LENGTH)
}
/** /**
* 切换题型 * 切换题型
@ -85,7 +133,18 @@ class ExamViewModel(application: Application) : ScrollViewModel<Exam>(applicatio
* @return * @return
*/ */
private fun createExam(type: ExamType): Exam { private fun createExam(type: ExamType): Exam {
TODO("创建题目")
val questionForm = ValidStringForm(formDesc = "", textLength = QUESTION_TEXT_LENGTH)
val answerA = ValidStringForm(formDesc = "选项A", textLength = ANSWER_TEXT_LENGTH)
val answerB = ValidStringForm(formDesc = "选项B", textLength = ANSWER_TEXT_LENGTH)
val answerC = ValidStringForm(formDesc = "选项C", textLength = ANSWER_TEXT_LENGTH)
val answerD = ValidStringForm(formDesc = "选项D", textLength = ANSWER_TEXT_LENGTH)
return ChoiceQuestionVo(
_answers = mutableListOf(answerA, answerB, answerC, answerD),
rightAnswer = 0,
_question = questionForm,
)
} }
@ -113,7 +172,7 @@ class ExamViewModel(application: Application) : ScrollViewModel<Exam>(applicatio
* @param callback * @param callback
*/ */
fun updateExam(callback: (message: String) -> Unit) { fun updateExam(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP)
} }
/** /**
@ -130,36 +189,10 @@ class ExamViewModel(application: Application) : ScrollViewModel<Exam>(applicatio
* *
*/ */
fun load() { fun load() {
TODO("加载题目")
}
/**
*TODO 加载更多题目
*
* @param callback
*/
fun loadMore(callback: (message: String) -> Unit) {
// _data.value?.apply {
// val list= mutableListOf<Exam>()
// list.addAll(this)
// list.apply {
// repeat(10) {
// if (Random.nextBoolean()) add(OpenQuestionsVo(question = "这是一道开放题:$size")) else add(
// ChoiceQuestionVo(
// question = "这是一道选择题:$size,请从选项中选出正确答案",
// answers = listOf("选项A", "选项B", "选项C", "选项D"),
// rightAnswer = 3
// )
// )
// }
// }
// _data.postValue(list)
// callback("成功加载更多题目")
// }
// callback(NOT_IMPL_TIP)
} }
fun addQuestion() { fun addQuestion() {
_data.value?.apply { _data.value?.apply {
_newExam.value?.let { _newExam.value?.let {

@ -158,10 +158,8 @@ class RegAssociationViewModel(application: Application) : AndroidViewModel(appli
* @param callback * @param callback
*/ */
fun register(callback: (value: String) -> Unit) { fun register(callback: (value: String) -> Unit) {
val nameValue = name.formValue.value
val descValue = desc.formValue.value
val fileId = _fileId.value val fileId = _fileId.value
if (nameValue != null && descValue != null && fileId != null && if (fileId != null &&
name.statusForm.value == FormStatus.Valid && desc.statusForm.value == FormStatus.Valid name.statusForm.value == FormStatus.Valid && desc.statusForm.value == FormStatus.Valid
) { ) {
viewModelScope.launch { viewModelScope.launch {
@ -177,8 +175,8 @@ class RegAssociationViewModel(application: Application) : AndroidViewModel(appli
Logger.e(it) Logger.e(it)
}, typeToken = object : TypeToken<ApiResponse<Boolean>>() {}.type), }, typeToken = object : TypeToken<ApiResponse<Boolean>>() {}.type),
jsonParam = AssociationRegVo( jsonParam = AssociationRegVo(
name = nameValue, name = name.getValue(),
desc = descValue, desc = desc.getValue(),
fileId = fileId, fileId = fileId,
associationId = _checkInfo.value?.body?.associationVo?.associationId, associationId = _checkInfo.value?.body?.associationVo?.associationId,
token = TokenManager.getToken() token = TokenManager.getToken()

@ -1,8 +1,14 @@
package com.gyf.csams.association.model package com.gyf.csams.association.model
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.gyf.lib.uikit.StringForm import androidx.lifecycle.viewModelScope
import com.gyf.lib.util.NOT_IMPL_TIP import com.google.gson.reflect.TypeToken
import com.gyf.csams.module.*
import com.gyf.lib.uikit.AsyncStringForm
import com.gyf.lib.util.*
import kotlinx.coroutines.launch
/** /**
* 社团重命名状态管理 * 社团重命名状态管理
@ -11,18 +17,79 @@ import com.gyf.lib.util.NOT_IMPL_TIP
class RenameViewModel : ViewModel() { class RenameViewModel : ViewModel() {
val menuName = "换名申请表" val menuName = "换名申请表"
val oldName = StringForm(formDesc = "社团原名", textLength = 10) val oldName = AsyncStringForm(formDesc = "社团原名", textLength = 10)
val newName = StringForm(formDesc = "社团新名", textLength = 10)
val cause = StringForm(formDesc = "换名原因", textLength = 30)
val postDesc = "提交申请" val newName = AsyncStringForm(formDesc = "社团新名", textLength = 10)
val back = "返回"
val cause = AsyncStringForm(formDesc = "换名原因", textLength = 30)
private val _actionResult = MutableLiveData<String>()
val actionResult: LiveData<String> = _actionResult
private fun clean() {
newName.clean()
cause.clean()
}
private val _checkInfo = MutableLiveData<ApiResponse<RenameCheckVo>>()
val checkInfo: LiveData<ApiResponse<RenameCheckVo>> = _checkInfo
init {
read()
}
/**
* 提交重命名申请
*
*/
fun apply(associationId: Int) {
viewModelScope.launch {
HttpClient.post(
url = Api.buildUrl(AssociationApi.RenameRegister),
callback = HttpCallback<Boolean>(action = "提交换名申请表", onSuccess = {
it.body?.let {
if (it) {
clean()
}
}
_actionResult.postValue(it.message)
}, typeToken = object : TypeToken<ApiResponse<Boolean>>() {}.type),
jsonParam = RenameApplyVo(
rename = RenameVo(
newName = newName.getValue(),
cause = cause.getValue(),
renameId = _checkInfo.value?.body?.renameVo?.renameId
),
associationId = associationId,
token = TokenManager.getToken()
)
)
}
}
/** /**
* TODO 提交表单 * 查看审核进度
* *
* @param callback
*/ */
fun post(callback: (message: String) -> Unit) { private fun read() {
callback(NOT_IMPL_TIP) viewModelScope.launch {
HttpClient.post(url = Api.buildUrl(AssociationApi.RenameRead),
callback = HttpCallback<RenameCheckVo>(action = "查看审核进度",
onSuccess = { it ->
_checkInfo.postValue(it)
it.body?.renameVo?.let {
newName.setValue(it.newName)
cause.setValue(it.cause)
}
}, typeToken = object : TypeToken<ApiResponse<RenameCheckVo>>() {}.type
),
jsonParam = OnlyToken(clientType = ClientType.Foreground)
)
}
} }
} }

@ -3,7 +3,9 @@ package com.gyf.csams.association.ui
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@ -11,9 +13,7 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.*
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -34,6 +34,8 @@ import com.gyf.csams.module.ActivityVo
import com.gyf.csams.uikit.* import com.gyf.csams.uikit.*
import com.gyf.lib.uikit.* import com.gyf.lib.uikit.*
import com.gyf.lib.util.TokenManager import com.gyf.lib.util.TokenManager
import com.orhanobut.logger.Logger
import kotlinx.coroutines.delay
/** /**
@ -45,7 +47,7 @@ class AssociationActivity : ComponentActivity() {
private val associationId: Int private val associationId: Int
get() { get() {
val id = intent.getIntExtra( val id = intent.getIntExtra(
AssociationActivity::javaClass.name, AssociationActivity::class.java.name,
0 0
) )
return if (id == 0) throw IllegalArgumentException("社团id:${id}不合法,初始化失败") else id return if (id == 0) throw IllegalArgumentException("社团id:${id}不合法,初始化失败") else id
@ -63,12 +65,26 @@ class AssociationActivity : ComponentActivity() {
val intent = Intent(this, ExamActivity::class.java) val intent = Intent(this, ExamActivity::class.java)
val expanded by model.expanded.observeAsState(false) val expanded by model.expanded.observeAsState(false)
var message: String? by remember {
mutableStateOf(null)
}
//TODO重命名操作反馈
val rename =
rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
val m = it.data?.getStringExtra(RenameActivity::class.java.name)
Logger.i("社团重命名返回:${m}")
message = m
}
}
Column { Column {
TextTopAppBar(nav = nav, TextTopAppBar(nav = nav,
currentMenuName = currentMenuName.menuName, currentMenuName = currentMenuName.menuName,
menuNames = AssociationMenu.values(), menuNames = AssociationMenu.values(),
iconMenu = { model.switchType() }) { iconMenu = { model.switchType() }) {
Row { Row {
DropdownMenu( DropdownMenu(
expanded = expanded, expanded = expanded,
onDismissRequest = { }, onDismissRequest = { },
@ -85,7 +101,7 @@ class AssociationActivity : ComponentActivity() {
ApplyActActivity::class.java ApplyActActivity::class.java
).apply { ).apply {
putExtra( putExtra(
AssociationActivity::javaClass.name, AssociationActivity::class.java.name,
associationId associationId
) )
} }
@ -120,12 +136,15 @@ class AssociationActivity : ComponentActivity() {
} }
} }
DropdownMenuItem(onClick = { DropdownMenuItem(onClick = {
startActivity( rename.launch(Intent(
Intent( this@AssociationActivity,
this@AssociationActivity, RenameActivity::class.java
ReNameActivity::class.java ).apply {
putExtra(
AssociationActivity::class.java.name,
associationId
) )
) })
model.close() model.close()
}) { }) {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
@ -136,6 +155,7 @@ class AssociationActivity : ComponentActivity() {
) )
} }
} }
} }
TokenManager.getUserInfo()?.associationVo == null -> DropdownMenuItem( TokenManager.getUserInfo()?.associationVo == null -> DropdownMenuItem(
onClick = { onClick = {
@ -187,6 +207,22 @@ class AssociationActivity : ComponentActivity() {
composable(AssociationMenu.Main.name) { composable(AssociationMenu.Main.name) {
model.clickMenu(AssociationMenu.Main) model.clickMenu(AssociationMenu.Main)
Main() Main()
//TODO 提示
val scaffoldModel: ScaffoldModel = viewModel()
message?.let {
scaffoldModel.update(message = message, actionLabel = "刷新")
val s by scaffoldModel.data.observeAsState()
if (s == null) {
message = null
// nav.navigate(AssociationMenu.Main.name)
}
LaunchedEffect(message) {
delay(it.length * 300L)
message = null
// nav.navigate(AssociationMenu.Main.name)
}
}
ShowSnackbar(scaffoldState = scaffoldState) ShowSnackbar(scaffoldState = scaffoldState)
} }
composable(AssociationMenu.ActivityList.name) { composable(AssociationMenu.ActivityList.name) {
@ -202,6 +238,18 @@ class AssociationActivity : ComponentActivity() {
} }
} }
//TODO下拉菜单操作反馈
@Composable
private fun ShowTip(
model: AssociationViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel()
) {
val m by model.dropDownMenuResult.observeAsState()
m?.let {
Logger.i("收到${it}")
scaffoldModel.update(message = it, actionLabel = "关闭提示")
}
}
/** /**
* 社团成员 * 社团成员
@ -466,9 +514,7 @@ class AssociationActivity : ComponentActivity() {
private fun OngoingActivity( private fun OngoingActivity(
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
Row(modifier = modifier.clickable(onClick = { Row(horizontalArrangement = Arrangement.Center) {
startActivity(Intent(this, ActivityDetailActivity::class.java))
}), horizontalArrangement = Arrangement.Center) {
val weight = 0.5F val weight = 0.5F
val spaceWeight = (1 - 0.5F) / 2 val spaceWeight = (1 - 0.5F) / 2
Spacer(modifier = Modifier.weight(spaceWeight)) Spacer(modifier = Modifier.weight(spaceWeight))

@ -18,12 +18,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.gyf.csams.R import com.gyf.csams.R
import com.gyf.csams.association.model.ANSWER_SIZE import com.gyf.csams.association.model.*
import com.gyf.csams.association.model.ExamActivityType
import com.gyf.csams.association.model.ExamViewModel
import com.gyf.csams.module.ChoiceQuestionVo
import com.gyf.csams.module.Exam
import com.gyf.csams.module.OpenQuestionsVo
import com.gyf.csams.uikit.Background import com.gyf.csams.uikit.Background
import com.gyf.csams.uikit.BackgroundImage import com.gyf.csams.uikit.BackgroundImage
import com.gyf.lib.uikit.BaseTextField import com.gyf.lib.uikit.BaseTextField
@ -119,9 +114,9 @@ class ExamActivity : ComponentActivity() {
newExam?.let { newExam?.let {
item { item {
Column { Column {
OutlinedButton(onClick = { model.switchType(it) }) { // OutlinedButton(onClick = { model.switchType(it) }) {
Text(text = "切换到${if (newExam is ChoiceQuestionVo) "开放题" else "选择题"}") // Text(text = "切换到${if (newExam is ChoiceQuestionVo) "开放题" else "选择题"}")
} // }
ExamChild(it = it, examHeight = examHeight, isAdd = true) ExamChild(it = it, examHeight = examHeight, isAdd = true)
} }
} }
@ -159,9 +154,9 @@ class ExamActivity : ComponentActivity() {
} }
if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) { // if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) {
model.loadMore { scaffoldModel.update(message = it) } // model.loadMore { scaffoldModel.update(message = it) }
} // }
} }
@ -175,17 +170,16 @@ class ExamActivity : ComponentActivity() {
@Composable @Composable
private fun Question( private fun Question(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
exam: Exam, exam: Exam
model: ExamViewModel = viewModel()
) { ) {
/*问题**/ exam._question?.let {
val s = model.createQuestion() BaseTextField(
BaseTextField( form = it,
form = s, modifier = modifier
modifier = modifier .fillMaxSize()
.fillMaxSize() .background(color = MaterialTheme.colors.background)
.background(color = MaterialTheme.colors.background) )
) }
} }
@ -201,43 +195,46 @@ class ExamActivity : ComponentActivity() {
exam: Exam exam: Exam
) { ) {
val list by model.data.observeAsState() val list by model.data.observeAsState()
val newExam by model.newExam.observeAsState() model.newExam.value?._question?.let {
Box( val value by it.formValue.observeAsState()
contentAlignment = Alignment.Center, Box(
modifier = modifier contentAlignment = Alignment.Center,
) { modifier = modifier
IconButton(onClick = { ) {
if (isAdd) { IconButton(onClick = {
if ((newExam?.question ?: "").isNotEmpty()) { if (isAdd) {
scaffoldModel.update( if ((value?.isNotEmpty() == true)) {
message = model.addTip, scaffoldModel.update(
actionLabel = model.actionLabel message = model.addTip,
) { actionLabel = model.actionLabel
model.addQuestion() ) {
model.addQuestion()
}
} else {
scaffoldModel.update(message = model.questionIsNull)
} }
} else {
scaffoldModel.update(message = model.questionIsNull)
}
} else {
if (list?.size == 1) {
scaffoldModel.update(model.deleteLeastOne)
} else { } else {
scaffoldModel.update( if (list?.size == 1) {
message = model.deleteTip, scaffoldModel.update(model.deleteLeastOne)
actionLabel = model.actionLabel } else {
) { scaffoldModel.update(
model.deleteQuestion(exam = exam) message = model.deleteTip,
actionLabel = model.actionLabel
) {
model.deleteQuestion(exam = exam)
}
} }
} }
}) {
Icon(
painter = painterResource(id = if (isAdd) R.drawable.ic_add_select else R.drawable.ic_sami_select),
contentDescription = null
)
} }
}) {
Icon(
painter = painterResource(id = if (isAdd) R.drawable.ic_add_select else R.drawable.ic_sami_select),
contentDescription = null
)
} }
} }
} }
@ -309,7 +306,7 @@ class ExamActivity : ComponentActivity() {
.weight(1 - questionWeight) .weight(1 - questionWeight)
) { ) {
choiceQuestionVo.answers.apply { choiceQuestionVo._answers.apply {
Column { Column {
forEach { forEach {
Row( Row(
@ -327,8 +324,8 @@ class ExamActivity : ComponentActivity() {
val isRightAnswer = val isRightAnswer =
choiceQuestionVo.rightAnswer == answerIndex choiceQuestionVo.rightAnswer == answerIndex
RadioButton(selected = isRightAnswer, onClick = click) RadioButton(selected = isRightAnswer, onClick = click)
val c = model.createQuestion() BaseTextField(form = it)
BaseTextField(form = c)
} }
} }
} }

@ -1,99 +0,0 @@
package com.gyf.csams.association.ui
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.gyf.csams.association.model.RenameViewModel
import com.gyf.csams.uikit.Background
import com.gyf.csams.uikit.BackgroundImage
import com.gyf.lib.uikit.BaseTextField
import com.gyf.lib.uikit.Body
import com.gyf.lib.uikit.MainColumnFrame
import com.gyf.lib.uikit.ScaffoldModel
import com.gyf.lib.util.BottomButton
/**
* 社团重命名
*
*/
class ReNameActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Body {
MainColumnFrame(background = { Background(image = BackgroundImage.Rename) }) {
Spacer(
modifier = Modifier
.weight(0.2F)
)
Title(modifier = Modifier.weight(0.1F))
OldName(modifier = Modifier.weight(0.1F))
NewName(modifier = Modifier.weight(0.1F))
Cause(modifier = Modifier.weight(0.2F))
Spacer(modifier = Modifier.height(10.dp))
val model: RenameViewModel = viewModel()
val scaffoldModel: ScaffoldModel = viewModel()
BottomButton(
modifier = Modifier
.weight(0.1F)
.fillMaxWidth()
) {
model.post { scaffoldModel.update(message = it) }
}
Spacer(modifier = Modifier.weight(1 - 0.2F * 2 - 0.1F * 4))
}
}
}
}
/**
* 标题
*
*/
@Composable
private fun Title(modifier: Modifier = Modifier, model: RenameViewModel = viewModel()) {
Row(modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
Text(text = model.menuName, style = MaterialTheme.typography.h4)
}
}
/**
* 社团原名
*
*/
@Composable
private fun OldName(modifier: Modifier = Modifier, model: RenameViewModel = viewModel()) {
BaseTextField(form = model.oldName, modifier = modifier.fillMaxWidth(), singeLine = true)
}
/**
* 社团新名
*
*/
@Composable
private fun NewName(modifier: Modifier = Modifier, model: RenameViewModel = viewModel()) {
BaseTextField(form = model.newName, modifier = modifier.fillMaxWidth(), singeLine = true)
}
/**
* 换名原因
*
*/
@Composable
private fun Cause(modifier: Modifier = Modifier, model: RenameViewModel = viewModel()) {
BaseTextField(form = model.cause, modifier = modifier.fillMaxWidth())
}
}

@ -0,0 +1,195 @@
package com.gyf.csams.association.ui
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
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.association.model.AssociationViewModel
import com.gyf.csams.association.model.RenameViewModel
import com.gyf.csams.module.CheckStatus
import com.gyf.csams.uikit.Background
import com.gyf.csams.uikit.BackgroundImage
import com.gyf.csams.uikit.CheckTip
import com.gyf.lib.uikit.BaseTextField
import com.gyf.lib.uikit.Body
import com.gyf.lib.uikit.MainColumnFrame
import com.gyf.lib.uikit.checkForm
import com.gyf.lib.util.BottomButton
import com.orhanobut.logger.Logger
/**
* 社团重命名
*
*/
class RenameActivity : ComponentActivity() {
private val associationId: Int
get() {
val id = intent.getIntExtra(
AssociationActivity::class.java.name,
0
)
return if (id == 0) throw IllegalArgumentException("社团id:${id}不合法,初始化失败") else id
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Body {
MainColumnFrame(background = { Background(image = BackgroundImage.Rename) }) {
val model: RenameViewModel = viewModel()
val checkInfo by model.checkInfo.observeAsState()
checkInfo?.body?.auditCheckVo.let {
if (it == null) {
Title(modifier = Modifier.weight(0.2F))
} else {
Title()
CheckTip(it = it, modifier = Modifier.weight(0.15F))
}
}
OldName(modifier = Modifier.weight(0.1F))
NewName(modifier = Modifier.weight(0.1F))
Cause(modifier = Modifier.weight(0.2F))
Spacer(modifier = Modifier.height(10.dp))
val oldNameStatus by model.oldName.statusForm.observeAsState()
val newNameStatus by model.newName.statusForm.observeAsState()
val cause by model.cause.statusForm.observeAsState()
val hasError = repeatError()
BottomButton(
modifier = Modifier
.weight(0.1F)
.fillMaxWidth(),
enabled = checkForm(newNameStatus, cause) && !hasError
) {
model.apply(associationId = associationId)
}
val actionResult by model.actionResult.observeAsState()
actionResult?.let {
if (it.isNotEmpty()) {
setResult(
RESULT_OK,
Intent().apply {
putExtra(
RenameActivity::class.java.name,
actionResult
)
})
finish()
} else {
Logger.w("申请已提交,但是没有收到返回")
}
}
Spacer(modifier = Modifier.weight(1 - 0.2F * 2 - 0.1F * 4))
}
}
}
}
//TODO 合并ValidStringForm
@Composable
private fun repeatError(model: RenameViewModel = viewModel()): Boolean {
val oldName by model.oldName.formValue.observeAsState()
val newName by model.newName.formValue.observeAsState()
return oldName?.isNotEmpty() == true && newName?.isNotEmpty() == true && oldName == newName
}
@Composable
private fun isReadOnly(model: RenameViewModel): Boolean {
val checkInfo by model.checkInfo.observeAsState()
val flag = (checkInfo?.body?.let { it.auditCheckVo.checkStatus != CheckStatus.Finish })
Logger.d("flag=${flag}")
return flag == true
}
/**
* 标题
*
*/
@Composable
private fun Title(modifier: Modifier = Modifier, model: RenameViewModel = viewModel()) {
Row(modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
Text(text = model.menuName, style = MaterialTheme.typography.h6)
}
}
/**
* 社团原名
*
*/
@Composable
private fun OldName(
modifier: Modifier = Modifier,
model: RenameViewModel = viewModel(),
ass: AssociationViewModel = viewModel()
) {
LaunchedEffect(associationId) {
ass.load(id = associationId)
}
val associationVo by ass.associationVo.observeAsState()
associationVo?.let {
model.oldName.setValue(it.associationVo.name)
}
BaseTextField(
form = model.oldName, modifier = modifier.fillMaxWidth(), singeLine = true,
readOnly = true, isError = repeatError()
)
if (repeatError()) {
Text(text = "社团原名和社团新名不能重复", color = MaterialTheme.colors.error)
}
}
/**
* 社团新名
*
*/
@Composable
private fun NewName(modifier: Modifier = Modifier, model: RenameViewModel = viewModel()) {
BaseTextField(
form = model.newName, modifier = modifier.fillMaxWidth(), singeLine = true,
readOnly = isReadOnly(model = model), isError = repeatError()
)
if (repeatError()) {
Text(text = "社团原名和社团新名不能重复", color = MaterialTheme.colors.error)
}
}
/**
* 换名原因
*
*/
@Composable
private fun Cause(modifier: Modifier = Modifier, model: RenameViewModel = viewModel()) {
BaseTextField(
form = model.cause, modifier = modifier.fillMaxWidth(),
readOnly = isReadOnly(model = model)
)
}
}

@ -96,7 +96,7 @@ class MarqueeViewModel : AbstractComment() {
}, typeToken = object : TypeToken<ApiResponse<Boolean>>() {}.type }, typeToken = object : TypeToken<ApiResponse<Boolean>>() {}.type
), ),
jsonParam = LeaveMessageVo( jsonParam = LeaveMessageVo(
message = newContent.formValue.value ?: "", message = newContent.getValue(),
token = TokenManager.getToken() token = TokenManager.getToken()
) )
) )

@ -26,6 +26,11 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import com.google.accompanist.coil.rememberCoilPainter import com.google.accompanist.coil.rememberCoilPainter
import com.google.accompanist.imageloading.ImageLoadState
import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.PagerState
import com.google.accompanist.pager.rememberPagerState
import com.gyf.csams.R import com.gyf.csams.R
import com.gyf.csams.account.model.AccountViewModel import com.gyf.csams.account.model.AccountViewModel
import com.gyf.csams.account.model.RefreshViewModel import com.gyf.csams.account.model.RefreshViewModel
@ -34,14 +39,12 @@ import com.gyf.csams.association.ui.AssociationActivity
import com.gyf.csams.association.ui.RegAssociationActivity import com.gyf.csams.association.ui.RegAssociationActivity
import com.gyf.csams.main.model.* import com.gyf.csams.main.model.*
import com.gyf.csams.message.ui.SysMessageActivity import com.gyf.csams.message.ui.SysMessageActivity
import com.gyf.csams.module.AssociationVo import com.gyf.csams.module.*
import com.gyf.csams.module.CheckStatus
import com.gyf.csams.module.ClientType
import com.gyf.csams.module.UserVo
import com.gyf.csams.uikit.* import com.gyf.csams.uikit.*
import com.gyf.lib.service.BaseActivity import com.gyf.lib.service.BaseActivity
import com.gyf.lib.uikit.* import com.gyf.lib.uikit.*
import com.gyf.lib.util.* import com.gyf.lib.util.*
import com.orhanobut.logger.Logger
/** /**
@ -52,23 +55,20 @@ class MainActivity : BaseActivity() {
override val clientType: ClientType = ClientType.Foreground override val clientType: ClientType = ClientType.Foreground
@ExperimentalPagerApi
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
val imageViewModel: ImageViewModel = viewModel()
NavBody { nav, scaffoldState -> NavBody { nav, scaffoldState ->
NavHost(navController = nav, startDestination = MainMenu.Main.name) { NavHost(navController = nav, startDestination = MainMenu.Main.name) {
composable(MainMenu.Main.name) { composable(MainMenu.Main.name) {
Main(navController = nav) Main(navController = nav)
ShowSnackbar(scaffoldState = scaffoldState) ShowSnackbar(scaffoldState = scaffoldState)
imageViewModel.start()
} }
composable(MainMenu.List.name) { composable(MainMenu.List.name) {
AssociationList(navController = nav) AssociationList(navController = nav)
ShowSnackbar(scaffoldState = scaffoldState) ShowSnackbar(scaffoldState = scaffoldState)
imageViewModel.cancel()
} }
composable(MainMenu.Center.name) { composable(MainMenu.Center.name) {
val refresh: RefreshViewModel = viewModel() val refresh: RefreshViewModel = viewModel()
@ -78,7 +78,6 @@ class MainActivity : BaseActivity() {
Center(navController = nav) Center(navController = nav)
ShowSnackbar(scaffoldState = scaffoldState) ShowSnackbar(scaffoldState = scaffoldState)
} }
imageViewModel.cancel()
} }
} }
@ -124,7 +123,7 @@ class MainActivity : BaseActivity() {
this@MainActivity, this@MainActivity,
AssociationActivity::class.java AssociationActivity::class.java
).apply { ).apply {
putExtra(AssociationActivity::javaClass.name, it) putExtra(AssociationActivity::class.java.name, it)
}) })
} }
// CenterMenuItem(text = model.myJoinActivity) // CenterMenuItem(text = model.myJoinActivity)
@ -171,6 +170,7 @@ class MainActivity : BaseActivity() {
/** /**
* 主界面 * 主界面
*/ */
@ExperimentalPagerApi
@Composable @Composable
private fun Main(navController: NavHostController) { private fun Main(navController: NavHostController) {
MainColumnFrame( MainColumnFrame(
@ -178,21 +178,27 @@ class MainActivity : BaseActivity() {
mainMenu = MainMenu.Main, mainMenu = MainMenu.Main,
nav = navController nav = navController
) { ) {
Column(modifier = Modifier.weight(0.33F)) { val viewModel: ImageViewModel = viewModel()
Notification() val imageList by viewModel.imageList.observeAsState()
Column( imageList?.let {
modifier = Modifier val pagerState = rememberPagerState(pageCount = it.size)
.fillMaxSize() Column(modifier = Modifier.weight(0.33F)) {
.padding(horizontal = 15.dp), Notification()
verticalArrangement = Arrangement.SpaceEvenly Column(
) { modifier = Modifier
MessageBoard() .fillMaxSize()
ClubActivitiesTitle() .padding(horizontal = 15.dp),
verticalArrangement = Arrangement.SpaceEvenly
) {
MessageBoard()
ClubActivitiesTitle(vo = it[pagerState.currentPage])
}
}
Column(modifier = Modifier.weight(0.66F)) {
PosterWithDesc(pagerState = pagerState, imgList = it)
} }
} }
Column(modifier = Modifier.weight(0.66F)) {
PosterWithDesc()
}
} }
} }
@ -235,9 +241,6 @@ class MainActivity : BaseActivity() {
RESULT_OK -> { RESULT_OK -> {
it.data?.getStringExtra(RegAssociationActivity::class.java.name)?.let { it.data?.getStringExtra(RegAssociationActivity::class.java.name)?.let {
if (it == CheckStatus.Finish.name) { if (it == CheckStatus.Finish.name) {
// model.load {
// scaffoldModel.update(message = "社团审核通过",actionLabel = "关闭提示")
// }
navController.navigate(MainMenu.List.name) navController.navigate(MainMenu.List.name)
} }
} }
@ -318,7 +321,7 @@ class MainActivity : BaseActivity() {
private fun Association(associationVo: AssociationVo) { private fun Association(associationVo: AssociationVo) {
Card(modifier = Modifier.clickable(onClick = { Card(modifier = Modifier.clickable(onClick = {
val intent = Intent(this, AssociationActivity::class.java) val intent = Intent(this, AssociationActivity::class.java)
intent.putExtra(AssociationActivity::javaClass.name, associationVo.associationId) intent.putExtra(AssociationActivity::class.java.name, associationVo.associationId)
startActivity(intent) startActivity(intent)
})) { })) {
val backgroundImage = rememberCoilPainter(request = R.drawable.association_list_border) val backgroundImage = rememberCoilPainter(request = R.drawable.association_list_border)
@ -459,8 +462,9 @@ class MainActivity : BaseActivity() {
* 活动标题 * 活动标题
* *
*/ */
@ExperimentalPagerApi
@Composable @Composable
private fun ClubActivitiesTitle(modifier: Modifier = Modifier) { private fun ClubActivitiesTitle(modifier: Modifier = Modifier, vo: MainActivityPhotoVo) {
Card(modifier = modifier, backgroundColor = MaterialTheme.colors.background) { Card(modifier = modifier, backgroundColor = MaterialTheme.colors.background) {
Row( Row(
modifier = Modifier modifier = Modifier
@ -469,7 +473,7 @@ class MainActivity : BaseActivity() {
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Text( Text(
text = "超级课程表X滴滴出行-了不起的社团", text = vo.activityVo.activityName,
style = MaterialTheme.typography.h6, style = MaterialTheme.typography.h6,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
maxLines = 1 maxLines = 1
@ -483,35 +487,72 @@ class MainActivity : BaseActivity() {
* 带介绍活动海报 * 带介绍活动海报
* *
*/ */
@ExperimentalPagerApi
@Composable @Composable
private fun PosterWithDesc( private fun PosterWithDesc(
scaffoldModel: ScaffoldModel = viewModel(), pagerState: PagerState,
viewModel: ImageViewModel = viewModel() imgList: List<MainActivityPhotoVo>
) { ) {
imgList.let {
HorizontalPager(state = pagerState) { page ->
// Our page content
Logger.i("page=${page}")
Column {
val photo = rememberCoilPainter(request = Api.buildUrl(it[page].url))
Poster(
modifier = Modifier
.weight(0.6F)
.fillMaxWidth()
) {
when (photo.loadState) {
is ImageLoadState.Loading -> {
// Display a circular progress indicator whilst loading
CircularProgressIndicator()
}
is ImageLoadState.Error -> {
// If you wish to display some content if the request fails
Logger.e("轮播图加载失败")
}
else ->
it[page].apply {
Image(
painter = photo,
contentDescription = activityVo.activityName,
modifier = Modifier.clickable(onClick = {
startActivity(
Intent(
this@MainActivity,
ActivityDetailActivity::class.java
).apply {
putExtra(
ActivityDetailActivity::class.java.name,
activityVo.activityId
)
putExtra(
AssociationActivity::class.java.name,
associationVo.associationId
)
})
})
)
}
val error by viewModel.error.observeAsState() }
error?.let { }
scaffoldModel.update(message = it) DescCard(
viewModel.clearError() modifier = Modifier
} .weight(0.4F)
Carousel(imageBitmap = viewModel.image) { .fillMaxWidth(),
Column(modifier = Modifier.clickable(onClick = { content = it[page].activityVo.activityDesc
startActivity(Intent(this, ActivityDetailActivity::class.java)) )
})) { }
Poster(
modifier = Modifier
.weight(0.6F)
.fillMaxWidth()
)
DescCard(
modifier = Modifier
.weight(0.4F)
.fillMaxWidth(),
content = randomChinese(500)
)
} }
} }
} }
} }

@ -462,6 +462,25 @@ fun Background(image: BackgroundImage, alpha: Float = DefaultAlpha) {
} }
@Composable
fun Poster(modifier: Modifier = Modifier, image: @Composable () -> Unit) {
Card(
modifier = modifier,
backgroundColor = Color.Transparent
) {
Box(contentAlignment = Alignment.Center) {
Image(
painter = painterResource(id = R.drawable.hot_activity_background),
contentDescription = null,
modifier = Modifier.fillMaxSize()
)
Box(modifier = Modifier.padding(vertical = 10.dp)) {
image()
}
}
}
}
/** /**
* 活动海报 * 活动海报
* *

@ -1,100 +1,48 @@
package com.gyf.csams.uikit package com.gyf.csams.uikit
import android.app.Application import android.app.Application
import androidx.compose.ui.graphics.ImageBitmap
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.gyf.csams.R
import com.gyf.csams.module.ApiResponse import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.ClientType
import com.gyf.csams.module.MainActivityPhotoVo
import com.gyf.lib.util.* import com.gyf.lib.util.*
import com.orhanobut.logger.Logger
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class ImageViewModel(application: Application) : AndroidViewModel(application) { class ImageViewModel(application: Application) : AndroidViewModel(application) {
private val _image = MutableLiveData<ImageBitmap>()
private val _imageUrls = MutableLiveData<List<String>?>()
val image: LiveData<ImageBitmap> = _image
private var job: Job? = null
private val _error = MutableLiveData<String?>()
val error: LiveData<String?> = _error
private val urlPath = Api.buildUrl(MainApi.HotActivity)
fun clearError() {
_error.value = null
}
/** private val _imageList = MutableLiveData<List<MainActivityPhotoVo>>()
* 加载默认图片 val imageList: LiveData<List<MainActivityPhotoVo>> = _imageList
*
*/ init {
private fun defaultLoad() { load()
viewModelScope.launch {
_image.postValue(
ImageUtil.getImage(
getApplication(),
R.drawable.ic_launcher_foreground
)
)
}
} }
/** /**
* 循环加载网络图片 * 循环加载网络图片
* *
*/ */
fun start() { fun load() {
Logger.i("启动轮播") viewModelScope.launch {
if (job == null || job?.isCompleted == true || job?.isCancelled == true) { HttpClient.post(
job = viewModelScope.launch { url = Api.buildUrl(MainApi.HotActivity),
callback = HttpCallback<List<MainActivityPhotoVo>>(action = "加载活动轮播图",
HttpClient.get( onSuccess = {
url = urlPath, it.body?.let {
HttpCallback<List<String>>("获取轮播图", onSuccess = { _imageList.postValue(it)
_imageUrls.postValue(it.body)
var index = 0
_imageUrls.value?.apply {
viewModelScope.launch {
do {
val imageBitmap =
ImageUtil.getImage(
context = getApplication(),
data = get(index)
)
Logger.e("成功从image url:${get(index)}解析图片")
imageBitmap?.apply {
_image.postValue(this)
}
delay(5000)
index = if (index == size - 1) 0 else index.plus(1)
} while (job?.isActive == true)
}
} }
}, onFail = { },
Logger.e("无法从接口地址:${urlPath}获取图片url列表") typeToken = object : TypeToken<ApiResponse<List<MainActivityPhotoVo>>>() {}.type
_error.postValue(it) ),
defaultLoad() jsonParam = OnlyToken(clientType = ClientType.Foreground)
}, typeToken = object : TypeToken<ApiResponse<List<String>>>() {}.type) )
)
}.apply {
start()
}
} }
} }
fun cancel() {
Logger.i("停止轮播")
job?.cancel()
}
override fun onCleared() {
super.onCleared()
cancel()
}
} }

@ -2,12 +2,8 @@ package com.gyf.csams.util
import com.google.gson.* import com.google.gson.*
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.gyf.csams.association.model.ANSWER_SIZE import com.gyf.csams.association.model.*
import com.gyf.csams.association.model.QUESTION_TEXT_LENGTH
import com.gyf.csams.module.ChoiceQuestionVo
import com.gyf.csams.module.Exam
import com.gyf.csams.module.ExamType
import com.gyf.csams.module.OpenQuestionsVo
import com.gyf.lib.uikit.StringForm import com.gyf.lib.uikit.StringForm
import java.lang.reflect.Type import java.lang.reflect.Type

@ -2,8 +2,8 @@ package com.gyf.csams.util
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import com.gyf.csams.association.model.Exam
import com.gyf.csams.module.ApiResponse import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.Exam
import com.gyf.lib.util.HttpCallback import com.gyf.lib.util.HttpCallback
import java.lang.reflect.Type import java.lang.reflect.Type

@ -50,7 +50,7 @@ class ExampleUnitTest {
@Test @Test
fun testLib() { fun testLib() {
println(mutableListOf(('A'..'D').map { "选项${it}" }))
} }
} }

@ -63,6 +63,7 @@ dependencies {
api("com.google.accompanist:accompanist-insets:$accompanist_version") api("com.google.accompanist:accompanist-insets:$accompanist_version")
api("com.google.accompanist:accompanist-systemuicontroller:$accompanist_version") api("com.google.accompanist:accompanist-systemuicontroller:$accompanist_version")
api("com.google.accompanist:accompanist-coil:$accompanist_version") api("com.google.accompanist:accompanist-coil:$accompanist_version")
api("com.google.accompanist:accompanist-pager:$accompanist_version")
/** /**
* 针对最新的平台功能和 API 调整应用,同时还支持旧设备。 * 针对最新的平台功能和 API 调整应用,同时还支持旧设备。
* https://developer.android.com/jetpack/androidx/releases/core * https://developer.android.com/jetpack/androidx/releases/core

@ -18,6 +18,15 @@ import androidx.lifecycle.MutableLiveData
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
fun checkForm(vararg arrayOfStates: FormStatus?): Boolean {
arrayOfStates.forEach {
if (it != FormStatus.Valid) {
return false
}
}
return true
}
enum class FormStatus { enum class FormStatus {
//空 //空
Empty, Empty,
@ -25,7 +34,7 @@ enum class FormStatus {
//格式不匹配 //格式不匹配
FormatError, FormatError,
//学号已存在 //重复
Repeat, Repeat,
//校验通过 //校验通过
@ -66,6 +75,10 @@ open class StringForm(formDesc: String, val textLength: Int) :
Logger.i("${formDesc}更新值:${_formValue.value}") Logger.i("${formDesc}更新值:${_formValue.value}")
} }
fun getValue(): String {
return _formValue.value ?: throw IllegalArgumentException("获取${formDesc}失败,值为空!")
}
fun clean() { fun clean() {
_formValue.postValue("") _formValue.postValue("")
} }

@ -44,8 +44,13 @@ enum class AccountApi(val path: String) : UrlPath {
Logout("/logout"), Logout("/logout"),
//刷新用户信息 //刷新用户信息
Refresh("/refresh"); Refresh("/refresh"),
//加载部门干事概况
Load("/load/manager"),
//加载部门详情
LoadDetail("${Load.path}/detail");
override fun build(): String { override fun build(): String {
return "/api/account${this.path}" return "/api/account${this.path}"
@ -90,6 +95,11 @@ enum class AssociationApi(val path: String) : UrlPath {
//模糊查询社团 //模糊查询社团
List("/list"), List("/list"),
//后台社团管理
ListAll("${List.path}/all"),
Update("/update"),
//审核注册资料 //审核注册资料
Check("/check"), Check("/check"),
@ -103,8 +113,25 @@ enum class AssociationApi(val path: String) : UrlPath {
Load("/load"), Load("/load"),
//加载社团成员 //加载社团成员
LoadMember("${Load.path}/members"); LoadMember("${Load.path}/members"),
//社团重命名
Rename("/rename"),
//提交换名申请表
RenameRegister("${Rename.path}${Register.path}"),
//换名申请表受理
RenameAccept("${Rename.path}${Accept.path}"),
//换名申请表审核
RenameCheck("${Rename.path}${Check.path}"),
//换名申请表审核记录
RenameAudit("${Rename.path}${Audit.path}"),
//换名申请表审核进度
RenameRead("${Rename.path}${Read.path}");
override fun build(): String { override fun build(): String {
return "/api/association${this.path}" return "/api/association${this.path}"
@ -148,7 +175,10 @@ enum class ActivityApi(val path: String) : UrlPath {
Comment("/comment"), Comment("/comment"),
//发送评论 //发送评论
SendComment("${Comment.path}/send"); SendComment("${Comment.path}/send"),
//后台活动查看
ListAll("/list/all");
override fun build(): String { override fun build(): String {

@ -19,6 +19,5 @@ class ExampleUnitTest {
@Test @Test
fun testClientToken() { fun testClientToken() {
} }
} }
Loading…
Cancel
Save