| | |
| | | android.util.Log.d("SmsReceiver", "Received SMS code: ${code}") |
| | | val msg = Msg(0, "1111", "111111", messageBody.toString(), 1, "111", 1, 1) |
| | | val msgId = Core.msg.insert(msg) |
| | | val code = Code(0, rule.type, 1, rule.content, 1, 1, msgId, code, dateString, "中通",0) |
| | | val code = Code(0, rule.type, 1, rule.content, 1, 1, msgId, code, dateString, "中通",0,"","") |
| | | Core.code.insert(code) |
| | | android.util.Log.d("SMS_DEBUG", "历史短信已保存到数据库") |
| | | }else{ |
| | |
| | | import android.widget.TextView |
| | | import androidx.recyclerview.widget.RecyclerView |
| | | import com.example.firstapp.R |
| | | import com.example.firstapp.model.PackageInfo |
| | | import com.example.firstapp.database.entity.Code |
| | | import java.text.ParseException |
| | | import java.text.SimpleDateFormat |
| | | import java.util.Date |
| | | import java.util.Locale |
| | | |
| | | |
| | | class PackageAdapter : RecyclerView.Adapter<PackageAdapter.PackageViewHolder>() { |
| | | |
| | | private var packages = listOf<PackageInfo>() |
| | | private var packages = listOf<Code>() |
| | | |
| | | fun updatePackages(newPackages: List<PackageInfo>) { |
| | | fun updatePackages(newPackages: List<Code>) { |
| | | packages = newPackages |
| | | notifyDataSetChanged() |
| | | } |
| | | |
| | | //此处是渲染数据 |
| | | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PackageViewHolder { |
| | | val view = LayoutInflater.from(parent.context) |
| | | .inflate(R.layout.item_package_dashboard, parent, false) |
| | |
| | | private val textCourierName: TextView = view.findViewById(R.id.text_courier_name) |
| | | private val textTrackingNumber: TextView = view.findViewById(R.id.text_tracking_number) |
| | | private val textTime: TextView = view.findViewById(R.id.text_time) |
| | | private val textPickTime: TextView = view.findViewById(R.id.text_pick_time) |
| | | |
| | | fun bind(packageInfo: PackageInfo) { |
| | | imgCourier.setImageResource(packageInfo.courierIcon) |
| | | textCourierName.text = packageInfo.courierName |
| | | textTrackingNumber.text = packageInfo.trackingNumber |
| | | textTime.text = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()) |
| | | .format(packageInfo.receivedTime) |
| | | fun bind(code: Code) { |
| | | // imgCourier.setImageResource(code.category) |
| | | textCourierName.text = code.type |
| | | textTrackingNumber.text = code.code |
| | | // 步骤1:定义解析器,将字符串转为 Date |
| | | val parser = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) |
| | | val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()) |
| | | try { |
| | | val date: Date? = parser.parse(code.createtime) // 解析字符串 |
| | | date?.let { |
| | | textTime.text = "到货:"+formatter.format(it) // 格式化并赋值 |
| | | } ?: run { |
| | | // 处理解析失败(date 为 null 的情况) |
| | | textTime.text = "Invalid Date" |
| | | } |
| | | } catch (e: ParseException) { |
| | | e.printStackTrace() |
| | | textTime.text = "Format Error" |
| | | } |
| | | try { |
| | | val date2: Date? = parser.parse(code.pickuptime) // 解析字符串 |
| | | date2?.let { |
| | | textPickTime.text = "取件:"+formatter.format(it) // 格式化并赋值 |
| | | } ?: run { |
| | | textPickTime.text = "未取件" |
| | | } |
| | | } catch (e: ParseException) { |
| | | e.printStackTrace() |
| | | textPickTime.text = "未取件" |
| | | } |
| | | |
| | | } |
| | | } |
| | | } |
| | |
| | | import androidx.room.TypeConverters |
| | | import androidx.room.migration.Migration |
| | | import androidx.sqlite.db.SupportSQLiteDatabase |
| | | import com.example.firstapp.dao.PackageDao |
| | | import com.example.firstapp.database.dao.CodeDao |
| | | import com.example.firstapp.database.dao.KeywordDao |
| | | import com.example.firstapp.database.dao.MsgDao |
| | |
| | | import com.example.firstapp.utils.TAG_LIST |
| | | |
| | | import com.example.firstapp.database.ext.ConvertersDate |
| | | import com.example.firstapp.model.PackageInfo |
| | | import com.example.firstapp.model.CourierStat |
| | | import com.example.firstapp.model.DailyStat |
| | | |
| | |
| | | Msg::class, |
| | | Code::class, |
| | | KeywordEntity::class, |
| | | Reminder::class, |
| | | PackageInfo::class |
| | | Reminder::class |
| | | ], |
| | | views = [ |
| | | CourierStat::class, |
| | |
| | | abstract fun codeDao(): CodeDao |
| | | abstract fun keywordDao(): KeywordDao |
| | | abstract fun reminderDao(): ReminderDao |
| | | abstract fun packageDao(): PackageDao |
| | | |
| | | companion object { |
| | | @Volatile |
| | |
| | | import androidx.room.Update |
| | | import com.example.firstapp.database.entity.Code |
| | | import com.example.firstapp.database.entity.Msg |
| | | import com.example.firstapp.model.CourierStat |
| | | import com.example.firstapp.model.DailyStat |
| | | import io.reactivex.Completable |
| | | import kotlinx.coroutines.flow.Flow |
| | | |
| | | @Dao |
| | | interface CodeDao { |
| | |
| | | fun queryByTypeAndCodeAndDate(content: String, code: String, dateString: String): Code |
| | | |
| | | |
| | | @Query("update Code set pickup = '1' where id=:id") |
| | | @Query("update Code set pickup = '1' , pickuptime = CURRENT_TIMESTAMP where id=:id") |
| | | fun pickup(id: Long) |
| | | |
| | | //查询当天包裹信息 |
| | | @Query("SELECT * FROM code WHERE date(createtime) = date(:date/1000, 'unixepoch', 'localtime') ORDER BY createtime DESC") |
| | | fun getNewPackagesByDay(date: Long): List<Code> |
| | | |
| | | @Query("SELECT * FROM code WHERE date(createtime/1000, 'unixepoch', 'localtime') = date(:date/1000, 'unixepoch', 'localtime') ORDER BY createtime DESC") |
| | | fun getPackagesByDay(date: Long): Flow<List<Code>> |
| | | |
| | | @Query(""" |
| | | SELECT * FROM code |
| | | WHERE strftime('%Y-%W', createtime/1000, 'unixepoch', 'localtime') = |
| | | strftime('%Y-%W', :date/1000, 'unixepoch', 'localtime') |
| | | ORDER BY createtime DESC |
| | | """) |
| | | fun getPackagesByWeek(date: Long): Flow<List<Code>> |
| | | |
| | | @Query(""" |
| | | SELECT * FROM CourierStat |
| | | WHERE EXISTS ( |
| | | SELECT 1 FROM code p |
| | | WHERE p.category = CourierStat.category |
| | | AND strftime('%Y-%W', p.createtime/1000, 'unixepoch', 'localtime') = |
| | | strftime('%Y-%W', :date/1000, 'unixepoch', 'localtime') |
| | | ) |
| | | """) |
| | | fun getCourierStatsByWeek(date: Long): Flow<List<CourierStat>> |
| | | |
| | | @Query(""" |
| | | SELECT * FROM DailyStat |
| | | WHERE EXISTS ( |
| | | SELECT 1 FROM code p |
| | | WHERE date(p.createtime/1000, 'unixepoch', 'localtime') = DailyStat.date |
| | | AND strftime('%Y-%W', p.createtime/1000, 'unixepoch', 'localtime') = |
| | | strftime('%Y-%W', :date/1000, 'unixepoch', 'localtime') |
| | | ) |
| | | """) |
| | | fun getDailyStatsByWeek(date: Long): Flow<List<DailyStat>> |
| | | } |
| | |
| | | var createtime: String, |
| | | var name: String, |
| | | var pickup: Int, |
| | | var pickuptime: String, //取件时间 |
| | | var overtime: String, // 超期时间 |
| | | var time: Date = Date(), |
| | | // var overtime: String, |
| | | |
| | | ) |
| | |
| | | import androidx.annotation.WorkerThread |
| | | import com.example.firstapp.database.dao.CodeDao |
| | | import com.example.firstapp.database.entity.Code |
| | | import kotlinx.coroutines.Dispatchers |
| | | import kotlinx.coroutines.flow.Flow |
| | | import kotlinx.coroutines.withContext |
| | | |
| | | |
| | | class CodeRepository(private val codeDao: CodeDao) { |
| | |
| | | } |
| | | |
| | | fun queryByTypeAndCodeAndDate(content: String, code: String, dateString: String): Code { |
| | | return codeDao.queryByTypeAndCodeAndDate(content,code,dateString) |
| | | return codeDao.queryByTypeAndCodeAndDate(content, code, dateString) |
| | | } |
| | | |
| | | @WorkerThread |
| | | fun pickup(id: Long) = codeDao.pickup(id) |
| | | |
| | | |
| | | fun getPackages(date: Long, dateType: String): Flow<List<Code>> { |
| | | return when (dateType) { |
| | | "DAY" -> codeDao.getPackagesByDay(date) |
| | | "WEEK" -> codeDao.getPackagesByWeek(date) |
| | | else -> codeDao.getPackagesByDay(date) |
| | | } |
| | | } |
| | | |
| | | fun getCourierStats(date: Long) = codeDao.getCourierStatsByWeek(date) |
| | | |
| | | fun getDailyStats(date: Long) = codeDao.getDailyStatsByWeek(date) |
| | | |
| | | |
| | | @WorkerThread |
| | | fun getPackagesByDay(date: Long): List<Code> { |
| | | return codeDao.getNewPackagesByDay(date) |
| | | } |
| | | |
| | | |
| | | } |
| | |
| | | |
| | | @DatabaseView( |
| | | """ |
| | | SELECT courierName, COUNT(*) as count |
| | | FROM packages |
| | | GROUP BY courierName |
| | | SELECT category, COUNT(*) as count |
| | | FROM Code |
| | | GROUP BY category |
| | | """ |
| | | ) |
| | | data class CourierStat( |
| | | val courierName: String, |
| | | val category: String, |
| | | val count: Int |
| | | ) |
| | |
| | | |
| | | @DatabaseView( |
| | | """ |
| | | SELECT date(receivedTime/1000, 'unixepoch', 'localtime') as date, |
| | | SELECT date(createtime/1000, 'unixepoch', 'localtime') as date, |
| | | COUNT(*) as count |
| | | FROM packages |
| | | GROUP BY date(receivedTime/1000, 'unixepoch', 'localtime') |
| | | FROM code |
| | | GROUP BY date(createtime/1000, 'unixepoch', 'localtime') |
| | | """ |
| | | ) |
| | | data class DailyStat( |
| | |
| | | val createtime = sdf.format(date) |
| | | val existingCode = Core.code.queryByTypeAndCodeAndDate(rule.content, code, createtime) |
| | | if (existingCode == null) { |
| | | val code = Code(0, rule.type, 1, rule.content, 1, 1, msgId, code, createtime, "中通",0) |
| | | val code = Code(0, rule.type, 1, rule.content, 1, 1, msgId, code, createtime, "中通",0,"","") |
| | | Core.code.insert(code) |
| | | Log.d("SMS_DEBUG", "新短信已保存到数据库") |
| | | |
| | |
| | | import com.google.android.material.tabs.TabLayout |
| | | import androidx.recyclerview.widget.LinearLayoutManager |
| | | import com.example.firstapp.adapter.PackageAdapter |
| | | import com.example.firstapp.model.PackageInfo |
| | | import com.example.firstapp.core.Core |
| | | import com.github.mikephil.charting.charts.BarChart |
| | | import com.github.mikephil.charting.charts.PieChart |
| | | import com.github.mikephil.charting.components.Legend |
| | |
| | | private fun updatePieChartData() { |
| | | viewModel.getCourierStats(currentDate.timeInMillis).observe(viewLifecycleOwner) { stats -> |
| | | val entries = stats.map { stat -> |
| | | PieEntry(stat.count.toFloat(), stat.courierName) |
| | | PieEntry(stat.count.toFloat(), stat.category) |
| | | } |
| | | |
| | | val dataSet = PieDataSet(entries, "快递公司分布") |
| | |
| | | |
| | | private fun loadPackages() { |
| | | // 这里应该从数据库或网络加载数据 |
| | | // 这里使用模拟数据作为示例 |
| | | val mockPackages = listOf( |
| | | PackageInfo( |
| | | trackingNumber = "14-6-7023", |
| | | courierName = "某快递", |
| | | receivedTime = System.currentTimeMillis(), |
| | | courierIcon = R.drawable.data |
| | | ), |
| | | PackageInfo( |
| | | trackingNumber = "230721", |
| | | courierName = "京东", |
| | | receivedTime = System.currentTimeMillis() - 3600000, |
| | | courierIcon = R.drawable.data |
| | | ) |
| | | ) |
| | | |
| | | packageAdapter.updatePackages(mockPackages) |
| | | binding.textPackageCount.text = "${mockPackages.size}个" |
| | | // 根据当前选择的日期类型传入对应参数 |
| | | val packages = when (currentDateType) { |
| | | DateType.DAY -> Core.code.getPackagesByDay(currentDate.timeInMillis) |
| | | // DateType.WEEK -> Core.code.getPackagesByWeek(currentDate.timeInMillis) |
| | | // DateType.MONTH -> Core.code.getPackagesByMonth(currentDate.timeInMillis) |
| | | // DateType.YEAR -> Core.code.getPackagesByYear(currentDate.timeInMillis) |
| | | DateType.WEEK -> TODO() |
| | | DateType.MONTH -> TODO() |
| | | DateType.YEAR -> TODO() |
| | | } |
| | | packageAdapter.updatePackages(packages) |
| | | binding.textPackageCount.text = "${packageAdapter.itemCount}个" |
| | | } |
| | | private fun observePackages() { |
| | | viewModel.getPackages( |
| | |
| | | updatePieChartData() |
| | | } |
| | | else -> { |
| | | packageAdapter.updatePackages(packages) |
| | | } |
| | | packageAdapter.updatePackages(packages) |
| | | } |
| | | } |
| | | binding.textPackageCount.text = "${packages.size}个" |
| | | } |
| | |
| | | import androidx.lifecycle.asLiveData |
| | | import androidx.lifecycle.viewModelScope |
| | | import com.example.firstapp.AppDatabase |
| | | import com.example.firstapp.model.PackageInfo |
| | | import com.example.firstapp.repository.PackageRepository |
| | | import com.example.firstapp.database.entity.Code |
| | | import com.example.firstapp.database.repository.CodeRepository |
| | | import kotlinx.coroutines.launch |
| | | |
| | | class DashboardViewModel(application: Application) : AndroidViewModel(application) { |
| | | |
| | | private val repository: PackageRepository |
| | | |
| | | |
| | | private val repository: CodeRepository |
| | | |
| | | init { |
| | | val packageDao = AppDatabase.getInstance(application).packageDao() |
| | | repository = PackageRepository(packageDao) |
| | | val codeDao = AppDatabase.getInstance(application).codeDao() |
| | | repository = CodeRepository(codeDao) |
| | | } |
| | | |
| | | fun getPackages(date: Long, dateType: String) = |
| | | |
| | | fun getPackages(date: Long, dateType: String) = |
| | | repository.getPackages(date, dateType).asLiveData() |
| | | |
| | | fun getCourierStats(date: Long) = repository.getCourierStats(date).asLiveData() |
| | | |
| | | |
| | | fun getDailyStats(date: Long) = repository.getDailyStats(date).asLiveData() |
| | | |
| | | fun updatePackageStatus(packageInfo: PackageInfo) = viewModelScope.launch { |
| | | repository.update(packageInfo) |
| | | } |
| | | |
| | | fun insert(packageInfo: PackageInfo) = viewModelScope.launch { |
| | | repository.insert(packageInfo) |
| | | fun insert(code: Code) = viewModelScope.launch { |
| | | repository.insert(code) |
| | | } |
| | | } |
| | |
| | | android:padding="16dp"> |
| | | |
| | | <ImageView |
| | | android:layout_width="48dp" |
| | | android:layout_width="0dp" |
| | | android:layout_height="48dp" |
| | | android:layout_weight="1" |
| | | android:src="@drawable/resource_package" /> |
| | | |
| | | <TextView |
| | | android:id="@+id/text_package_count" |
| | | android:layout_width="wrap_content" |
| | | android:layout_width="0dp" |
| | | android:layout_height="wrap_content" |
| | | android:layout_gravity="center_vertical" |
| | | android:layout_marginStart="16dp" |
| | | android:layout_weight="1" |
| | | android:textSize="24sp" |
| | | android:textStyle="bold" |
| | | tools:text="4个" /> |
| | |
| | | tools:text="2025-01-14 10:30" /> |
| | | </LinearLayout> |
| | | |
| | | <TextView |
| | | android:id="@+id/text_tracking_number" |
| | | <LinearLayout |
| | | android:layout_width="wrap_content" |
| | | android:layout_height="wrap_content" |
| | | android:textColor="@android:color/darker_gray" |
| | | tools:text="14-6-7023" /> |
| | | android:orientation="vertical"> |
| | | |
| | | <TextView |
| | | android:id="@+id/text_tracking_number" |
| | | android:layout_width="wrap_content" |
| | | android:layout_height="wrap_content" |
| | | android:textColor="@android:color/darker_gray" |
| | | android:layout_gravity="end" |
| | | tools:text="14-6-7023" /> |
| | | |
| | | <TextView |
| | | android:id="@+id/text_pick_time" |
| | | android:layout_width="wrap_content" |
| | | android:layout_height="wrap_content" |
| | | android:layout_marginTop="4dp" |
| | | android:textColor="@android:color/darker_gray" |
| | | android:layout_gravity="end" |
| | | android:textSize="12sp" |
| | | tools:text="2025-01-15 11:30" /> |
| | | </LinearLayout> |
| | | |
| | | </LinearLayout> |
| | | |
| | | </androidx.cardview.widget.CardView> |