Browse Source

2024-07-01 新增

新增

1. 完成市场部营业额-团组列表-拜访记录页面绘制
2. 完成市场部营业额-团组列表-拜访记录接口对接
3. 绘制市场部营业额-团组列表-拜访记录添加界面
4. 市场部营业额-团组列表-拜访记录添加界面接口对接

修改:

1. 部分界面UI逻辑调整
2. BUG修改,代码优化
zhaiy 9 months ago
parent
commit
d23ec60dc3

+ 14 - 5
app/src/main/AndroidManifest.xml

@@ -26,21 +26,30 @@
         android:supportsRtl="true"
         android:theme="@style/AppTheme"
         tools:targetApi="31">
+        <activity
+            android:name=".ui.customer_resource.market_sales_revenue.AddCustomerVisitHistoryActivity"
+            android:exported="false"
+            android:launchMode="singleTop"/>
         <activity
             android:name=".ui.customer_resource.market_sales_revenue.SalesCustomerVisitListActivity"
-            android:exported="false" />
+            android:exported="false"
+            android:launchMode="singleTop"/>
         <activity
             android:name=".ui.customer_resource.market_sales_revenue.MarketSalesRevenueActivity"
-            android:exported="false" />
+            android:exported="false"
+            android:launchMode="singleTop"/>
         <activity
             android:name=".ui.document.DocumentGroupListActivity"
-            android:exported="false" />
+            android:exported="false"
+            android:launchMode="singleTop"/>
         <activity
             android:name=".ui.group_invite_official.invite_data.AddInviteDataActivity"
-            android:exported="false" />
+            android:exported="false"
+            android:launchMode="singleTop"/>
         <activity
             android:name=".ui.group_invite_official.invite_data.InviteDataActivity"
-            android:exported="false" />
+            android:exported="false"
+            android:launchMode="singleTop"/>
         <activity
             android:name=".ui.message.MessageListActivity"
             android:exported="false"

+ 36 - 2
app/src/main/java/com/pan_american/android/base/BaseActivity.kt

@@ -13,6 +13,7 @@ import android.view.inputmethod.InputMethodManager
 import android.widget.DatePicker
 import android.widget.PopupWindow
 import android.widget.TextView
+import android.widget.TimePicker
 import android.widget.Toast
 import androidx.activity.OnBackPressedCallback
 import androidx.appcompat.app.AppCompatActivity
@@ -189,7 +190,7 @@ abstract class BaseActivity<T: ViewBinding>: AppCompatActivity() {
     fun showDatePicker(text: String, textView: TextView, block: () -> Unit) {
         val calendar = Calendar.getInstance()
         val popView = View.inflate(OASystem.context, R.layout.popup_date_selector, null)
-        popupWindow = PopupWindow(popView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+        popupWindow = PopupWindow(popView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
 
         showPopupWindow {
 
@@ -210,11 +211,44 @@ abstract class BaseActivity<T: ViewBinding>: AppCompatActivity() {
 
             commit.setOnClickListener {
                 textView.text = date
+                popupWindow.dismiss()
                 block()
+            }
+
+            popupWindow.showAtLocation(binding.root, Gravity.BOTTOM, 0, 0)
+        }
+    }
+
+    /**
+     * 弹出时间选择组件
+     */
+    fun showTimePicker(text: String, textView: TextView, block: () -> Unit) {
+        val popView = View.inflate(OASystem.context, R.layout.popup_time_selector, null)
+        popupWindow = PopupWindow(popView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+
+        showPopupWindow {
+
+            val title = popView.findViewById<TextView>(R.id.time_selector_name)
+            val timePicker = popView.findViewById<TimePicker>(R.id.time_selector)
+            val commit = popView.findViewById<TextView>(R.id.commit)
+
+            var timeHour = timePicker.hour
+            var timeMinute = timePicker.minute
+
+            title.text = text
+
+            timePicker.setOnTimeChangedListener { _, hour, minute ->
+                timeHour = hour
+                timeMinute = minute
+            }
+
+            commit.setOnClickListener {
+                textView.text = String.format(resources.getString(R.string.time_format), timeHour, timeMinute)
                 popupWindow.dismiss()
+                block()
             }
 
-            popupWindow.showAtLocation(binding.root, Gravity.CENTER, 0, 0)
+            popupWindow.showAtLocation(binding.root, Gravity.BOTTOM, 0, 0)
         }
     }
 

+ 1 - 1
app/src/main/java/com/pan_american/android/data/model/customer_resource/market_sales_revenue/entity/VisitHistoryListItem.kt

@@ -2,7 +2,7 @@ package com.pan_american.android.data.model.customer_resource.market_sales_reven
 
 class VisitHistoryListItem {
     var id = 0
-    var diid = 0
+    var diId = 0
     var beginDt = ""
     var endDt = ""
     var customerUnit = ""

+ 19 - 0
app/src/main/java/com/pan_american/android/data/model/customer_resource/market_sales_revenue/network/MarketSalesAddVisitHistoryRequest.kt

@@ -0,0 +1,19 @@
+package com.pan_american.android.data.model.customer_resource.market_sales_revenue.network
+
+import com.pan_american.android.OASystem
+import com.pan_american.android.base.BaseRequest
+
+class MarketSalesAddVisitHistoryRequest(): BaseRequest() {
+    val userId = OASystem.userInfo.userId
+    val pageId = OASystem.MARKET_SALES_REVENUE
+
+    var id = 0
+    var diId = 0
+    var customerName = ""
+    var customerUnit = ""
+    var customerJob = ""
+    var customerContact = ""
+    var beginDt = ""
+    var endDt = ""
+    var remark = ""
+}

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

@@ -31,6 +31,7 @@ import com.pan_american.android.data.model.customer_resource.company_customer.ne
 import com.pan_american.android.data.model.customer_resource.company_customer.network.MarketCustomerRequest
 import com.pan_american.android.data.model.customer_resource.company_customer.network.MarketCustomerResponse
 import com.pan_american.android.data.model.customer_resource.company_customer.network.MarketCustomerSiftListResponse
+import com.pan_american.android.data.model.customer_resource.market_sales_revenue.network.MarketSalesAddVisitHistoryRequest
 import com.pan_american.android.data.model.customer_resource.market_sales_revenue.network.MarketSalesGroupListResponse
 import com.pan_american.android.data.model.customer_resource.market_sales_revenue.network.MarketSalesOrderRankResponse
 import com.pan_american.android.data.model.customer_resource.market_sales_revenue.network.MarketSalesRevenueBaseRequest
@@ -847,4 +848,10 @@ interface APIService {
      */
     @POST("api/Statistics/PostMarketingSalesVCDel")
     fun deleteMarketSalesVisitHistory(@Body deleteRequest: DeleteRequest): Call<BaseResponse>
+
+    /**
+     * 市场营业额,团组列表-添加/修改拜访记录
+     */
+    @POST("api/Statistics/PostMarketingSalesVCOperate")
+    fun updateMarketSalesVisitHistory(@Body marketSalesAddVisitHistoryRequest: MarketSalesAddVisitHistoryRequest): Call<BaseResponse>
 }

+ 239 - 0
app/src/main/java/com/pan_american/android/ui/customer_resource/market_sales_revenue/AddCustomerVisitHistoryActivity.kt

@@ -0,0 +1,239 @@
+package com.pan_american.android.ui.customer_resource.market_sales_revenue
+
+import android.os.Bundle
+import androidx.core.view.isNotEmpty
+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.data.model.customer_resource.market_sales_revenue.network.MarketSalesAddVisitHistoryRequest
+import com.pan_american.android.data.network.APIService
+import com.pan_american.android.data.network.ServiceCreator
+import com.pan_american.android.databinding.ActivityAddCustomerVisitHistoryBinding
+import com.pan_american.android.databinding.LayoutTitleBinding
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+
+class AddCustomerVisitHistoryActivity : BaseActivity<ActivityAddCustomerVisitHistoryBinding>() {
+
+    private lateinit var titleBinding: LayoutTitleBinding
+
+    private var fromList = false
+
+    private val apiService = ServiceCreator.create<APIService>()
+
+    private val marketSalesAddVisitHistoryRequest = MarketSalesAddVisitHistoryRequest()
+
+    private var startDateSelect = false
+
+    private var startTimeSelect = false
+
+    private var endDateSelect = false
+
+    private var endTimeSelect = false
+
+    override fun getViewBinding() = ActivityAddCustomerVisitHistoryBinding.inflate(layoutInflater)
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        intent.apply {
+            fromList = getBooleanExtra("fromList", false)
+            marketSalesAddVisitHistoryRequest.diId = getIntExtra("diId", 0)
+
+            if (fromList) {
+
+                marketSalesAddVisitHistoryRequest.id = getIntExtra("id", 0)
+
+                binding.clientName.setText(getStringExtra("customer_name"))
+                binding.customerCompany.setText(getStringExtra("customer_company"))
+                binding.clientJob.setText(getStringExtra("customer_job"))
+                binding.contractWay.setText(getStringExtra("customer_contact_way"))
+                binding.visitStartTime.text = getStringExtra("start_time")
+                binding.visitEndTime.text = getStringExtra("end_time")
+                binding.notes.setText(getStringExtra("remark").toString())
+
+                startDateSelect = true
+                startTimeSelect = true
+                endDateSelect = true
+                endTimeSelect = true
+            }
+        }
+
+        initTitle()
+        initViews()
+        initEvents()
+    }
+
+    override fun initTitle() {
+        titleBinding = LayoutTitleBinding.bind(binding.root).apply {
+            titleText.text = if (fromList) {
+                resources.getString(R.string.add_visit_history)
+            } else {
+                resources.getString(R.string.visit_history_detail)
+            }
+
+            backButton.setOnClickListener {
+                back()
+            }
+        }
+    }
+
+    override fun initViews() {
+        if (fromList) {
+            if (canBeEdit()) {
+                binding.commit.setText(resources.getString(R.string.update))
+            } else {
+
+                binding.clientName.isEnabled = false
+                binding.customerCompany.isEnabled = false
+                binding.clientJob.isEnabled = false
+                binding.contractWay.isEnabled = false
+                binding.visitStartTime.isEnabled = false
+                binding.visitEndTime.isEnabled = false
+                binding.notes.isEnabled(false)
+
+                binding.commit.setText(resources.getString(R.string.back))
+            }
+
+        } else {
+            binding.commit.setText(resources.getString(R.string.add))
+        }
+    }
+
+    override fun initEvents() {
+        binding.visitStartTime.setOnClickListener {
+
+            var date: String
+
+            var time: String
+
+            showDatePicker(resources.getString(R.string.start_time), binding.visitStartTime){
+                date = binding.visitStartTime.text.toString()
+
+                startDateSelect = true
+
+                showTimePicker(resources.getString(R.string.start_time), binding.visitStartTime) {
+
+                    time = binding.visitStartTime.text.toString()
+
+                    startTimeSelect = true
+
+                    binding.visitStartTime.text = String.format(resources.getString(R.string.with_space_format), date, time)
+                }
+            }
+        }
+
+        binding.visitEndTime.setOnClickListener {
+
+            var date: String
+
+            var time: String
+
+            showDatePicker(resources.getString(R.string.start_time), binding.visitEndTime){
+                date = binding.visitEndTime.text.toString()
+
+                endDateSelect = true
+
+                showTimePicker(resources.getString(R.string.start_time), binding.visitEndTime) {
+
+                    time = binding.visitEndTime.text.toString()
+
+                    endTimeSelect = true
+
+                    binding.visitEndTime.text = String.format(resources.getString(R.string.with_space_format), date, time)
+                }
+            }
+        }
+
+        binding.commit.setOnClickListener {
+            if (!canBeEdit()) {
+                back()
+                return@setOnClickListener
+            }
+
+            if (binding.clientName.text.isNullOrBlank()) {
+                showMessage(resources.getString(R.string.client_name_hint))
+                return@setOnClickListener
+            } else {
+                marketSalesAddVisitHistoryRequest.customerName = binding.clientName.text.toString()
+            }
+
+            if (binding.customerCompany.text.isNullOrBlank()) {
+                showMessage(resources.getString(R.string.customer_company_hint))
+                return@setOnClickListener
+            } else {
+                marketSalesAddVisitHistoryRequest.customerUnit = binding.customerCompany.text.toString()
+            }
+
+            if (binding.clientJob.text.isNullOrBlank()) {
+                showMessage(resources.getString(R.string.customer_job_hint))
+                return@setOnClickListener
+            } else {
+                marketSalesAddVisitHistoryRequest.customerJob = binding.clientJob.text.toString()
+            }
+
+            if (binding.contractWay.text.isNullOrBlank()) {
+                showMessage(resources.getString(R.string.customer_contact_way_hint))
+                return@setOnClickListener
+            } else {
+                marketSalesAddVisitHistoryRequest.customerContact = binding.contractWay.text.toString()
+            }
+
+            if (!startDateSelect || !startTimeSelect) {
+                showMessage(resources.getString(R.string.start_time_select_error))
+                return@setOnClickListener
+            } else {
+                marketSalesAddVisitHistoryRequest.beginDt = binding.visitStartTime.text.toString()
+            }
+
+            if (!endDateSelect || !endTimeSelect) {
+                showMessage(resources.getString(R.string.end_time_select_error))
+                return@setOnClickListener
+            } else {
+                marketSalesAddVisitHistoryRequest.endDt = binding.visitEndTime.text.toString()
+            }
+
+            if (binding.notes.isNotEmpty()) {
+                marketSalesAddVisitHistoryRequest.remark = binding.notes.getText()
+            }
+
+            updateVisitHistory()
+        }
+    }
+
+    private fun canBeEdit(): Boolean {
+        return OASystem.authorization(OASystem.MARKET_SALES_REVENUE, OASystem.EDIT)
+    }
+
+    private fun updateVisitHistory() {
+
+        apiService.updateMarketSalesVisitHistory(marketSalesAddVisitHistoryRequest).enqueue(object : Callback<BaseResponse> {
+            override fun onResponse(p0: Call<BaseResponse>, response: Response<BaseResponse>) {
+
+                val updateResponse = response.body()
+
+                if (updateResponse != null) {
+                    if (updateResponse.code == 200) {
+                        if (fromList) {
+                            showMessage(resources.getString(R.string.update_success))
+                        } else {
+                            showMessage(resources.getString(R.string.insert_success))
+                        }
+
+                        OASystem.needRefresh = true
+
+                        back()
+                    } else {
+                        showMessage(updateResponse.msg)
+                    }
+                }
+            }
+
+            override fun onFailure(p0: Call<BaseResponse>, p1: Throwable) {
+                showErrorInfo(R.string.update_error)
+            }
+        })
+    }
+}

+ 87 - 38
app/src/main/java/com/pan_american/android/ui/customer_resource/market_sales_revenue/SalesCustomerVisitListActivity.kt

@@ -1,9 +1,12 @@
 package com.pan_american.android.ui.customer_resource.market_sales_revenue
 
+import android.content.Intent
 import android.os.Bundle
+import android.util.Log
 import android.view.View
 import android.widget.TextView
 import androidx.recyclerview.widget.LinearLayoutManager
+import com.google.gson.Gson
 import com.pan_american.android.OASystem
 import com.pan_american.android.R
 import com.pan_american.android.base.BaseActivity
@@ -43,6 +46,8 @@ class SalesCustomerVisitListActivity : BaseActivity<ActivitySalesCustomerVisitLi
 
     private val historyList = ArrayList<VisitHistoryListItem>()
 
+    private var listInit = false
+
     override fun getViewBinding() = ActivitySalesCustomerVisitListBinding.inflate(layoutInflater)
 
     override fun onCreate(savedInstanceState: Bundle?) {
@@ -70,7 +75,15 @@ class SalesCustomerVisitListActivity : BaseActivity<ActivitySalesCustomerVisitLi
             addButton.visibility = View.VISIBLE
 
             addButton.setOnClickListener {
+                val intent = Intent(OASystem.context, AddCustomerVisitHistoryActivity::class.java).apply {
+                    putExtra("fromList", false)
+                    putExtra("diId", groupId)
+                }
+                startActivity(intent)
+            }
 
+            backButton.setOnClickListener {
+                back()
             }
         }
     }
@@ -82,54 +95,75 @@ class SalesCustomerVisitListActivity : BaseActivity<ActivitySalesCustomerVisitLi
         getVisitHistoryData(1)
     }
 
+    override fun onResume() {
+        super.onResume()
+
+        if (OASystem.needRefresh) {
+            pageIndex = 1
+            marketSalesVisitHistoryRequest.pageIndex = pageIndex
+            binding.visitHistoryList.adapter!!.notifyItemRangeRemoved(0, historyList.size)
+            historyList.clear()
+            listInit = false
+            getVisitHistoryData(2)
+
+            OASystem.needRefresh = false
+        }
+    }
+
     private fun getVisitHistoryData(type: Int) {
-        apiService.getMarketSalesVisitHistory(marketSalesVisitHistoryRequest).enqueue(object : Callback<MarketSalesVisitHistoryResponse> {
-            override fun onResponse(
-                p0: Call<MarketSalesVisitHistoryResponse>,
-                response: Response<MarketSalesVisitHistoryResponse>
-            ) {
-                val listResponse = response.body()
-
-                if (listResponse != null) {
-                    if (listResponse.code == 200) {
-
-                        for (item in listResponse.data) {
-                            historyList.add(item)
-                        }
 
-                        when(type) {
-                            1 -> {
-                                totalPage = getTotalPage(listResponse.count)
-                                binding.visitHistoryContainer.setEnableLoadMore(totalPage > pageIndex)
-                                initList()
+        if (!listInit) {
+            apiService.getMarketSalesVisitHistory(marketSalesVisitHistoryRequest).enqueue(object : Callback<MarketSalesVisitHistoryResponse> {
+                override fun onResponse(
+                    p0: Call<MarketSalesVisitHistoryResponse>,
+                    response: Response<MarketSalesVisitHistoryResponse>
+                ) {
+                    val listResponse = response.body()
+
+                    if (listResponse != null) {
+                        if (listResponse.code == 200) {
+
+                            for (item in listResponse.data) {
+                                item.beginDt = item.beginDt.substring(0, 16)
+                                item.endDt = item.endDt.substring(0, 16)
+                                historyList.add(item)
                             }
 
-                            2 -> {
-                                binding.visitHistoryContainer.finishRefresh()
-                                totalPage = getTotalPage(listResponse.count)
-                                binding.visitHistoryContainer.setEnableLoadMore(pageIndex < totalPage)
-                                initList()
+                            when(type) {
+                                1 -> {
+                                    totalPage = getTotalPage(listResponse.count)
+                                    binding.visitHistoryContainer.setEnableLoadMore(totalPage > pageIndex)
+                                    initList()
+                                    listInit = true
+                                }
+
+                                2 -> {
+                                    binding.visitHistoryContainer.finishRefresh()
+                                    totalPage = getTotalPage(listResponse.count)
+                                    binding.visitHistoryContainer.setEnableLoadMore(pageIndex < totalPage)
+                                    initList()
+                                    listInit = true
+                                }
+
+                                3 -> {
+                                    binding.visitHistoryContainer.finishLoadMore()
+                                    binding.visitHistoryContainer.setEnableLoadMore(pageIndex < totalPage)
+                                    binding.visitHistoryList.adapter!!.notifyItemInserted(historyList.size)
+                                    listInit = true
+                                }
                             }
 
-                            3 -> {
-                                binding.visitHistoryContainer.finishLoadMore()
-                                binding.visitHistoryContainer.setEnableLoadMore(pageIndex < totalPage)
-                                binding.visitHistoryList.adapter!!.notifyItemInserted(
-                                    historyList.size
-                                )
-                            }
+                        } else {
+                            showMessage(listResponse.msg)
                         }
-
-                    } else {
-                        showMessage(listResponse.msg)
                     }
                 }
-            }
 
-            override fun onFailure(p0: Call<MarketSalesVisitHistoryResponse>, p1: Throwable) {
-                showErrorInfo(R.string.visit_history_list_get_error)
-            }
-        })
+                override fun onFailure(p0: Call<MarketSalesVisitHistoryResponse>, p1: Throwable) {
+                    showErrorInfo(R.string.visit_history_list_get_error)
+                }
+            })
+        }
     }
 
     private fun initList() {
@@ -163,7 +197,20 @@ class SalesCustomerVisitListActivity : BaseActivity<ActivitySalesCustomerVisitLi
 
         adapter.onRecyclerViewItemClick = object : CardAdapter.OnRecyclerViewItemClick<VisitHistoryListItem> {
             override fun onItemClick(position: Int) {
+                val intent = Intent(OASystem.context, AddCustomerVisitHistoryActivity::class.java).apply {
+                    putExtra("fromList", true)
+                    putExtra("id", historyList[position].id)
+                    putExtra("diId", historyList[position].diId)
+                    putExtra("customer_name", historyList[position].customerName)
+                    putExtra("customer_company", historyList[position].customerUnit)
+                    putExtra("customer_job", historyList[position].customerJob)
+                    putExtra("customer_contact_way", historyList[position].customerContact)
+                    putExtra("start_time", historyList[position].beginDt)
+                    putExtra("end_time",historyList[position].endDt)
+                    putExtra("remark", historyList[position].remark)
+                }
 
+                startActivity(intent)
             }
 
             override fun onItemDelete(position: Int) {
@@ -187,6 +234,7 @@ class SalesCustomerVisitListActivity : BaseActivity<ActivitySalesCustomerVisitLi
                 marketSalesVisitHistoryRequest.pageIndex = pageIndex
                 historyList.clear()
                 binding.visitHistoryList.adapter!!.notifyItemRangeRemoved(0, historyList.size)
+                listInit = false
                 getVisitHistoryData(2)
             }
 
@@ -194,6 +242,7 @@ class SalesCustomerVisitListActivity : BaseActivity<ActivitySalesCustomerVisitLi
                 if (pageIndex < totalPage) {
                     pageIndex += 1
                     marketSalesVisitHistoryRequest.pageIndex = pageIndex
+                    listInit = false
                     getVisitHistoryData(3)
                 }
             }

+ 1 - 0
app/src/main/java/com/pan_american/android/ui/customer_resource/market_sales_revenue/SalesRevenueListFragment.kt

@@ -149,6 +149,7 @@ class SalesRevenueListFragment : BaseFragment<FragmentSalesRevenueListBinding>()
                         if (listResponse.code == 200) {
 
                             for (item in listResponse.data) {
+                                item.collectionDays = item.collectionDays.substring(0, 10)
                                 groupList.add(item)
                             }
 

+ 293 - 0
app/src/main/res/layout/activity_add_customer_visit_history.xml

@@ -0,0 +1,293 @@
+<?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">
+
+    <include
+        layout="@layout/layout_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:layout_margin="@dimen/common_padding">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <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:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:text="@string/client_name"
+                    android:textSize="@dimen/text_size_medium" />
+
+                <EditText
+                    android:id="@+id/client_name"
+                    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_input"
+                    android:importantForAutofill="no"
+                    android:inputType="text"
+                    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:layout_marginTop="@dimen/common_padding"
+                android:layout_marginBottom="@dimen/common_padding"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:text="@string/customer_company"
+                    android:textSize="@dimen/text_size_medium" />
+
+                <EditText
+                    android:id="@+id/customer_company"
+                    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_input"
+                    android:importantForAutofill="no"
+                    android:inputType="text"
+                    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:layout_marginTop="@dimen/common_padding"
+                android:layout_marginBottom="@dimen/common_padding"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:text="@string/client_job_name"
+                    android:textSize="@dimen/text_size_medium" />
+
+                <EditText
+                    android:id="@+id/client_job"
+                    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_input"
+                    android:importantForAutofill="no"
+                    android:inputType="text"
+                    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:layout_marginTop="@dimen/common_padding"
+                android:layout_marginBottom="@dimen/common_padding"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:text="@string/client_contract_way"
+                    android:textSize="@dimen/text_size_medium" />
+
+                <EditText
+                    android:id="@+id/contract_way"
+                    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_input"
+                    android:importantForAutofill="no"
+                    android:inputType="textEmailAddress|phone"
+                    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:layout_marginTop="@dimen/common_padding"
+                android:layout_marginBottom="@dimen/common_padding"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:text="@string/start_time"
+                    android:textSize="@dimen/text_size_medium" />
+
+                <TextView
+                    android:id="@+id/visit_start_time"
+                    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:layout_marginTop="@dimen/common_padding"
+                android:layout_marginBottom="@dimen/common_padding"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:text="@string/end_time"
+                    android:textSize="@dimen/text_size_medium" />
+
+                <TextView
+                    android:id="@+id/visit_end_time"
+                    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:layout_marginTop="@dimen/common_padding"
+                android:layout_marginBottom="@dimen/common_padding_huge"
+                android:orientation="vertical">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="start"
+                    android:text="@string/visit_matter"
+                    android:textSize="@dimen/text_size_medium" />
+
+                <com.pan_american.android.util.ScrollEditText
+                    android:id="@+id/notes"
+                    android:layout_width="match_parent"
+                    android:layout_height="120dp"
+                    android:layout_marginTop="@dimen/common_padding" />
+
+            </LinearLayout>
+
+        </LinearLayout>
+
+    </ScrollView>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/button_height"
+        android:layout_marginStart="@dimen/common_padding"
+        android:layout_marginTop="@dimen/common_padding_huge"
+        android:layout_marginEnd="@dimen/common_padding"
+        android:layout_marginBottom="@dimen/common_padding_heavy"
+        android:background="@drawable/shape_corner_solid_blue"
+        android:orientation="horizontal">
+
+        <com.pan_american.android.util.CommitButton
+            android:id="@+id/commit"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+
+    </LinearLayout>
+
+</LinearLayout>

+ 1 - 1
app/src/main/res/layout/activity_market_sales_revenue.xml

@@ -3,7 +3,7 @@
     android:id="@+id/main"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@color/background_color"
+    android:background="@color/white"
     android:orientation="vertical">
 
     <include

+ 1 - 0
app/src/main/res/layout/fragment_sales_revenue_list.xml

@@ -4,6 +4,7 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:background="@color/background_color"
     android:orientation="vertical">
 
     <LinearLayout

+ 52 - 0
app/src/main/res/layout/popup_time_selector.xml

@@ -0,0 +1,52 @@
+<?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:background="@drawable/shape_corner_white"
+    android:orientation="vertical"
+    tools:viewBindingIgnore="true">
+
+    <TextView
+        android:id="@+id/time_selector_name"
+        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:gravity="center"
+        android:textSize="@dimen/text_size_large"
+        android:textStyle="bold" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <TimePicker
+            android:id="@+id/time_selector"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/common_padding"
+            android:layout_marginEnd="@dimen/common_padding"
+            android:layout_weight="1"
+            android:timePickerMode="spinner" />
+
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/commit"
+        android:layout_width="match_parent"
+        android:layout_height="40dp"
+        android:layout_marginStart="@dimen/common_padding_huge"
+        android:layout_marginTop="@dimen/common_padding"
+        android:layout_marginEnd="@dimen/common_padding_huge"
+        android:layout_marginBottom="@dimen/common_padding_huge"
+        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>

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

@@ -62,6 +62,8 @@
 
     <string name="date_format">%d-%02d-%02d</string>
 
+    <string name="time_format">%02d:%02d</string>
+
     <string name="with_space_format">%s  %s</string>
 
     <string name="price_and_currency_format">%.2f (%s)</string>
@@ -961,19 +963,29 @@
     <string name="payment_date">收款日期</string>
 
     <string name="visit_history">拜访记录</string>
+    <string name="add_visit_history">添加拜访记录</string>
+    <string name="visit_history_detail">拜访记录详情</string>
+
+    <string name="customer_company_hint">请输入客户单位</string>
+    <string name="customer_job_hint">请输入客户职位</string>
+    <string name="customer_contact_way_hint">请输入客户联系方式</string>
 
     <string name="sales_group_list_get_error">销售团组列表获取失败</string>
 
     <string name="client_job_name">客户职位</string>
-    
+
     <string name="client_contract_way">联系方式</string>
 
     <string name="visit_matter">拜访事项</string>
 
     <string name="end_time">结束时间</string>
 
+    <string name="start_time_select_error">请选择正确的开始时间(日期 + 时间)</string>
+
+    <string name="end_time_select_error">请选择正确的结束时间(日期 + 时间)</string>
+
     <string name="visit_history_delete_alert">确认删除该条 %s 的拜访记录?</string>
-    
+
     <string name="visit_history_list_get_error">拜访记录列表获取失败</string>
 
     <!-- TODO: Remove or change this placeholder text -->