瀏覽代碼

2024-08-22 新增 / 修改

新增:

1. 团组商邀公务 - 公务出访 列表界面
2. 团组商邀公务 - 公务出访 添加界面
3. 团组商邀公务 - 公务出访 图片上传

修改:
1. 部分bug修改
2. 修改部分界面UI
3. 修改部分界面逻辑
4. 工程级项目依赖修改
zhaiy 10 月之前
父節點
當前提交
426e291240
共有 48 個文件被更改,包括 4345 次插入74 次删除
  1. 14 1
      .idea/deploymentTargetDropDown.xml
  2. 4 1
      app/build.gradle
  3. 17 1
      app/src/main/AndroidManifest.xml
  4. 6 0
      app/src/main/java/com/pan_american/android/OASystem.kt
  5. 0 1
      app/src/main/java/com/pan_american/android/base/BaseActivity.kt
  6. 13 0
      app/src/main/java/com/pan_american/android/data/model/common/entity/SimpleGroupInfo.kt
  7. 3 0
      app/src/main/java/com/pan_american/android/data/model/common/network/QueryDataSetRequest.kt
  8. 9 0
      app/src/main/java/com/pan_american/android/data/model/common/network/QueryDataSetResponse.kt
  9. 7 0
      app/src/main/java/com/pan_american/android/data/model/common/network/SimpleGroupInfoRequest.kt
  10. 6 0
      app/src/main/java/com/pan_american/android/data/model/common/network/SimpleGroupInfoResponse.kt
  11. 0 7
      app/src/main/java/com/pan_american/android/data/model/group_common_modle/bill_management/network/BillFileGroupNameRequest.kt
  12. 32 0
      app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/entity/OfficialVisitDetail.kt
  13. 11 0
      app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/entity/OfficialVisitListItem.kt
  14. 10 0
      app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/entity/PictureListItem.kt
  15. 6 0
      app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/DeleteOfficialVisitPic.kt
  16. 3 0
      app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/GetOfficialVisitDetailRequest.kt
  17. 9 0
      app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/GetOfficialVisitDetailResponse.kt
  18. 7 0
      app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/OfficialVisitListRequest.kt
  19. 9 0
      app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/OfficialVisitListResponse.kt
  20. 3 0
      app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/ProvinceAndCityDownloadFileRequest.kt
  21. 5 0
      app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/ProvinceAndCityDownloadFileResponse.kt
  22. 7 0
      app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/UpdateOfficialVisitRequest.kt
  23. 8 0
      app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/UpdateOfficialVisitResponse.kt
  24. 64 3
      app/src/main/java/com/pan_american/android/data/network/APIService.kt
  25. 1 0
      app/src/main/java/com/pan_american/android/ui/efficiency_tools/daily_payment/DailyPaymentListActivity.kt
  26. 1 0
      app/src/main/java/com/pan_american/android/ui/group_airplane_ticket/airplane_payment_insert/AddAirplaneTicketActivity.kt
  27. 37 35
      app/src/main/java/com/pan_american/android/ui/group_common/bill_management/BillManagementActivity.kt
  28. 8 9
      app/src/main/java/com/pan_american/android/ui/group_common/insurance_payment_insert/AddInsurancePaymentActivity.kt
  29. 1060 0
      app/src/main/java/com/pan_american/android/ui/group_invite_official/official_visits/AddOfficialVisitsActivity.kt
  30. 538 0
      app/src/main/java/com/pan_american/android/ui/group_invite_official/official_visits/InviteVisitsActivity.kt
  31. 1 1
      app/src/main/java/com/pan_american/android/ui/group_management/group_info/AddGroupInfoActivity.kt
  32. 9 0
      app/src/main/java/com/pan_american/android/ui/group_visa/visa_payment_insert/AddVisaPaymentActivity.kt
  33. 644 0
      app/src/main/java/com/pan_american/android/ui/picture_preview/PicturePreviewActivity.kt
  34. 3 2
      app/src/main/java/com/pan_american/android/ui/resource_management/service_resource/ServiceResourceSearchFragment.kt
  35. 22 1
      app/src/main/java/com/pan_american/android/ui/workspace/WorkspaceFragment.kt
  36. 2 2
      app/src/main/res/layout/activity_add_airplane_ticket.xml
  37. 1031 0
      app/src/main/res/layout/activity_add_official_visits.xml
  38. 319 0
      app/src/main/res/layout/activity_invite_visits.xml
  39. 35 0
      app/src/main/res/layout/activity_picture_preview.xml
  40. 33 0
      app/src/main/res/layout/fragment_workspace.xml
  41. 6 7
      app/src/main/res/layout/item_guide_and_car_list.xml
  42. 32 0
      app/src/main/res/layout/item_image_preview.xml
  43. 172 0
      app/src/main/res/layout/item_official_visits_list.xml
  44. 62 0
      app/src/main/res/layout/popup_recycler_view.xml
  45. 二進制
      app/src/main/res/mipmap-xxhdpi/icon_official_visits.png
  46. 63 2
      app/src/main/res/values/strings.xml
  47. 2 1
      app/src/main/res/xml/file_paths.xml
  48. 11 0
      settings.gradle

+ 14 - 1
.idea/deploymentTargetDropDown.xml

@@ -6,7 +6,20 @@
         <State />
       </entry>
       <entry key="app">
-        <State />
+        <State>
+          <runningDeviceTargetSelectedWithDropDown>
+            <Target>
+              <type value="RUNNING_DEVICE_TARGET" />
+              <deviceKey>
+                <Key>
+                  <type value="SERIAL_NUMBER" />
+                  <value value="3bb3c424" />
+                </Key>
+              </deviceKey>
+            </Target>
+          </runningDeviceTargetSelectedWithDropDown>
+          <timeTargetWasSelectedWithDropDown value="2024-08-21T09:11:19.338155400Z" />
+        </State>
       </entry>
     </value>
   </component>

+ 4 - 1
app/build.gradle

@@ -57,7 +57,7 @@ dependencies {
 
     implementation 'com.android.tools:r8:8.3.37'
 
-    implementation 'androidx.core:core-ktx:1.9.0'
+    implementation 'androidx.core:core-ktx:1.10.1'
     implementation 'androidx.appcompat:appcompat:1.6.1'
     implementation 'com.google.android.material:material:1.8.0'
 
@@ -96,4 +96,7 @@ dependencies {
 
     //扇形图组件
     implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
+
+    //url uri 图片展示组件
+    implementation 'com.squareup.picasso:picasso:2.8'
 }

+ 17 - 1
app/src/main/AndroidManifest.xml

@@ -14,6 +14,9 @@
     <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
+    <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
+    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
 
     <application
         android:name=".OASystem"
@@ -26,9 +29,22 @@
         android:supportsRtl="true"
         android:theme="@style/AppTheme"
         tools:targetApi="31">
+        <activity
+            android:name=".ui.picture_preview.PicturePreviewActivity"
+            android:exported="false"
+            android:launchMode="singleTop"/>
+        <activity
+            android:name=".ui.group_invite_official.official_visits.AddOfficialVisitsActivity"
+            android:exported="false"
+            android:launchMode="singleTop" />
+        <activity
+            android:name=".ui.group_invite_official.official_visits.InviteVisitsActivity"
+            android:exported="false"
+            android:launchMode="singleTop" />
         <activity
             android:name=".ui.group_common.bill_management.BillManagementActivity"
-            android:exported="false" />
+            android:exported="false"
+            android:launchMode="singleTop" />
         <activity
             android:name=".ui.customer_resource.related_invitee.RelatedInviteeActivity"
             android:exported="false"

+ 6 - 0
app/src/main/java/com/pan_american/android/OASystem.kt

@@ -247,6 +247,9 @@ class OASystem : Application() {
         //机票费用录入
         const val AIRPLANE_PAYMENT_INSERT = 161
 
+        //公务出访
+        const val OFFICIAL_VISITS = 166
+
         //市场部营业额
         const val MARKET_SALES_REVENUE = 180
 
@@ -304,6 +307,9 @@ class OASystem : Application() {
         //通知权限code
         const val NOTIFICATION_REQUEST_CODE = 1002
 
+        //相册权限code
+        const val GALLERY_REQUEST_CODE = 1003
+
         //刷新主页消息和公告
         const val REFRESH_NAVIGATION = 2001
 

+ 0 - 1
app/src/main/java/com/pan_american/android/base/BaseActivity.kt

@@ -30,7 +30,6 @@ import java.util.Calendar
 abstract class BaseActivity<T: ViewBinding>: AppCompatActivity() {
 
     private lateinit var _binding: T
-
     protected val binding get() = _binding
 
     lateinit var popupWindow: PopupWindow

+ 13 - 0
app/src/main/java/com/pan_american/android/data/model/common/entity/SimpleGroupInfo.kt

@@ -0,0 +1,13 @@
+package com.pan_american.android.data.model.common.entity
+
+class SimpleGroupInfo {
+    val id = 0
+    val name = ""
+    val clientName = ""
+    val visitPNumber = 0
+    val visitCountry = ""
+    val visitDays = 0
+    val visitStartDate = ""
+    val visitEndDate = ""
+    val tourCode = ""
+}

+ 3 - 0
app/src/main/java/com/pan_american/android/data/model/common/network/QueryDataSetRequest.kt

@@ -0,0 +1,3 @@
+package com.pan_american.android.data.model.common.network
+
+class QueryDataSetRequest(val dataTypeArr: ArrayList<Int>)

+ 9 - 0
app/src/main/java/com/pan_american/android/data/model/common/network/QueryDataSetResponse.kt

@@ -0,0 +1,9 @@
+package com.pan_american.android.data.model.common.network
+
+import com.pan_american.android.base.BaseResponse
+import com.pan_american.android.data.model.common.entity.Selector
+
+class QueryDataSetResponse(val data: ArrayList<DataSet>): BaseResponse() {
+
+    inner class DataSet(val key: Int, val arr: ArrayList<Selector>)
+}

+ 7 - 0
app/src/main/java/com/pan_american/android/data/model/common/network/SimpleGroupInfoRequest.kt

@@ -0,0 +1,7 @@
+package com.pan_american.android.data.model.common.network
+
+import com.pan_american.android.base.BaseRequest
+
+class SimpleGroupInfoRequest: BaseRequest() {
+    var search = ""
+}

+ 6 - 0
app/src/main/java/com/pan_american/android/data/model/common/network/SimpleGroupInfoResponse.kt

@@ -0,0 +1,6 @@
+package com.pan_american.android.data.model.common.network
+
+import com.pan_american.android.base.BaseResponse
+import com.pan_american.android.data.model.common.entity.SimpleGroupInfo
+
+class SimpleGroupInfoResponse(val data: ArrayList<SimpleGroupInfo>):BaseResponse()

+ 0 - 7
app/src/main/java/com/pan_american/android/data/model/group_common_modle/bill_management/network/BillFileGroupNameRequest.kt

@@ -1,7 +0,0 @@
-package com.pan_american.android.data.model.group_common_modle.bill_management.network
-
-import com.pan_american.android.base.BaseRequest
-
-class BillFileGroupNameRequest: BaseRequest() {
-    var search = ""
-}

+ 32 - 0
app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/entity/OfficialVisitDetail.kt

@@ -0,0 +1,32 @@
+package com.pan_american.android.data.model.group_invite_official.official_visits.entity
+
+import com.pan_american.android.OASystem
+
+open class OfficialVisitDetail {
+    var id = 0
+    var diId = 0
+    var type = 0
+    var client = ""
+    var date = ""
+    var time = ""
+    var address = ""
+    var contact = ""
+    var job = ""
+    var tel = ""
+    var officialForm = 0
+    var setting = ""
+    var dresscode = ""
+    var attendees = ""
+    var isNeedTrans = -1
+    var translators = ""
+    var language = ""
+    var trip = ""
+    var createUserId = OASystem.userInfo.userId
+    var remark = ""
+    var isSubmitApproval = -1
+    var isPay = -1
+    var country = ""
+    var area = ""
+    var field = ""
+    var reqSample = ""
+}

+ 11 - 0
app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/entity/OfficialVisitListItem.kt

@@ -0,0 +1,11 @@
+package com.pan_american.android.data.model.group_invite_official.official_visits.entity
+
+class OfficialVisitListItem {
+    val id = 0
+    val client = ""
+    val date = ""
+    val time = ""
+    val contact = ""
+    val createUserName = ""
+    val createTime = ""
+}

+ 10 - 0
app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/entity/PictureListItem.kt

@@ -0,0 +1,10 @@
+package com.pan_american.android.data.model.group_invite_official.official_visits.entity
+
+import android.net.Uri
+
+class PictureListItem {
+    var picName = ""
+    var uri: Uri = Uri.EMPTY
+    var url = ""
+    var fromServer = false
+}

+ 6 - 0
app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/DeleteOfficialVisitPic.kt

@@ -0,0 +1,6 @@
+package com.pan_american.android.data.model.group_invite_official.official_visits.network
+
+class DeleteOfficialVisitPic {
+    var id = 0
+    var fileName = ""
+}

+ 3 - 0
app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/GetOfficialVisitDetailRequest.kt

@@ -0,0 +1,3 @@
+package com.pan_american.android.data.model.group_invite_official.official_visits.network
+
+class GetOfficialVisitDetailRequest(val id: Int, val diId: Int)

+ 9 - 0
app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/GetOfficialVisitDetailResponse.kt

@@ -0,0 +1,9 @@
+package com.pan_american.android.data.model.group_invite_official.official_visits.network
+
+import com.pan_american.android.base.BaseResponse
+import com.pan_american.android.data.model.group_invite_official.official_visits.entity.OfficialVisitDetail
+
+class GetOfficialVisitDetailResponse(val data: Data): BaseResponse() {
+
+    inner class Data(val screenshotOfMailUrls: List<String>): OfficialVisitDetail()
+}

+ 7 - 0
app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/OfficialVisitListRequest.kt

@@ -0,0 +1,7 @@
+package com.pan_american.android.data.model.group_invite_official.official_visits.network
+
+import com.pan_american.android.base.BaseRequest
+
+class OfficialVisitListRequest: BaseRequest() {
+    var diid = 0
+}

+ 9 - 0
app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/OfficialVisitListResponse.kt

@@ -0,0 +1,9 @@
+package com.pan_american.android.data.model.group_invite_official.official_visits.network
+
+import com.pan_american.android.base.BaseResponse
+import com.pan_american.android.data.model.group_invite_official.official_visits.entity.OfficialVisitListItem
+
+class OfficialVisitListResponse(val data: Data): BaseResponse() {
+
+    inner class Data(val dataCount: Int, val dataList: ArrayList<OfficialVisitListItem>)
+}

+ 3 - 0
app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/ProvinceAndCityDownloadFileRequest.kt

@@ -0,0 +1,3 @@
+package com.pan_american.android.data.model.group_invite_official.official_visits.network
+
+class ProvinceAndCityDownloadFileRequest(val fileType: Int, val diId: Int)

+ 5 - 0
app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/ProvinceAndCityDownloadFileResponse.kt

@@ -0,0 +1,5 @@
+package com.pan_american.android.data.model.group_invite_official.official_visits.network
+
+import com.pan_american.android.base.BaseResponse
+
+class ProvinceAndCityDownloadFileResponse(val data: String): BaseResponse()

+ 7 - 0
app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/UpdateOfficialVisitRequest.kt

@@ -0,0 +1,7 @@
+package com.pan_american.android.data.model.group_invite_official.official_visits.network
+
+import com.pan_american.android.data.model.group_invite_official.official_visits.entity.OfficialVisitDetail
+
+class UpdateOfficialVisitRequest: OfficialVisitDetail() {
+    var status = 0
+}

+ 8 - 0
app/src/main/java/com/pan_american/android/data/model/group_invite_official/official_visits/network/UpdateOfficialVisitResponse.kt

@@ -0,0 +1,8 @@
+package com.pan_american.android.data.model.group_invite_official.official_visits.network
+
+import com.pan_american.android.base.BaseResponse
+
+class UpdateOfficialVisitResponse(val data: Data): BaseResponse() {
+
+    inner class Data(val id: Int)
+}

+ 64 - 3
app/src/main/java/com/pan_american/android/data/network/APIService.kt

@@ -15,9 +15,13 @@ import com.pan_american.android.data.model.common.network.GroupCurrencyRequest
 import com.pan_american.android.data.model.common.network.GroupCurrencyResponse
 import com.pan_american.android.data.model.common.network.GroupSimpleInfoRequest
 import com.pan_american.android.data.model.common.network.GroupSimpleInfoResponse
+import com.pan_american.android.data.model.common.network.QueryDataSetRequest
+import com.pan_american.android.data.model.common.network.QueryDataSetResponse
 import com.pan_american.android.data.model.common.network.QuerySetDataRequest
 import com.pan_american.android.data.model.common.network.ResourceRequest
 import com.pan_american.android.data.model.common.network.SelectorResponse
+import com.pan_american.android.data.model.common.network.SimpleGroupInfoRequest
+import com.pan_american.android.data.model.common.network.SimpleGroupInfoResponse
 import com.pan_american.android.data.model.currency.network.CurrencyExchangeRequest
 import com.pan_american.android.data.model.currency.network.CurrencyExchangeResponse
 import com.pan_american.android.data.model.currency.network.CurrencyResponse
@@ -78,7 +82,6 @@ import com.pan_american.android.data.model.group_common_modle.bill_management.ne
 import com.pan_american.android.data.model.group_common_modle.bill_management.network.BillFileDownloadAllResponse
 import com.pan_american.android.data.model.group_common_modle.bill_management.network.BillFileDownloadThisModelRequest
 import com.pan_american.android.data.model.group_common_modle.bill_management.network.BillFileDownloadThisModelResponse
-import com.pan_american.android.data.model.group_common_modle.bill_management.network.BillFileGroupNameRequest
 import com.pan_american.android.data.model.group_common_modle.bill_management.network.BillFileListRequest
 import com.pan_american.android.data.model.group_common_modle.bill_management.network.BillFileListResponse
 import com.pan_american.android.data.model.group_common_modle.insurance_payment_insert.network.InsurancePaymentDetailRequest
@@ -112,6 +115,15 @@ import com.pan_american.android.data.model.group_invite_official.invite_official
 import com.pan_american.android.data.model.group_invite_official.invite_official_payment_insert.network.InviteOfficialListRequest
 import com.pan_american.android.data.model.group_invite_official.invite_official_payment_insert.network.InviteOfficialListResponse
 import com.pan_american.android.data.model.group_invite_official.invite_official_payment_insert.network.UpdateInviteOfficialRequest
+import com.pan_american.android.data.model.group_invite_official.official_visits.network.DeleteOfficialVisitPic
+import com.pan_american.android.data.model.group_invite_official.official_visits.network.GetOfficialVisitDetailRequest
+import com.pan_american.android.data.model.group_invite_official.official_visits.network.GetOfficialVisitDetailResponse
+import com.pan_american.android.data.model.group_invite_official.official_visits.network.OfficialVisitListRequest
+import com.pan_american.android.data.model.group_invite_official.official_visits.network.OfficialVisitListResponse
+import com.pan_american.android.data.model.group_invite_official.official_visits.network.ProvinceAndCityDownloadFileRequest
+import com.pan_american.android.data.model.group_invite_official.official_visits.network.ProvinceAndCityDownloadFileResponse
+import com.pan_american.android.data.model.group_invite_official.official_visits.network.UpdateOfficialVisitRequest
+import com.pan_american.android.data.model.group_invite_official.official_visits.network.UpdateOfficialVisitResponse
 import com.pan_american.android.data.model.group_management.group_info.network.GetSellCodeResponse
 import com.pan_american.android.data.model.group_management.group_info.network.GroupCustomerListRequest
 import com.pan_american.android.data.model.group_management.group_info.network.GroupCustomerListResponse
@@ -166,6 +178,7 @@ import com.pan_american.android.data.model.resource_management.hotel_resource.ne
 import com.pan_american.android.data.model.resource_management.hotel_resource.network.HotelResourceDetailResponse
 import com.pan_american.android.data.model.resource_management.hotel_resource.network.HotelResourceListRequest
 import com.pan_american.android.data.model.resource_management.hotel_resource.network.HotelResourceListResponse
+import okhttp3.RequestBody
 import retrofit2.Call
 import retrofit2.http.Body
 import retrofit2.http.GET
@@ -921,10 +934,10 @@ interface APIService {
     fun getRelatedInviteeGroupList(@Body relatedInviteeListRequest: RelatedInviteeListRequest): Call<RelatedInviteeListResponse>
 
     /**
-     * 票据管理,基础数据源,团组名称
+     * 公共接口,基础数据源,团组名称
      */
     @POST("api/Groups/QueryGroupListOffset")
-    fun getGroupNameWithSearch(@Body billFileGroupNameRequest: BillFileGroupNameRequest): Call<SelectorResponse>
+    fun getGroupNameWithSearch(@Body simpleGroupInfoRequest: SimpleGroupInfoRequest): Call<SimpleGroupInfoResponse>
 
     /**
      * 票据管理,获取当前团组 当前板块的票据
@@ -950,4 +963,52 @@ interface APIService {
     @POST("api/Groups/ExportGroupByModule")
     fun downloadGroupThisModelBillFile(@Body billFileDownloadThisModelRequest: BillFileDownloadThisModelRequest): Call<BillFileDownloadThisModelResponse>
 
+    /**
+     * 公务出访,根据团组ID获取
+     */
+    @POST("api/Resource/QueryOfficialActivitiesByDiId")
+    fun getGroupOfficialVisitList(@Body officialVisitListRequest: OfficialVisitListRequest): Call<OfficialVisitListResponse>
+
+    /**
+     * 公务出访,删除公务出访信息
+     */
+    @POST("api/Resource/DelOfficialActivities")
+    fun deleteGroupOfficialVisit(@Body deleteRequest: DeleteRequest): Call<BaseResponse>
+
+    /**
+     * 公务出访,省外办/市外办 文件下载
+     */
+    @POST("api/Resource/OfficialActivitiesFileDownload")
+    fun downloadProvinceAndCityRequestFile(@Body provinceAndCityDownloadFileRequest: ProvinceAndCityDownloadFileRequest):Call<ProvinceAndCityDownloadFileResponse>
+
+    /**
+     * 基础数据源,通用接口
+     */
+    @POST("api/System/QuerySetDataInitByArr")
+    fun getQueryDataSet(@Body queryDataSetRequest: QueryDataSetRequest): Call<QueryDataSetResponse>
+
+    /**
+     * 公务出访,新增/修改数据
+     * status:  1.新增    2.修改
+     */
+    @POST("api/Resource/OpOfficialActivities")
+    fun updateOfficialVisitData(@Body updateOfficialVisitRequest: UpdateOfficialVisitRequest): Call<UpdateOfficialVisitResponse>
+
+    /**
+     * 公务出访,图片文件上传
+     */
+    @POST("api/Resource/OfficialActivitiesUploadFiles")
+    fun uploadOfficialPic(@Body requestBody: RequestBody): Call<BaseResponse>
+
+    /**
+     * 公务出访,删除图片
+     */
+    @POST("api/Resource/OfficialActivitiesDelFile")
+    fun deleteOfficialPic(@Body deleteOfficialVisitPic: DeleteOfficialVisitPic): Call<BaseResponse>
+
+    /**
+     * 公务出访,根据id获取公务出访详情
+     */
+    @POST("api/Resource/QueryOfficialActivitiesById")
+    fun getOfficialVisitDetailById(@Body getOfficialVisitDetailRequest: GetOfficialVisitDetailRequest): Call<GetOfficialVisitDetailResponse>
 }

+ 1 - 0
app/src/main/java/com/pan_american/android/ui/efficiency_tools/daily_payment/DailyPaymentListActivity.kt

@@ -648,6 +648,7 @@ class DailyPaymentListActivity : BaseActivity<ActivityDaliyPaymentListBinding>()
                     val baseResponse = response.body()
                     if (baseResponse != null) {
                         if (baseResponse.code == 200) {
+
                             dailyPaymentCardListItems.removeAt(position)
                             binding.dailyPaymentList.adapter!!.notifyItemRemoved(position)
                             binding.dailyPaymentList.adapter!!.notifyItemRangeChanged(position, dailyPaymentCardListItems.size - position)

+ 1 - 0
app/src/main/java/com/pan_american/android/ui/group_airplane_ticket/airplane_payment_insert/AddAirplaneTicketActivity.kt

@@ -1200,6 +1200,7 @@ class AddAirplaneTicketActivity : BaseActivity<ActivityAddAirplaneTicketBinding>
             }
 
             override fun onItemDelete(position: Int) {
+
                 customerList.removeAt(position)
                 binding.customerList.adapter!!.notifyItemRemoved(position)
                 binding.customerList.adapter!!.notifyItemRangeChanged(position, customerList.size - position)

+ 37 - 35
app/src/main/java/com/pan_american/android/ui/group_common/bill_management/BillManagementActivity.kt

@@ -21,16 +21,18 @@ import com.pan_american.android.base.BaseResponse
 import com.pan_american.android.base.CustomAlertDialog
 import com.pan_american.android.base.ListAdapter
 import com.pan_american.android.data.model.common.entity.Selector
+import com.pan_american.android.data.model.common.entity.SimpleGroupInfo
 import com.pan_american.android.data.model.common.network.DeleteRequest
 import com.pan_american.android.data.model.common.network.QuerySetDataRequest
 import com.pan_american.android.data.model.common.network.SelectorResponse
+import com.pan_american.android.data.model.common.network.SimpleGroupInfoRequest
+import com.pan_american.android.data.model.common.network.SimpleGroupInfoResponse
 import com.pan_american.android.data.model.group_common_modle.bill_management.adapter.BillFileItemAdapter
 import com.pan_american.android.data.model.group_common_modle.bill_management.entity.BillFileListItem
 import com.pan_american.android.data.model.group_common_modle.bill_management.network.BillFileDownloadAllRequest
 import com.pan_american.android.data.model.group_common_modle.bill_management.network.BillFileDownloadAllResponse
 import com.pan_american.android.data.model.group_common_modle.bill_management.network.BillFileDownloadThisModelRequest
 import com.pan_american.android.data.model.group_common_modle.bill_management.network.BillFileDownloadThisModelResponse
-import com.pan_american.android.data.model.group_common_modle.bill_management.network.BillFileGroupNameRequest
 import com.pan_american.android.data.model.group_common_modle.bill_management.network.BillFileListRequest
 import com.pan_american.android.data.model.group_common_modle.bill_management.network.BillFileListResponse
 import com.pan_american.android.data.network.APIService
@@ -54,9 +56,9 @@ class BillManagementActivity : BaseActivity<ActivityBillManagementBinding>() {
 
     private var selectedPaymentPlateId = 0
 
-    private val groupNameList = ArrayList<Selector>()
+    private val simpleGroupInfoList = ArrayList<SimpleGroupInfo>()
 
-    private val groupNameDataRequest = BillFileGroupNameRequest()
+    private val simpleGroupInfoRequest = SimpleGroupInfoRequest()
 
     private var selectedGroupNameId = 0
 
@@ -103,15 +105,15 @@ class BillManagementActivity : BaseActivity<ActivityBillManagementBinding>() {
     override fun initEvents() {
 
         binding.groupName.setOnClickListener {
-            groupNameDataRequest.apply {
+            simpleGroupInfoRequest.apply {
                 pageIndex = 1
-                pageSize = 12
+                pageSize = 10
                 search = ""
             }
 
-            groupNameList.clear()
+            simpleGroupInfoList.clear()
 
-            getGroupNameResource(1)
+            getSimpleGroupInfoResource(1)
         }
 
         binding.paymentPlate.setOnClickListener {
@@ -179,35 +181,35 @@ class BillManagementActivity : BaseActivity<ActivityBillManagementBinding>() {
     }
 
     private fun initGroupName() {
-        groupNameDataRequest.apply {
+        simpleGroupInfoRequest.apply {
             pageIndex = 1
             pageSize = 3
             search = ""
         }
 
-        groupNameList.clear()
+        simpleGroupInfoList.clear()
 
-        getGroupNameResource(0)
+        getSimpleGroupInfoResource(0)
     }
 
-    private fun getGroupNameResource(type: Int) {
-        apiService.getGroupNameWithSearch(groupNameDataRequest).enqueue(object : Callback<SelectorResponse> {
-            override fun onResponse(p0: Call<SelectorResponse>, response: Response<SelectorResponse>) {
+    private fun getSimpleGroupInfoResource(type: Int) {
+        apiService.getGroupNameWithSearch(simpleGroupInfoRequest).enqueue(object : Callback<SimpleGroupInfoResponse> {
+            override fun onResponse(p0: Call<SimpleGroupInfoResponse>, response: Response<SimpleGroupInfoResponse>) {
                 val resourceResponse = response.body()
 
                 if (resourceResponse != null) {
                     if (resourceResponse.code == 200) {
 
                         for (item in resourceResponse.data) {
-                            groupNameList.add(item)
+                            simpleGroupInfoList.add(item)
                         }
 
                         when(type) {
 
                             0 -> {
-                                binding.groupName.text = groupNameList[0].name
+                                binding.groupName.text = simpleGroupInfoList[0].name
 
-                                selectedGroupNameId = groupNameList[0].id
+                                selectedGroupNameId = simpleGroupInfoList[0].id
 
                                 initGroupPlate()
                             }
@@ -232,8 +234,8 @@ class BillManagementActivity : BaseActivity<ActivityBillManagementBinding>() {
                                     val layoutManager = LinearLayoutManager(OASystem.context)
                                     selector.layoutManager = layoutManager
 
-                                    val adapter = ListAdapter.Builder<Selector>().apply {
-                                        setData(groupNameList)
+                                    val adapter = ListAdapter.Builder<SimpleGroupInfo>().apply {
+                                        setData(simpleGroupInfoList)
                                         setLayoutId(R.layout.item_selector)
                                         addBindView { itemView, data ->
                                             itemView.findViewById<TextView>(R.id.selector_item_name).apply {
@@ -251,9 +253,9 @@ class BillManagementActivity : BaseActivity<ActivityBillManagementBinding>() {
                                     selector.adapter = adapter
 
                                     adapter.onRecyclerViewItemClick =
-                                        object : ListAdapter.OnRecyclerViewItemClick<Selector> {
+                                        object : ListAdapter.OnRecyclerViewItemClick<SimpleGroupInfo> {
                                             override fun onItemClick(position: Int) {
-                                                groupNameList[position].apply {
+                                                simpleGroupInfoList[position].apply {
                                                     binding.groupName.text = name
 
                                                     selectedGroupNameId = id
@@ -268,19 +270,19 @@ class BillManagementActivity : BaseActivity<ActivityBillManagementBinding>() {
                                     selectorContainer.setOnRefreshLoadMoreListener(object :
                                         OnRefreshLoadMoreListener {
                                         override fun onRefresh(p0: RefreshLayout) {
-                                            groupNameDataRequest.pageIndex = 1
+                                            simpleGroupInfoRequest.pageIndex = 1
 
-                                            selector.adapter!!.notifyItemRangeRemoved(0, groupNameList.size)
+                                            selector.adapter!!.notifyItemRangeRemoved(0, simpleGroupInfoList.size)
 
-                                            groupNameList.clear()
+                                            simpleGroupInfoList.clear()
 
-                                            getGroupNameResource(2)
+                                            getSimpleGroupInfoResource(2)
                                         }
 
                                         override fun onLoadMore(p0: RefreshLayout) {
-                                            groupNameDataRequest.pageIndex += 1
+                                            simpleGroupInfoRequest.pageIndex += 1
 
-                                            getGroupNameResource(3)
+                                            getSimpleGroupInfoResource(3)
                                         }
                                     })
 
@@ -295,36 +297,36 @@ class BillManagementActivity : BaseActivity<ActivityBillManagementBinding>() {
 
                                         override fun afterTextChanged(editable: Editable?) {
 
-                                            adapter.notifyItemRangeRemoved(0, groupNameList.size)
+                                            adapter.notifyItemRangeRemoved(0, simpleGroupInfoList.size)
 
-                                            groupNameList.clear()
+                                            simpleGroupInfoList.clear()
 
-                                            groupNameDataRequest.apply {
+                                            simpleGroupInfoRequest.apply {
                                                 pageIndex = 1
                                                 search = editable.toString()
                                             }
 
-                                            getGroupNameResource(2)
+                                            getSimpleGroupInfoResource(2)
                                         }
                                     })
 
                                     popupWindow.showAtLocation(binding.root, Gravity.BOTTOM, 0, 0)
                                 }
 
-                                selectorContainer.setEnableLoadMore(groupNameDataRequest.pageIndex < getTotalPage(resourceResponse.count))
+                                selectorContainer.setEnableLoadMore(simpleGroupInfoRequest.pageIndex < getTotalPage(resourceResponse.count))
                                 selector.adapter!!.notifyItemInserted(0)
                             }
 
                             2 -> {
                                 selectorContainer.finishRefresh()
-                                selectorContainer.setEnableLoadMore(groupNameDataRequest.pageIndex < getTotalPage(resourceResponse.count))
+                                selectorContainer.setEnableLoadMore(simpleGroupInfoRequest.pageIndex < getTotalPage(resourceResponse.count))
                                 selector.adapter!!.notifyItemInserted(0)
                             }
 
                             3 -> {
                                 selectorContainer.finishLoadMore()
-                                selectorContainer.setEnableLoadMore(groupNameDataRequest.pageIndex < getTotalPage(resourceResponse.count))
-                                selector.adapter!!.notifyItemInserted(groupNameList.size)
+                                selectorContainer.setEnableLoadMore(simpleGroupInfoRequest.pageIndex < getTotalPage(resourceResponse.count))
+                                selector.adapter!!.notifyItemInserted(simpleGroupInfoList.size)
                             }
                         }
 
@@ -334,7 +336,7 @@ class BillManagementActivity : BaseActivity<ActivityBillManagementBinding>() {
                 }
             }
 
-            override fun onFailure(p0: Call<SelectorResponse>, p1: Throwable) {
+            override fun onFailure(p0: Call<SimpleGroupInfoResponse>, p1: Throwable) {
                 showErrorInfo(R.string.group_name_list_get_failed)
             }
         })

+ 8 - 9
app/src/main/java/com/pan_american/android/ui/group_common/insurance_payment_insert/AddInsurancePaymentActivity.kt

@@ -168,6 +168,13 @@ class AddInsurancePaymentActivity : BaseActivity<ActivityAddInsurancePaymentBind
                     insuranceTypeId = item.id
                 }
             }
+
+            for (item in currencyList) {
+                if (item.currencyCode == "CNY") {
+                    binding.insuranceCurrency.text = item.currencyCode
+                    currencyId = item.currencyId
+                }
+            }
         }
     }
 
@@ -206,15 +213,7 @@ class AddInsurancePaymentActivity : BaseActivity<ActivityAddInsurancePaymentBind
                     setLayoutId(R.layout.item_selector)
                     addBindView { itemView, data ->
                         itemView.findViewById<TextView>(R.id.selector_item_name).apply {
-                            text = String.format(
-                                resources.getString(R.string.currency_name_code_format),
-                                String.format(
-                                    resources.getString(R.string.with_space_format),
-                                    data.lastName,
-                                    data.firstName
-                                ),
-                                data.pinyin
-                            )
+                            text = String.format(resources.getString(R.string.currency_name_code_format), String.format(resources.getString(R.string.with_space_format), data.lastName, data.firstName), data.pinyin)
 
                             for (item in customerSelectList) {
                                 if (data.id == item.id) {

File diff suppressed because it is too large
+ 1060 - 0
app/src/main/java/com/pan_american/android/ui/group_invite_official/official_visits/AddOfficialVisitsActivity.kt


+ 538 - 0
app/src/main/java/com/pan_american/android/ui/group_invite_official/official_visits/InviteVisitsActivity.kt

@@ -0,0 +1,538 @@
+package com.pan_american.android.ui.group_invite_official.official_visits
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.Gravity
+import android.view.View
+import android.widget.EditText
+import android.widget.LinearLayout
+import android.widget.PopupWindow
+import android.widget.TextView
+import androidx.core.content.res.ResourcesCompat
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.pan_american.android.OASystem
+import com.pan_american.android.R
+import com.pan_american.android.base.BaseActivity
+import com.pan_american.android.base.BaseResponse
+import com.pan_american.android.base.CardAdapter
+import com.pan_american.android.base.CustomAlertDialog
+import com.pan_american.android.base.ListAdapter
+import com.pan_american.android.data.model.common.entity.SimpleGroupInfo
+import com.pan_american.android.data.model.common.network.DeleteRequest
+import com.pan_american.android.data.model.common.network.SimpleGroupInfoRequest
+import com.pan_american.android.data.model.common.network.SimpleGroupInfoResponse
+import com.pan_american.android.data.model.group_invite_official.official_visits.entity.OfficialVisitListItem
+import com.pan_american.android.data.model.group_invite_official.official_visits.network.OfficialVisitListRequest
+import com.pan_american.android.data.model.group_invite_official.official_visits.network.OfficialVisitListResponse
+import com.pan_american.android.data.model.group_invite_official.official_visits.network.ProvinceAndCityDownloadFileRequest
+import com.pan_american.android.data.model.group_invite_official.official_visits.network.ProvinceAndCityDownloadFileResponse
+import com.pan_american.android.data.network.APIService
+import com.pan_american.android.data.network.ServiceCreator
+import com.pan_american.android.databinding.ActivityInviteVisitsBinding
+import com.pan_american.android.databinding.LayoutTitleBinding
+import com.scwang.smart.refresh.footer.ClassicsFooter
+import com.scwang.smart.refresh.header.ClassicsHeader
+import com.scwang.smart.refresh.layout.api.RefreshLayout
+import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+
+class InviteVisitsActivity : BaseActivity<ActivityInviteVisitsBinding>() {
+
+    private val apiService = ServiceCreator.create<APIService>()
+
+    private val simpleGroupInfoRequest = SimpleGroupInfoRequest()
+
+    private val officialVisitListRequest = OfficialVisitListRequest()
+
+    private val simpleGroupInfoList = ArrayList<SimpleGroupInfo>()
+
+    private val officialVisitList = ArrayList<OfficialVisitListItem>()
+
+    private var groupId = 0
+
+    private lateinit var titleBinding: LayoutTitleBinding
+
+    override fun getViewBinding() = ActivityInviteVisitsBinding.inflate(layoutInflater)
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        screenAdaptation(binding)
+
+        initTitle()
+        initViews()
+    }
+
+    override fun initTitle() {
+        titleBinding = LayoutTitleBinding.bind(binding.root).apply {
+            titleText.text = resources.getString(R.string.official_visits)
+
+            if (OASystem.authorization(OASystem.OFFICIAL_VISITS, OASystem.ADD)) {
+                addButton.visibility = View.VISIBLE
+            }
+
+            addButton.setOnClickListener {
+                val intent = Intent(OASystem.context, AddOfficialVisitsActivity::class.java).apply {
+                    putExtra("fromList", false)
+                    run {
+                        for (item in simpleGroupInfoList) {
+                            if (groupId == item.id) {
+                                putExtra("groupName", item.name)
+                                putExtra("visitCountry", item.visitCountry)
+                                putExtra("clientName", item.clientName)
+                                putExtra("groupCode", item.tourCode)
+                                putExtra("groupId", groupId)
+                                return@run
+                            }
+                        }
+                    }
+                }
+                startActivity(intent)
+            }
+
+            backButton.setOnClickListener {
+                back()
+            }
+        }
+    }
+
+    override fun initViews() {
+
+        binding.officialVisitsContainer.setRefreshHeader(ClassicsHeader(OASystem.context))
+        binding.officialVisitsContainer.setRefreshFooter(ClassicsFooter(OASystem.context))
+
+        simpleGroupInfoRequest.apply {
+            pageIndex = 1
+            pageSize = 3
+        }
+
+        officialVisitListRequest.apply {
+            pageIndex = 1
+            pageSize = 10
+        }
+
+        getSimpleGroupInfoResource(0)
+    }
+
+    override fun initEvents() {
+
+        binding.groupNameSelector.setOnClickListener {
+            simpleGroupInfoRequest.apply {
+                pageIndex = 1
+                pageSize = 10
+                search = ""
+            }
+
+            simpleGroupInfoList.clear()
+
+            getSimpleGroupInfoResource(1)
+        }
+
+        binding.baseInfoSwitch.setOnClickListener {
+
+            if (binding.groupBaseInfo.visibility == View.GONE) {
+                binding.groupBaseInfo.visibility = View.VISIBLE
+                binding.baseInfoSwitch.text = resources.getString(R.string.hide)
+            } else {
+                binding.groupBaseInfo.visibility = View.GONE
+                binding.baseInfoSwitch.text = resources.getString(R.string.show)
+            }
+        }
+
+        binding.provinceRequestData.setOnClickListener {
+            downloadRequestData(1)
+        }
+
+        binding.cityRequestData.setOnClickListener {
+            downloadRequestData(2)
+        }
+    }
+
+    override fun onResume() {
+        super.onResume()
+
+        if (OASystem.needRefresh) {
+            binding.officialVisitsList.adapter!!.notifyItemRangeRemoved(0, officialVisitList.size)
+            officialVisitListRequest.pageIndex = 1
+            officialVisitList.clear()
+            getGroupOfficialVisitsList(2)
+        }
+    }
+
+    private fun getSimpleGroupInfoResource(type: Int) {
+        apiService.getGroupNameWithSearch(simpleGroupInfoRequest).enqueue(object :
+            Callback<SimpleGroupInfoResponse> {
+            override fun onResponse(p0: Call<SimpleGroupInfoResponse>, response: Response<SimpleGroupInfoResponse>) {
+                val resourceResponse = response.body()
+
+                if (resourceResponse != null) {
+                    if (resourceResponse.code == 200) {
+
+                        for (item in resourceResponse.data) {
+                            simpleGroupInfoList.add(item)
+                        }
+
+                        when(type) {
+
+                            0 -> {
+
+                                simpleGroupInfoList[0].apply {
+                                    binding.groupNameSelector.text = name
+                                    binding.groupCustomer.text = clientName
+                                    binding.visitCountry.text = visitCountry
+                                    binding.visitDays.text = visitDays.toString()
+                                    binding.visitMembers.text = visitPNumber.toString()
+                                    binding.duringTime.text = String.format(resources.getString(R.string.during_format), this.visitStartDate.substring(0, 10), this.visitEndDate.substring(0, 10))
+
+                                    groupId = id
+                                }
+
+                                initEvents()
+
+                                getGroupOfficialVisitsList(1)
+                            }
+
+                            1 -> {
+
+                                val popView = View.inflate(OASystem.context, R.layout.popup_selector, null)
+                                popupWindow = PopupWindow(popView, RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)
+
+                                showPopupWindow {
+                                    val searchView: LinearLayout = popView.findViewById(R.id.search_view)
+                                    searchView.visibility = View.VISIBLE
+
+                                    val searchText: EditText = popView.findViewById(R.id.search_text)
+
+                                    selector = popView.findViewById(R.id.selector_list)
+
+                                    selectorContainer = popView.findViewById(R.id.selector_refresh_container)
+                                    selectorContainer.setEnableRefresh(true)
+                                    selectorContainer.setEnableLoadMore(true)
+
+                                    val layoutManager = LinearLayoutManager(OASystem.context)
+                                    selector.layoutManager = layoutManager
+
+                                    val adapter = ListAdapter.Builder<SimpleGroupInfo>().apply {
+                                        setData(simpleGroupInfoList)
+                                        setLayoutId(R.layout.item_selector)
+                                        addBindView { itemView, data ->
+                                            itemView.findViewById<TextView>(R.id.selector_item_name).apply {
+                                                text = data.name
+
+                                                if (binding.groupNameSelector.text == data.name) {
+                                                    setTextColor(ResourcesCompat.getColor(resources, R.color.text_color_blue, null))
+                                                } else {
+                                                    setTextColor(ResourcesCompat.getColor(resources, R.color.text_color, null))
+                                                }
+                                            }
+                                        }
+                                    }.create()
+
+                                    selector.adapter = adapter
+
+                                    adapter.onRecyclerViewItemClick =
+                                        object : ListAdapter.OnRecyclerViewItemClick<SimpleGroupInfo> {
+                                            override fun onItemClick(position: Int) {
+                                                simpleGroupInfoList[position].apply {
+                                                    binding.groupNameSelector.text = name
+                                                    binding.groupCustomer.text = clientName
+                                                    binding.visitCountry.text = visitCountry
+                                                    binding.visitDays.text = visitDays.toString()
+                                                    binding.visitMembers.text = visitPNumber.toString()
+                                                    binding.duringTime.text = String.format(resources.getString(R.string.during_format), this.visitStartDate.substring(0, 10), this.visitEndDate.substring(0, 10))
+
+                                                    groupId = id
+
+                                                    getGroupOfficialVisitsList(1)
+
+                                                    popupWindow.dismiss()
+                                                }
+                                            }
+                                        }
+
+                                    selectorContainer.setOnRefreshLoadMoreListener(object :
+                                        OnRefreshLoadMoreListener {
+                                        override fun onRefresh(p0: RefreshLayout) {
+                                            simpleGroupInfoRequest.pageIndex = 1
+
+                                            selector.adapter!!.notifyItemRangeRemoved(0, simpleGroupInfoList.size)
+
+                                            simpleGroupInfoList.clear()
+
+                                            getSimpleGroupInfoResource(2)
+                                        }
+
+                                        override fun onLoadMore(p0: RefreshLayout) {
+                                            simpleGroupInfoRequest.pageIndex += 1
+
+                                            getSimpleGroupInfoResource(3)
+                                        }
+                                    })
+
+                                    searchText.addTextChangedListener(object : TextWatcher {
+                                        override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
+
+                                        }
+
+                                        override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
+
+                                        }
+
+                                        override fun afterTextChanged(editable: Editable?) {
+
+                                            adapter.notifyItemRangeRemoved(0, simpleGroupInfoList.size)
+
+                                            simpleGroupInfoList.clear()
+
+                                            simpleGroupInfoRequest.apply {
+                                                pageIndex = 1
+                                                search = editable.toString()
+                                            }
+
+                                            getSimpleGroupInfoResource(2)
+                                        }
+                                    })
+
+                                    popupWindow.showAtLocation(binding.root, Gravity.BOTTOM, 0, 0)
+                                }
+
+                                selectorContainer.setEnableLoadMore(simpleGroupInfoRequest.pageIndex < getTotalPage(resourceResponse.count))
+                                selector.adapter!!.notifyItemInserted(0)
+                            }
+
+                            2 -> {
+                                selectorContainer.finishRefresh()
+                                selectorContainer.setEnableLoadMore(simpleGroupInfoRequest.pageIndex < getTotalPage(resourceResponse.count))
+                                selector.adapter!!.notifyItemInserted(0)
+                            }
+
+                            3 -> {
+                                selectorContainer.finishLoadMore()
+                                selectorContainer.setEnableLoadMore(simpleGroupInfoRequest.pageIndex < getTotalPage(resourceResponse.count))
+                                selector.adapter!!.notifyItemInserted(simpleGroupInfoList.size)
+                            }
+                        }
+
+                    } else {
+                        showMessage(resourceResponse.msg)
+                    }
+                }
+            }
+
+            override fun onFailure(p0: Call<SimpleGroupInfoResponse>, p1: Throwable) {
+                showErrorInfo(R.string.group_name_list_get_failed)
+            }
+        })
+    }
+
+    private fun getTotalPage(count: Int): Int {
+        var pageCount = count / 10
+
+        if (count % 10 > 0) {
+            pageCount += 1
+        }
+
+        return pageCount
+    }
+
+    private fun getGroupOfficialVisitsList(type: Int) {
+
+        officialVisitListRequest.diid = groupId
+
+        apiService.getGroupOfficialVisitList(officialVisitListRequest).enqueue(object : Callback<OfficialVisitListResponse> {
+            override fun onResponse(
+                p0: Call<OfficialVisitListResponse>,
+                response: Response<OfficialVisitListResponse>
+            ) {
+                val listResponse = response.body()
+
+                if (listResponse != null) {
+                    if (listResponse.code == 200) {
+
+                        for (item in listResponse.data.dataList) {
+                            officialVisitList.add(item)
+                        }
+
+                        when(type) {
+                            1 -> {
+                                binding.officialVisitsContainer.setEnableLoadMore(officialVisitListRequest.pageIndex < getTotalPage(listResponse.data.dataCount))
+                                initList()
+                            }
+
+                            2 -> {
+                                binding.officialVisitsContainer.finishRefresh()
+                                binding.officialVisitsContainer.setEnableLoadMore(officialVisitListRequest.pageIndex < getTotalPage(listResponse.data.dataCount))
+                                initList()
+                            }
+
+                            3 -> {
+                                binding.officialVisitsContainer.finishLoadMore()
+                                binding.officialVisitsContainer.setEnableLoadMore(officialVisitListRequest.pageIndex < getTotalPage(listResponse.data.dataCount))
+                                binding.officialVisitsList.adapter!!.notifyItemInserted(officialVisitList.size)
+                            }
+                        }
+
+                    } else {
+                        showMessage(listResponse.msg)
+                    }
+                }
+            }
+
+            override fun onFailure(p0: Call<OfficialVisitListResponse>, p1: Throwable) {
+                showErrorInfo(R.string.official_visits_list_get_error)
+            }
+        })
+    }
+
+    private fun initList() {
+        if (officialVisitList.size == 0) {
+            showMessage(resources.getString(R.string.no_data))
+            return
+        }
+
+        val layoutManager = LinearLayoutManager(OASystem.context)
+        binding.officialVisitsList.layoutManager = layoutManager
+
+        val adapter = CardAdapter.Builder<OfficialVisitListItem>().apply {
+            setData(officialVisitList)
+            setLayoutId(R.layout.item_official_visits_list)
+            setCanDelete(OASystem.authorization(OASystem.OFFICIAL_VISITS, OASystem.DELETE))
+            addBindView { itemView, data ->
+                itemView.findViewById<TextView>(R.id.official_department).text = data.client
+                itemView.findViewById<TextView>(R.id.official_time).text = String.format(resources.getString(R.string.with_space_format), data.date.substring(0, 10), data.time)
+                itemView.findViewById<TextView>(R.id.contacts_name).text = data.contact
+                itemView.findViewById<TextView>(R.id.creator).text = data.createUserName
+                itemView.findViewById<TextView>(R.id.create_time).text = data.createTime
+            }
+        }.create()
+
+        binding.officialVisitsList.adapter = adapter
+
+        adapter.onRecyclerViewItemClick = object : CardAdapter.OnRecyclerViewItemClick<OfficialVisitListItem> {
+            override fun onItemClick(position: Int) {
+                val intent = Intent(OASystem.context, AddOfficialVisitsActivity::class.java).apply {
+                    run {
+                        for (item in simpleGroupInfoList) {
+                            if (groupId == item.id) {
+                                putExtra("groupName", item.name)
+                                putExtra("visitCountry", item.visitCountry)
+                                putExtra("clientName", item.clientName)
+                                putExtra("groupCode", item.tourCode)
+                                putExtra("id", officialVisitList[position].id)
+                                putExtra("groupId", groupId)
+                                putExtra("fromList", true)
+                                return@run
+                            }
+                        }
+                    }
+                }
+
+                startActivity(intent)
+            }
+
+            override fun onItemDelete(position: Int) {
+                CustomAlertDialog.Builder(OASystem.context).apply {
+                    setTitle(resources.getString(R.string.alert))
+                    setMessage(String.format(resources.getString(R.string.delete_alert_text), officialVisitList[position].client))
+                    setNegativeButtonAndListener(resources.getString(R.string.cancel)) { dialog, _ ->
+                        dialog.dismiss()
+                    }
+                    setPositiveButtonAndListener(resources.getString(R.string.confirm)) { dialog, _ ->
+                        dialog.dismiss()
+                        deleteOfficialItem(position)
+                    }
+                }.show()
+            }
+        }
+
+        binding.officialVisitsContainer.setOnRefreshLoadMoreListener(object : OnRefreshLoadMoreListener {
+            override fun onRefresh(p0: RefreshLayout) {
+                binding.officialVisitsList.adapter!!.notifyItemRangeRemoved(0, officialVisitList.size)
+                officialVisitListRequest.pageIndex = 1
+                officialVisitList.clear()
+                getGroupOfficialVisitsList(2)
+            }
+
+            override fun onLoadMore(p0: RefreshLayout) {
+                officialVisitListRequest.pageIndex += 1
+                getGroupOfficialVisitsList(3)
+            }
+        })
+    }
+
+    private fun deleteOfficialItem(position: Int) {
+        apiService.deleteGroupOfficialVisit(DeleteRequest(officialVisitList[position].id)).enqueue(object : Callback<BaseResponse> {
+            override fun onResponse(p0: Call<BaseResponse>, response: Response<BaseResponse>) {
+
+                val deleteResponse = response.body()
+
+                if (deleteResponse != null) {
+                    if (deleteResponse.code == 200) {
+
+                        officialVisitList.removeAt(position)
+                        binding.officialVisitsList.adapter!!.notifyItemRemoved(position)
+                        binding.officialVisitsList.adapter!!.notifyItemRangeChanged(position, officialVisitList.size - position)
+
+                        showMessage(resources.getString(R.string.delete_success))
+
+                    } else {
+                        showMessage(deleteResponse.msg)
+                    }
+                }
+            }
+
+            override fun onFailure(p0: Call<BaseResponse>, p1: Throwable) {
+                showErrorInfo(R.string.delete_error)
+            }
+        })
+    }
+
+    private fun downloadRequestData(type: Int) {
+        apiService.downloadProvinceAndCityRequestFile(ProvinceAndCityDownloadFileRequest(type, groupId)).enqueue(object : Callback<ProvinceAndCityDownloadFileResponse> {
+            override fun onResponse(call: Call<ProvinceAndCityDownloadFileResponse>, response: Response<ProvinceAndCityDownloadFileResponse>) {
+
+                val urlResponse = response.body()
+
+                if (urlResponse != null) {
+                    if (urlResponse.code == 200) {
+
+                        CustomAlertDialog.Builder(OASystem.context).apply {
+                            setTitle(resources.getString(R.string.confirm))
+
+                            when(type) {
+                                1 -> {
+                                    setMessage(String.format(resources.getString(R.string.request_data_download_hint), binding.groupNameSelector.text, resources.getString(R.string.province_request_data)))
+                                }
+
+                                2 -> {
+                                    setMessage(String.format(resources.getString(R.string.request_data_download_hint), binding.groupNameSelector.text, resources.getString(R.string.city_request_data)))
+                                }
+                            }
+
+                            setNegativeButtonAndListener(resources.getString(R.string.cancel)) { dialog, _ ->
+                                dialog.dismiss()
+                            }
+
+                            setPositiveButtonAndListener(resources.getString(R.string.confirm)) { _, _ ->
+                                val uri = Uri.parse(urlResponse.data)
+                                startActivity(Intent(Intent.ACTION_VIEW, uri))
+                            }
+                        }.show()
+
+                    } else {
+                        showMessage(urlResponse.msg)
+                    }
+                }
+            }
+
+            override fun onFailure(call: Call<ProvinceAndCityDownloadFileResponse>, t: Throwable) {
+                showErrorInfo(R.string.interface_request_error)
+            }
+        })
+    }
+}

+ 1 - 1
app/src/main/java/com/pan_american/android/ui/group_management/group_info/AddGroupInfoActivity.kt

@@ -322,7 +322,7 @@ class AddGroupInfoActivity : BaseActivity<ActivityAddGroupInfoBinding>() {
             byteArrayOutputStream.reset()
             bitmap.recycle()
 
-        } while ((!base64Adjusted))
+        } while (!base64Adjusted)
 
         val file = File(filesDir, "data.txt")
         if (file.exists()) {

+ 9 - 0
app/src/main/java/com/pan_american/android/ui/group_visa/visa_payment_insert/AddVisaPaymentActivity.kt

@@ -174,6 +174,13 @@ class AddVisaPaymentActivity : BaseActivity<ActivityAddVisaPaymentBinding>() {
             binding.visaHandleNumber.setText(customerSelectList.size.toString())
 
             binding.visaExemptionNumber.setText("0")
+
+            for (item in priceUnitList) {
+                if (item.currencyCode == "CNY") {
+                    binding.priceUnit.text = item.currencyCode
+                    priceUnit = item.currencyId
+                }
+            }
         }
     }
 
@@ -792,9 +799,11 @@ class AddVisaPaymentActivity : BaseActivity<ActivityAddVisaPaymentBinding>() {
             }
 
             override fun onItemDelete(position: Int) {
+
                 customerSelectList.removeAt(position)
                 binding.customerList.adapter!!.notifyItemRemoved(position)
                 binding.customerList.adapter!!.notifyItemRangeChanged(position, customerSelectList.size - position)
+
             }
         }
     }

+ 644 - 0
app/src/main/java/com/pan_american/android/ui/picture_preview/PicturePreviewActivity.kt

@@ -0,0 +1,644 @@
+package com.pan_american.android.ui.picture_preview
+
+import android.annotation.SuppressLint
+import android.graphics.Matrix
+import android.graphics.PointF
+import android.graphics.RectF
+import android.os.Bundle
+import android.view.GestureDetector
+import android.view.GestureDetector.OnDoubleTapListener
+import android.view.MotionEvent
+import android.view.ViewTreeObserver
+import android.widget.ImageView
+import androidx.appcompat.widget.AppCompatImageView
+import com.pan_american.android.OASystem
+import com.pan_american.android.R
+import com.pan_american.android.base.BaseActivity
+import com.pan_american.android.databinding.ActivityPicturePreviewBinding
+import com.pan_american.android.databinding.LayoutTitleBinding
+import com.squareup.picasso.Callback
+import com.squareup.picasso.Picasso
+import kotlin.math.atan2
+import kotlin.math.sqrt
+
+class PicturePreviewActivity : BaseActivity<ActivityPicturePreviewBinding>() {
+
+    companion object {
+        const val NONE = 0
+        const val DRAG = 1
+        const val ZOOM = 2
+    }
+
+    private var fromServer = false
+
+    private var uri = ""
+
+    private var url = ""
+
+    private var picName = ""
+
+    private lateinit var imageView: AppCompatImageView
+
+    private lateinit var gestureDetector: GestureDetector
+
+    private val pointF = PointF()
+
+    private val matrix = Matrix()
+
+    private val tempMatrix = Matrix()
+
+    private val savedMatrix = Matrix()
+
+    //双击放大还是缩小
+    private var isZoomIn = false
+
+    private var mode = 0
+
+    private var xDown = 0F
+
+    private var yDown = 0F
+
+    private var oldDist = 0F
+
+    private var oldRotation = 0F
+
+    private var rotation = 0F //旋转角度差值
+
+    private var newRotation = 0F
+
+    private var resetScale = 1F
+
+    private var currScale = 1F
+
+    private var widthScreen = 0
+
+    private var heightScreen = 0
+
+    private var isCheckTopAndBottom = false
+
+    private var isCheckRightAndLeft = false
+
+    private lateinit var titleBinding: LayoutTitleBinding
+
+    override fun getViewBinding() = ActivityPicturePreviewBinding.inflate(layoutInflater)
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        intent.apply {
+
+            fromServer = getBooleanExtra("fromServer", false)
+            picName = getStringExtra("name").toString()
+
+            if (fromServer) {
+                url = getStringExtra("url").toString()
+            } else {
+                uri = getStringExtra("uri").toString()
+            }
+
+        }
+
+        imageView = binding.imageView
+
+        initTitle()
+        initViews()
+        initEvents()
+    }
+
+    override fun initTitle() {
+        titleBinding = LayoutTitleBinding.bind(binding.root).apply {
+            titleText.text = resources.getString(R.string.picture_preview)
+
+            backButton.setOnClickListener {
+                back()
+            }
+        }
+    }
+
+    @SuppressLint("ClickableViewAccessibility")
+    override fun initViews() {
+
+//        binding.imageName.text = picName
+
+        imageView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
+            override fun onGlobalLayout() {
+                imageView.viewTreeObserver.removeOnGlobalLayoutListener(this)
+
+                //获取imageView的宽和高
+                // 此时可以安全地获取ImageView的尺寸并设置图片
+                widthScreen = imageView.width
+                heightScreen = imageView.height
+
+                if (fromServer) {
+                    Picasso.get().load(url).resize(widthScreen, heightScreen).centerInside().into(imageView, object : Callback {
+                        override fun onSuccess() {
+
+                            imageView.scaleType = ImageView.ScaleType.MATRIX
+
+                            //初始化图片的矩阵
+                            matrix.set(imageView.imageMatrix)
+
+                            /**
+                             * 初始化 将图片放在屏幕中心位置
+                             */
+                            center()
+
+                            /**
+                             * 图片设置中心之后,重新设置图片的缩放矩阵
+                             */
+                            imageView.imageMatrix = matrix
+                        }
+
+                        override fun onError(p0: Exception?) {
+                            showErrorInfo(R.string.picture_load_error)
+                        }
+                    })
+                } else {
+                    Picasso.get().load(uri).resize(widthScreen, heightScreen).centerInside().into(imageView, object : Callback {
+                        override fun onSuccess() {
+                            imageView.scaleType = ImageView.ScaleType.MATRIX
+
+                            //初始化图片的矩阵
+                            matrix.set(imageView.imageMatrix)
+
+                            /**
+                             * 初始化 将图片放在屏幕中心位置
+                             */
+                            center()
+
+                            /**
+                             * 图片设置中心之后,重新设置图片的缩放矩阵
+                             */
+                            imageView.imageMatrix = matrix
+                        }
+
+                        override fun onError(p0: java.lang.Exception?) {
+
+                        }
+                    })
+                }
+            }
+        })
+
+    }
+
+    @SuppressLint("ClickableViewAccessibility")
+    override fun initEvents() {
+
+        /**
+         * 设置ImageView的触摸事件
+         */
+        imageView.setOnTouchListener { _, event ->
+            onTouchEvent(event)
+            true
+        }
+
+        /**
+         * 初始化手势
+         * 单击  双击 长按
+         * 这三个均是手势起作用
+         * 如果想要在这三种手势中进行何种操作,
+         * 将代码放在对应的方法中即可。
+         */
+        gestureDetector = GestureDetector(OASystem.context, object : GestureDetector.SimpleOnGestureListener() {})
+
+        gestureDetector.setOnDoubleTapListener(object : OnDoubleTapListener {
+
+            /**
+             * 单击手势 会触发该方法一次
+             * 单击对应的代码应放在这里
+             */
+            override fun onSingleTapConfirmed(p0: MotionEvent): Boolean {
+
+//                this@PicturePreviewActivity.finish()
+                return false
+            }
+
+            /**
+             * 双击手势的时候 会触发该方法一次
+             * 所以双击手势对应的代码应放在这里
+             */
+            override fun onDoubleTap(motionEvent: MotionEvent): Boolean {
+
+//                pointF.x = motionEvent.x
+//                pointF.y = motionEvent.y
+//                tempMatrix.set(savedMatrix)
+//
+//                if (resetScale < 1F) {
+//                    isZoomIn = true
+//                }
+//
+//                isZoomIn = if (isZoomIn) {
+//                    tempMatrix.postScale(resetScale, resetScale, pointF.x, pointF.y)
+//                    false
+//                } else {
+//                    true
+//                }
+//
+//                matrix.set(tempMatrix)
+//                center()
+//                imageView.imageMatrix = matrix
+
+                return false
+            }
+
+            override fun onDoubleTapEvent(p0: MotionEvent): Boolean {
+
+                return false
+            }
+        })
+    }
+
+    override fun onTouchEvent(event: MotionEvent): Boolean {
+        /**
+         * 在这里调用手势的方法
+         * 这是手势和触摸事件同时使用的方法
+         */
+        if (gestureDetector.onTouchEvent(event)) {
+            return true
+        } else {
+
+            when (event.action and MotionEvent.ACTION_MASK) {
+
+                MotionEvent.ACTION_DOWN -> {
+
+                    mode = DRAG
+
+                    xDown = event.x
+                    yDown = event.y
+
+                    /**
+                     * 单个手指放下,首先保存图片的缩放矩阵到savedMatrix
+                     */
+                    savedMatrix.set(matrix)
+                }
+
+                MotionEvent.ACTION_POINTER_DOWN -> {
+
+                    mode = ZOOM
+
+                    /**
+                     * 第二个手指刚放下时
+                     * 计算两个手指间的距离
+                     */
+                    oldDist = spacing(event)
+
+                    /**
+                     * 第二个手指刚放下时
+                     * 计算两个手指间的旋转角度
+                     */
+                    oldRotation = rotation(event)
+                    savedMatrix.set(matrix)
+                    /**
+                     * 第二个手指刚放下时
+                     * 计算两个手指见的中间点坐标,并存在pointF中
+                     */
+                    midPoint(pointF, event)
+
+                }
+
+                MotionEvent.ACTION_MOVE -> {
+
+                    if (mode == ZOOM) {
+
+                        tempMatrix.set(savedMatrix)
+
+                        /**
+                         * 两个手指开始移动
+                         * 计算移动后旋转角度
+                         */
+                        newRotation = rotation(event)
+
+                        /**
+                         * 两个角度之差
+                         * 即是图片的旋转角度
+                         */
+                        rotation = newRotation - oldRotation
+
+                        /**
+                         * 计算移动后两点间的中间点
+                         */
+                        val newDist = spacing(event)
+
+                        /**
+                         * 两个中间点的商即时放大倍数
+                         */
+                        val scale = newDist / oldDist
+
+                        /**
+                         * 放大倍数的倒数即是还原图片原来大小的倍数
+                         */
+                        resetScale = oldDist / newDist
+
+                        tempMatrix.postScale(scale, scale, pointF.x, pointF.y)// 縮放
+//                        tempMatrix.postRotate(rotation, pointF.x, pointF.y)// 旋轉
+
+                        matrix.set(tempMatrix)
+
+                        /**
+                         * 调用该方法即可重新图片
+                         */
+                        imageView.imageMatrix = matrix
+
+                    } else if (mode == DRAG) {
+
+                        tempMatrix.set(savedMatrix)
+
+                        var tx = event.x - xDown
+                        var ty = event.y - yDown
+
+                        /**
+                         * 单个手指移动后的距离大于20 才算作移动
+                         */
+                        if (sqrt(tx * tx + ty * ty) > 20F) {
+
+                            /**
+                             * 设置图片宽高与屏幕宽高的大小的boolean类型的值
+                             */
+
+                            /**
+                             * 得到目前图片的宽高
+                             */
+                            val rectF = getMatrixRectF()
+
+                            /**
+                             * 图片宽度小于屏幕大小
+                             * 不移动
+                             */
+                            if (rectF.width() <= widthScreen) {
+                                tx = 0F
+                                isCheckRightAndLeft = false
+                            } else {
+                                isCheckRightAndLeft = true
+                            }
+
+                            /**
+                             * 图片高度小于屏幕高度
+                             * 不移动
+                             */
+                            if (rectF.height() <= heightScreen) {
+                                ty = 0F
+                                isCheckTopAndBottom = false
+                            } else {
+                                isCheckTopAndBottom = true
+                            }
+
+                            tempMatrix.postTranslate(tx, ty)// 平移
+
+                            /**
+                             * 如果想在拖动图片的同时检测图片边缘是否
+                             * 到达屏幕的边缘,则取消下面的注释
+                             */
+//                            checkDxDyBounds()
+                            matrix.set(tempMatrix)
+                            imageView.imageMatrix = matrix
+                        }
+                    }
+                }
+
+                MotionEvent.ACTION_UP -> {
+
+                }
+
+                MotionEvent.ACTION_POINTER_UP -> {
+
+                    if (mode == ZOOM) {
+
+                        /**
+                         * 双手放开,停止图片的旋转和缩放
+                         * Reset_scale还原图片的缩放比例
+                         */
+//                        val rectF = getMatrixRectF()
+//
+//                        if (rectF.width() < widthScreen || rectF.height() < heightScreen) {
+//
+//                            val imageRatio = rectF.width() / rectF.height()
+//
+//                            tempMatrix.postScale(widthScreen / rectF.width(), heightScreen / rectF.height() * imageRatio, pointF.x, pointF.y)
+//                        }
+//                        tempMatrix.postScale(resetScale, resetScale, pointF.x, pointF.y)
+
+                        /**
+                         * 双手放开,停止缩放、旋转图片,此时根据已旋转的角度
+                         * 计算还原图片的角度,最终的效果是把图片竖直或横平方正。
+                         */
+                        setRotate()
+                        matrix.set(tempMatrix)
+
+                        /**
+                         * 将图片放在屏幕中间位置
+                         */
+//                        center()
+
+                        imageView.imageMatrix = matrix
+                        tempMatrix.reset()
+
+                    } else if (mode == DRAG) {
+                        
+                        /**
+                         * 单手拖动图片,放开手指,停止拖动
+                         * 此时检测图片是否已经偏离屏幕边缘
+                         * 如果偏离屏幕边缘,则图片回弹
+                         */
+
+//                        checkDxDyBounds()
+
+                        matrix.set(tempMatrix)
+                        imageView.imageMatrix = matrix
+                        tempMatrix.reset()
+                    }
+
+                    mode = NONE
+
+                }
+            }
+
+            return true
+        }
+    }
+
+    /**
+     * 根据当前图片的Matrix获得图片的范围
+     * 这里获取的是当前显示的图片的大小。
+     * 图片放大后,获取的就是图片放大后的图片的大小。
+     * 图片缩小后,获取的就是图片缩小后的图片的大小。
+     *
+     * 这个大小与图片的大小是有区别的。
+     * 下面是固定用法,记住即可。
+     * @return
+     */
+    private fun getMatrixRectF(): RectF {
+        val m = matrix
+        val rect = RectF()
+        val drawable = imageView.drawable
+
+        if (drawable != null) {
+
+            rect.set(0F, 0F, drawable.intrinsicWidth.toFloat(), drawable.intrinsicHeight.toFloat())
+            m.mapRect(rect)
+        }
+
+        return rect
+    }
+
+    /**
+     * 横向、纵向 图片居中
+     */
+    private fun center() {
+        val rect = getMatrixRectF()
+        var deltaX = 0F
+        var deltaY = 0F
+        val height = rect.height()
+        val width = rect.width()
+
+        /**
+         *  图片小于屏幕大小,则居中显示。
+         *  大于屏幕,如果图片上方留空则往上移,
+         *  图片下方留空则往下移
+         */
+        val screenHeight = heightScreen
+        if (height < screenHeight) {
+
+            deltaY = (screenHeight - height) / 2 - rect.top
+
+        } else if (rect.top > 0) {
+
+            deltaY = -rect.top
+
+        } else if (rect.bottom < screenHeight) {
+
+            deltaY = imageView.height - rect.bottom
+
+        }
+
+        val screenWidth = widthScreen
+        if (width < screenWidth) {
+
+            deltaX = screenWidth - width / 2 - rect.left
+
+        } else if (rect.left > 0) {
+
+            deltaX = -rect.left
+
+        } else if (rect.right < screenWidth) {
+
+            deltaX = screenWidth - rect.right
+
+        }
+        
+        matrix.postTranslate(deltaX, deltaY)
+    }
+
+    // 触碰两点间距离
+    private fun spacing(event: MotionEvent ): Float {
+        val x = event.getX(0) - event.getX(1)
+        val y = event.getY(0) - event.getY(1)
+        return  sqrt(x * x + y * y)
+    }
+
+    // 取手势中心点
+    private fun midPoint(point: PointF, event: MotionEvent) {
+        val x = event.getX(0) + event.getX(1)
+        val y = event.getY(0) + event.getY(1)
+        point.set(x / 2, y / 2)
+    }
+
+    // 取旋转角度
+    private fun rotation(event: MotionEvent): Float {
+        val deltaX = (event.getX(0) - event.getX(1))
+        val deltaY = (event.getY(0) - event.getY(1))
+        /**
+         * 反正切函数
+         * 计算两个坐标点的正切角度
+         */
+        val radians = atan2(deltaY, deltaX).toDouble()
+        return Math.toDegrees(radians).toFloat()
+    }
+    /**
+     * 手指松开,确定旋转的角度
+     */
+    private fun setRotate(){
+
+        when(rotation) {
+            in -135F .. -90F -> {
+                tempMatrix.postRotate(-90F, pointF.x, pointF.y)
+            }
+
+            in -90F..-45F -> {
+            tempMatrix.postRotate(-90F, pointF.x, pointF.y)
+            }
+
+            in -45F.. 0F -> {
+                tempMatrix.postRotate(0F, pointF.x, pointF.y)
+            }
+
+            in 0F .. 45F -> {
+                tempMatrix.postRotate(0F, pointF.x, pointF.y)
+            }
+
+            in 45F .. 90F -> {
+                tempMatrix.postRotate(90F, pointF.x, pointF.y)
+            }
+
+            in 90F .. 135F -> {
+                tempMatrix.postRotate(90F, pointF.x, pointF.y)
+            }
+        }
+    }
+    /**
+     * 检测图片偏离屏幕两边的距离
+     * 然后平移,是图片边缘在屏幕边,
+     * 使图片周围没有空白
+     */
+    private fun checkDxDyBounds(){
+        val rectF = getMatrixRectF()
+        var dx = 0.0F
+        var dy = 0.0F
+        /**
+         * 如果图片的左侧大于零,说明图片左侧向右
+         * 偏离了左侧屏幕,则左移偏离的距离.
+         * rectF.left的值,是基于左侧坐标计算的。
+         * 图片正常情况下,该值为0.
+         * 当图片向右侧拖动以后,该值大于0.
+         * 当图片向左侧拖动以后,该值小于0.
+         */
+        if (rectF.left > 0) {
+            dx = -rectF.left
+        }
+        /**
+         * 如果图片的右侧偏离屏幕的右侧,则
+         * 图片右移图片的宽度与图片显示的宽度的差.
+         *
+         * rectF.right的值,是基于左侧计算的,图片没有缩放旋转情况下,
+         * 该值==touchImageView.getWidth()图片的宽度。
+         * 当拖动图片以后,该值变化,等于显示的图片的宽度
+         */
+        if (rectF.right < 0) {
+            dx = widthScreen - rectF.right
+        }
+        /**
+         * 当图片顶部大于0,说明图片向下偏离屏幕顶部,
+         * 则图片向上回弹偏离的距离。
+         *
+         * rectF.top的值基于顶部坐标,
+         * 图片正常情况下,该值=0.
+         */
+        if (rectF.top > 0) {
+            dy = -rectF.top
+        }
+        /**
+         * 当图片底部小于图片高度时,图片偏离屏幕底部
+         * 则图片回弹图片的高度与显示的图片的高度之差。
+         *
+         * rectF.bottom的值,基于顶部坐标。
+         * 图片正常情况下,该值=图片的高度。
+         */
+        if (rectF.bottom < 0) {
+            dy = heightScreen - rectF.bottom
+        }
+        /**
+         * 计算后,设置图片回弹
+         */
+        tempMatrix.postTranslate(dx, dy)
+    }
+}

+ 3 - 2
app/src/main/java/com/pan_american/android/ui/resource_management/service_resource/ServiceResourceSearchFragment.kt

@@ -3,6 +3,7 @@ package com.pan_american.android.ui.resource_management.service_resource
 import android.content.Context
 import android.os.Bundle
 import android.view.LayoutInflater
+import android.view.View
 import android.view.ViewGroup
 import android.view.inputmethod.InputMethodManager
 import com.pan_american.android.R
@@ -15,8 +16,8 @@ class ServiceResourceSearchFragment : BaseFragment<FragmentServiceResourceSearch
         inflater: LayoutInflater, container: ViewGroup?, bundle: Bundle?
     ) = FragmentServiceResourceSearchBinding.inflate(layoutInflater, container, false)
 
-    override fun onStart() {
-        super.onStart()
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
 
         initViews()
         initEvents()

+ 22 - 1
app/src/main/java/com/pan_american/android/ui/workspace/WorkspaceFragment.kt

@@ -23,6 +23,7 @@ import com.pan_american.android.ui.group_common.insurance_payment_insert.Insuran
 import com.pan_american.android.ui.group_hotel.hotel_predetermine.HotelPredetermineActivity
 import com.pan_american.android.ui.group_invite_official.invite_data.InviteDataActivity
 import com.pan_american.android.ui.group_invite_official.invite_official_payment_insert.InviteOfficialPaymentInsertActivity
+import com.pan_american.android.ui.group_invite_official.official_visits.InviteVisitsActivity
 import com.pan_american.android.ui.group_management.group_info.GroupInfoActivity
 import com.pan_american.android.ui.group_op.ground_convey_payment_insert.GroundConveyPaymentInsertActivity
 import com.pan_american.android.ui.group_visa.visa_payment_insert.VisaPaymentInsertActivity
@@ -136,7 +137,11 @@ class WorkspaceFragment : BaseFragment<FragmentWorkspaceBinding>(), OnClickListe
                 }
 
                 OASystem.GROUND_CONVEY_PAYMENT_INSERT -> {
-                    if (OASystem.authorization(OASystem.GROUND_CONVEY_PAYMENT_INSERT, OASystem.VIEW)) {
+                    if (OASystem.authorization(
+                            OASystem.GROUND_CONVEY_PAYMENT_INSERT,
+                            OASystem.VIEW
+                        )
+                    ) {
                         if (binding.groupOp.visibility == View.GONE) {
                             binding.groupOp.visibility = View.VISIBLE
                         }
@@ -166,6 +171,16 @@ class WorkspaceFragment : BaseFragment<FragmentWorkspaceBinding>(), OnClickListe
                     }
                 }
 
+                OASystem.OFFICIAL_VISITS -> {
+                    if (OASystem.authorization(OASystem.OFFICIAL_VISITS, OASystem.VIEW)) {
+                        if (binding.groupInviteOfficial.visibility == View.GONE) {
+                            binding.groupInviteOfficial.visibility = View.VISIBLE
+                        }
+                        binding.officialVisits.visibility = View.VISIBLE
+                        binding.officialVisits.setOnClickListener(this)
+                    }
+                }
+
                 //团组经理主管
                 OASystem.GROUP_INFORMATION -> {
                     if (OASystem.authorization(OASystem.GROUP_INFORMATION, OASystem.VIEW)) {
@@ -250,6 +265,7 @@ class WorkspaceFragment : BaseFragment<FragmentWorkspaceBinding>(), OnClickListe
                         binding.airplaneThreeCode.setOnClickListener(this)
                     }
                 }
+
                 OASystem.AIRPLANE_PAYMENT_INSERT -> {
                     if (OASystem.authorization(OASystem.AIRPLANE_PAYMENT_INSERT, OASystem.VIEW)) {
                         if (binding.groupAirplaneTicket.visibility == View.GONE) {
@@ -320,6 +336,11 @@ class WorkspaceFragment : BaseFragment<FragmentWorkspaceBinding>(), OnClickListe
                 startActivity(intent)
             }
 
+            binding.officialVisits.id -> {
+                val intent = Intent(OASystem.context, InviteVisitsActivity::class.java)
+                startActivity(intent)
+            }
+
             binding.groupOperation.id -> {
                 val intent = Intent(OASystem.context, GroupInfoActivity::class.java)
                 startActivity(intent)

+ 2 - 2
app/src/main/res/layout/activity_add_airplane_ticket.xml

@@ -20,9 +20,9 @@
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginStart="@dimen/common_padding_heavy"
+            android:layout_marginStart="@dimen/common_padding"
             android:layout_marginTop="@dimen/common_padding"
-            android:layout_marginEnd="@dimen/common_padding_heavy"
+            android:layout_marginEnd="@dimen/common_padding"
             android:orientation="vertical">
 
             <LinearLayout

File diff suppressed because it is too large
+ 1031 - 0
app/src/main/res/layout/activity_add_official_visits.xml


+ 319 - 0
app/src/main/res/layout/activity_invite_visits.xml

@@ -0,0 +1,319 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/main"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".ui.group_invite_official.official_visits.InviteVisitsActivity">
+
+    <include
+        layout="@layout/layout_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/common_padding"
+        android:layout_marginTop="@dimen/common_padding_huge"
+        android:layout_marginEnd="@dimen/common_padding"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:text="@string/group_name"
+            android:textSize="@dimen/text_size_medium" />
+
+        <TextView
+            android:id="@+id/group_name_selector"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/common_padding"
+            android:layout_weight="1"
+            android:background="@color/white"
+            android:gravity="end"
+            android:hint="@string/please_select"
+            android:singleLine="true"
+            android:textColor="@color/text_color"
+            android:textColorHint="@color/hint_text_color"
+            android:textSize="@dimen/text_size_medium" />
+    </LinearLayout>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/line"
+        android:layout_marginTop="@dimen/common_padding"
+        android:layout_marginBottom="@dimen/common_padding"
+        android:background="@color/line_color" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@color/white"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/common_padding"
+            android:layout_marginEnd="@dimen/common_padding">
+
+            <TextView
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="@string/group_base_info"
+                android:textColor="@color/text_color_blue"
+                android:textSize="@dimen/text_size_large"
+                android:textStyle="bold" />
+
+            <TextView
+                android:id="@+id/base_info_switch"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:text="@string/show"
+                android:textColor="@color/title_background_color"
+                android:textSize="@dimen/text_size_medium" />
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginStart="@dimen/common_padding"
+            android:layout_marginTop="@dimen/common_padding"
+            android:layout_marginEnd="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:id="@+id/group_base_info"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="@dimen/common_padding"
+            android:orientation="vertical"
+            android:visibility="gone">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:text="@string/group_customer"
+                    android:textSize="@dimen/text_size_medium" />
+
+                <TextView
+                    android:id="@+id/group_customer"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_gravity="center"
+                    android:layout_marginStart="@dimen/common_padding"
+                    android:gravity="end"
+                    android:hint="@string/no_info"
+                    android:textColorHint="@color/hint_text_color" />
+            </LinearLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/line"
+                android:layout_marginTop="@dimen/common_padding"
+                android:layout_marginBottom="@dimen/common_padding"
+                android:background="@color/line_color" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:text="@string/visit_country"
+                    android:textSize="@dimen/text_size_medium" />
+
+                <TextView
+                    android:id="@+id/visit_country"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_gravity="center"
+                    android:layout_marginStart="@dimen/common_padding"
+                    android:background="@color/white"
+                    android:gravity="end"
+                    android:hint="@string/no_info"
+                    android:textColorHint="@color/hint_text_color" />
+            </LinearLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/line"
+                android:layout_marginTop="@dimen/common_padding"
+                android:layout_marginBottom="@dimen/common_padding"
+                android:background="@color/line_color" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:text="@string/visit_days"
+                    android:textSize="@dimen/text_size_medium" />
+
+                <TextView
+                    android:id="@+id/visit_days"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_gravity="center"
+                    android:layout_marginStart="@dimen/common_padding"
+                    android:background="@color/white"
+                    android:gravity="end"
+                    android:hint="@string/no_info"
+                    android:singleLine="true"
+                    android:textColorHint="@color/hint_text_color"
+                    android:textSize="@dimen/text_size_medium" />
+            </LinearLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/line"
+                android:layout_marginTop="@dimen/common_padding"
+                android:layout_marginBottom="@dimen/common_padding"
+                android:background="@color/line_color" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:text="@string/visit_members"
+                    android:textSize="@dimen/text_size_medium" />
+
+                <TextView
+                    android:id="@+id/visit_members"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_gravity="center"
+                    android:layout_marginStart="@dimen/common_padding"
+                    android:background="@color/white"
+                    android:gravity="end"
+                    android:hint="@string/no_info"
+                    android:singleLine="true"
+                    android:textColorHint="@color/hint_text_color"
+                    android:textSize="@dimen/text_size_medium" />
+            </LinearLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/line"
+                android:layout_marginTop="@dimen/common_padding"
+                android:layout_marginBottom="@dimen/common_padding"
+                android:background="@color/line_color" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:text="@string/during_time"
+                    android:textSize="@dimen/text_size_medium" />
+
+                <TextView
+                    android:id="@+id/during_time"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_gravity="center"
+                    android:layout_marginStart="@dimen/common_padding"
+                    android:background="@color/white"
+                    android:gravity="end"
+                    android:hint="@string/no_info"
+                    android:textColorHint="@color/hint_text_color" />
+            </LinearLayout>
+        </LinearLayout>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:background="@color/background_color"
+        android:layout_weight="1"
+        android:orientation="vertical">
+
+        <com.scwang.smart.refresh.layout.SmartRefreshLayout
+            android:id="@+id/official_visits_container"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_margin="@dimen/common_padding"
+            app:srlEnablePreviewInEditMode="true">
+
+            <com.scwang.smart.refresh.header.ClassicsHeader
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/official_visits_list"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:overScrollMode="never" />
+
+            <com.scwang.smart.refresh.footer.ClassicsFooter
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+
+        </com.scwang.smart.refresh.layout.SmartRefreshLayout>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/province_request_data"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_margin="@dimen/common_padding"
+            android:layout_weight="1"
+            android:background="@drawable/shape_corner_solid_blue"
+            android:gravity="center"
+            android:padding="@dimen/common_padding_small"
+            android:text="@string/province_request_data"
+            android:textColor="@color/white"
+            android:textSize="@dimen/text_size_medium" />
+
+        <TextView
+            android:id="@+id/city_request_data"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_margin="@dimen/common_padding"
+            android:layout_weight="1"
+            android:background="@drawable/shape_corner_solid_blue"
+            android:gravity="center"
+            android:padding="@dimen/common_padding_small"
+            android:text="@string/city_request_data"
+            android:textColor="@color/white"
+            android:textSize="@dimen/text_size_medium" />
+
+    </LinearLayout>
+
+</LinearLayout>

+ 35 - 0
app/src/main/res/layout/activity_picture_preview.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/main"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/black"
+    android:orientation="vertical"
+    tools:context=".ui.picture_preview.PicturePreviewActivity">
+
+    <include
+        layout="@layout/layout_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <androidx.appcompat.widget.AppCompatImageView
+        android:id="@+id/image_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scaleType="fitCenter"
+        android:adjustViewBounds="true" />
+
+<!--    <TextView-->
+<!--        android:id="@+id/image_name"-->
+<!--        android:layout_width="match_parent"-->
+<!--        android:layout_height="wrap_content"-->
+<!--        android:layout_marginTop="@dimen/common_padding_huge"-->
+<!--        android:layout_marginBottom="@dimen/common_padding_huge"-->
+<!--        android:gravity="center"-->
+<!--        android:padding="@dimen/common_padding_large"-->
+<!--        android:textColor="@color/white"-->
+<!--        android:textSize="@dimen/text_size_large"-->
+<!--        android:textStyle="bold" />-->
+
+</LinearLayout>

+ 33 - 0
app/src/main/res/layout/fragment_workspace.xml

@@ -566,6 +566,39 @@
                             android:textSize="@dimen/text_size_medium"
                             app:drawableStartCompat="@mipmap/icon_invite_official_payment" />
 
+                        <View
+                            android:layout_width="match_parent"
+                            android:layout_height="1dp"
+                            android:layout_marginStart="35dp"
+                            android:background="@color/line_color" />
+
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:id="@+id/official_visits"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:visibility="gone">
+
+                        <TextView
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:drawablePadding="@dimen/common_padding"
+                            android:gravity="center_vertical"
+                            android:paddingTop="@dimen/common_padding"
+                            android:paddingBottom="@dimen/common_padding"
+                            android:text="@string/official_visits"
+                            android:textColor="@color/text_color"
+                            android:textSize="@dimen/text_size_medium"
+                            app:drawableStartCompat="@mipmap/icon_official_visits" />
+
+                        <View
+                            android:layout_width="match_parent"
+                            android:layout_height="1dp"
+                            android:layout_marginStart="35dp"
+                            android:background="@color/line_color" />
+
                     </LinearLayout>
 
                 </LinearLayout>

+ 6 - 7
app/src/main/res/layout/item_guide_and_car_list.xml

@@ -15,7 +15,7 @@
         android:layout_margin="@dimen/common_padding"
         android:orientation="vertical">
 
-        <RelativeLayout
+        <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="@dimen/common_padding"
@@ -23,10 +23,10 @@
 
             <TextView
                 android:id="@+id/supplier_name"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginEnd="50dp"
-                android:layout_toStartOf="@id/delete"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_marginEnd="@dimen/common_padding_heavy"
+                android:layout_weight="1"
                 android:textColor="@color/text_color_blue"
                 android:textSize="@dimen/text_size_medium"
                 android:textStyle="bold" />
@@ -35,12 +35,11 @@
                 android:id="@+id/delete"
                 android:layout_width="@dimen/common_padding_heavy"
                 android:layout_height="@dimen/common_padding_heavy"
-                android:layout_alignParentEnd="true"
                 android:layout_marginEnd="@dimen/common_padding"
                 android:src="@mipmap/icon_delete"
                 tools:ignore="ContentDescription" />
 
-        </RelativeLayout>
+        </LinearLayout>
 
         <View
             android:layout_width="match_parent"

+ 32 - 0
app/src/main/res/layout/item_image_preview.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <androidx.appcompat.widget.AppCompatImageView
+        android:id="@+id/image_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/common_padding"
+        android:scaleType="fitCenter"
+        android:adjustViewBounds="true" />
+
+    <TextView
+        android:id="@+id/image_name"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/common_padding_huge"
+        android:gravity="center"
+        android:padding="@dimen/common_padding_large"
+        android:textColor="@color/text_color"
+        android:textSize="@dimen/text_size_medium"
+        android:textStyle="bold" />
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="@color/line_color"
+        android:layout_margin="@dimen/common_padding" />
+
+</LinearLayout>

+ 172 - 0
app/src/main/res/layout/item_official_visits_list.xml

@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginTop="@dimen/common_padding"
+    android:layout_marginBottom="@dimen/common_padding"
+    android:background="@drawable/shape_corner_stroke_white"
+    android:orientation="vertical"
+    tools:viewBindingIgnore="true">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/common_padding"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:id="@+id/official_department"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:layout_marginEnd="@dimen/common_padding_heavy"
+                android:textColor="@color/text_color_blue"
+                android:textSize="@dimen/text_size_medium"
+                android:textStyle="bold" />
+
+            <ImageView
+                android:id="@+id/delete"
+                android:layout_width="@dimen/common_padding_heavy"
+                android:layout_height="@dimen/common_padding_heavy"
+                android:layout_marginEnd="@dimen/common_padding"
+                android:src="@mipmap/icon_delete"
+                tools:ignore="ContentDescription" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/official_time"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:id="@+id/official_time"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/contacts"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:id="@+id/contacts_name"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/creator"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:id="@+id/creator"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/line"
+            android:layout_marginTop="@dimen/common_padding_huge"
+            android:layout_marginBottom="@dimen/common_padding"
+            android:background="@color/line_color" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:layout_marginBottom="@dimen/common_padding_huge"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/create_time"
+                android:textSize="@dimen/text_size_medium" />
+
+            <TextView
+                android:id="@+id/create_time"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:background="@color/white"
+                android:gravity="end"
+                android:singleLine="true"
+                android:textSize="@dimen/text_size_medium" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+</LinearLayout>

+ 62 - 0
app/src/main/res/layout/popup_recycler_view.xml

@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/shape_corner_white"
+    android:orientation="vertical"
+    tools:viewBindingIgnore="true">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/common_padding"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/recycler_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:text="@string/please_select"
+            android:textColor="@color/text_color"
+            android:textSize="@dimen/text_size_large" />
+
+    </LinearLayout>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/line"
+        android:layout_margin="@dimen/common_padding"
+        android:background="@color/line_color" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/recycler_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_margin="@dimen/common_padding"/>
+
+<!--    <LinearLayout-->
+<!--        android:layout_width="match_parent"-->
+<!--        android:layout_height="wrap_content"-->
+<!--        android:layout_marginTop="@dimen/common_padding"-->
+<!--        android:layout_marginBottom="@dimen/common_padding"-->
+<!--        android:orientation="horizontal">-->
+
+<!--        <TextView-->
+<!--            android:id="@+id/commit"-->
+<!--            android:layout_width="match_parent"-->
+<!--            android:layout_height="@dimen/button_height"-->
+<!--            android:layout_marginStart="@dimen/common_padding_huge"-->
+<!--            android:layout_marginEnd="@dimen/common_padding_huge"-->
+<!--            android:layout_marginBottom="@dimen/common_padding"-->
+<!--            android:background="@drawable/shape_corner_solid_blue"-->
+<!--            android:gravity="center"-->
+<!--            android:text="@string/confirm"-->
+<!--            android:textColor="@color/white"-->
+<!--            android:textSize="@dimen/text_size_large"-->
+<!--            android:textStyle="bold" />-->
+
+<!--    </LinearLayout>-->
+
+</LinearLayout>

二進制
app/src/main/res/mipmap-xxhdpi/icon_official_visits.png


+ 63 - 2
app/src/main/res/values/strings.xml

@@ -1007,7 +1007,7 @@
     <string name="payment_plate">费用板块</string>
 
     <string name="download_this_model_bill">下载此模块票据</string>
-    
+
     <string name="download_all_model_bill">下载所有票据</string>
 
     <string name="payment_plate_get_error">费用板块获取失败</string>
@@ -1019,9 +1019,70 @@
     <string name="bill_file_all_model_download_hint">是否下载该团组所有模块票据? \n\n当前团组: %s</string>
 
     <string name="bill_file_this_model_download_hint">是否下载该团组当前模块所有票据? \n\n当前团组: %s \n\n当前模块: %s</string>
-    
+
     <string name="bill_file_delete_hint">确认删除文档: %s ?</string>
 
+    <!-- 公务出访 -->
+    <string name="official_visits">公务出访</string>
+    <string name="official_visits_list_get_error">公务出访列表获取失败</string>
+
+    <string name="province_request_data">省外办请示文件</string>
+    <string name="city_request_data">市外办请示文件</string>
+
+    <string name="request_data_download_hint">团组名称: %S \n\n文件类型: %S \n\n点击确认前往下载</string>
+
+    <string name="add_official_visits">新增公务出访数据</string>
+    <string name="update_official_visits">公务出访数据修改</string>
+    <string name="official_time">公务时间</string>
+    <string name="official_department">公务单位</string>
+    <string name="official_date">公务日期</string>
+    <string name="invitor">邀请方</string>
+    <string name="official_contact_job">公务方联系人职务</string>
+    <string name="official_contact">公务方联系人</string>
+    <string name="official_type">公务形式</string>
+    <string name="dress_demand">着装要求</string>
+    <string name="need_translator">需要翻译</string>
+    <string name="translator">翻译人员</string>
+    <string name="translate_language">翻译语种</string>
+    <string name="is_approval">是否报批</string>
+    <string name="official_location">公务地址</string>
+    <string name="official_background">公务方背景</string>
+    <string name="official_request_example">公务请示范例</string>
+    <string name="provisional_agenda">暂定议程</string>
+    <string name="participation_member">参会人员</string>
+    <string name="email_screenshot">邮件截图</string>
+
+    <string name="check_commit">复核确认</string>
+
+    <string name="gallery_permission_hint">请在设置中打开文件访问权限</string>
+
+    <string name="country_input_hint">请输入国家</string>
+    <string name="area_input_hint">请输入地区</string>
+    <string name="official_department_input_hint">请输入公务单位</string>
+    <string name="official_date_select_hint">请选择公务日期</string>
+    <string name="official_time_select_hint">请选择公务时间</string>
+    <string name="invitor_select_hint">请选择邀请方</string>
+    <string name="official_contact_job_input_hint">请输入公务方联系人职务</string>
+    <string name="official_contact_input_hint">请输入公务方联系人</string>
+    <string name="phone_input_hint">请输入联系电话</string>
+    <string name="official_type_select_hint">请选择公务形式</string>
+    <string name="official_dress_demand_input_hint">请输入着装要求</string>
+    <string name="official_industry_input_hint">请输入涉及领域</string>
+    <string name="translate_language_input_hint">请输入翻译语种</string>
+    <string name="official_location_input_hint">请输入公务地址</string>
+    <string name="official_background_input_hint">请输入公务方背景</string>
+    <string name="picture_upload_hint">请上传图片</string>
+
+    <string name="picture_select_error_hint">图片路径获取失败,请从系统图片选择器选择图片</string>
+    <string name="picture_upload_error">图片文件上传错误</string>
+    <string name="official_visit_detail_get_error">公务出访详情获取错误</string>
+
+    <string name="picture_uploaded_delete_hint">是否删除图片: %s ? \n\n此文件已上传至服务器此操作将永久删除该文件, 该操作不可逆, 是否继续?</string>
+
+    <!-- 图片预览 -->
+    <string name="picture_preview">图片预览</string>
+    <string name="picture_load_error">图片加载失败</string>
+
     <!-- TODO: Remove or change this placeholder text -->
     <string name="hello_blank_fragment">Hello blank fragment</string>
 

+ 2 - 1
app/src/main/res/xml/file_paths.xml

@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<paths xmlns:android="http://schemas.android.com/apk/res/android">
+<paths>
     <external-path name="my_images" path="/" />
+    <external-path name="external_files" path="." />
 </paths>

+ 11 - 0
settings.gradle

@@ -4,6 +4,12 @@ pluginManagement {
         jcenter()
         mavenCentral()
         gradlePluginPortal()
+        maven { url 'https://jitpack.io' }
+        maven { url 'https://maven.aliyun.com/repository/releases' }
+        maven { url 'https://maven.aliyun.com/repository/google' }
+        maven { url 'https://maven.aliyun.com/repository/central' }
+        maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
+        maven { url 'https://maven.aliyun.com/repository/public' }
     }
 }
 dependencyResolutionManagement {
@@ -13,6 +19,11 @@ dependencyResolutionManagement {
         jcenter()
         mavenCentral()
         maven {url 'https://jitpack.io'}
+        maven { url 'https://maven.aliyun.com/repository/releases'}
+        maven { url 'https://maven.aliyun.com/repository/google' }
+        maven { url 'https://maven.aliyun.com/repository/central' }
+        maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
+        maven { url 'https://maven.aliyun.com/repository/public' }
     }
 }
 rootProject.name = "OASystem"