日报填报日期范围修改
parent
f3966a45ed
commit
4eed47cc70
|
|
@ -103,6 +103,7 @@ public class WorkServiceImpl implements WorkService {
|
|||
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||
private static final DateTimeFormatter REPORT_DATE_TIME_TEXT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm");
|
||||
private static final ZoneId BUSINESS_ZONE_ID = ZoneId.of("Asia/Shanghai");
|
||||
private static final LocalTime DAILY_REPORT_CUTOFF_TIME = LocalTime.of(10, 0);
|
||||
|
||||
private final WorkMapper workMapper;
|
||||
private final OpportunityMapper opportunityMapper;
|
||||
|
|
@ -2465,7 +2466,12 @@ public class WorkServiceImpl implements WorkService {
|
|||
}
|
||||
|
||||
private LocalDate currentBusinessDate() {
|
||||
return LocalDate.now(BUSINESS_ZONE_ID);
|
||||
return resolveBusinessDate(LocalDateTime.now(BUSINESS_ZONE_ID));
|
||||
}
|
||||
|
||||
static LocalDate resolveBusinessDate(LocalDateTime businessDateTime) {
|
||||
LocalDate date = businessDateTime.toLocalDate();
|
||||
return businessDateTime.toLocalTime().isBefore(DAILY_REPORT_CUTOFF_TIME) ? date.minusDays(1) : date;
|
||||
}
|
||||
|
||||
private record PhotoMetadata(String cleanText, List<String> photoUrls) {}
|
||||
|
|
|
|||
|
|
@ -12,25 +12,21 @@ minio:
|
|||
spring:
|
||||
application:
|
||||
name: unis-crm-backend
|
||||
jackson:
|
||||
time-zone: Asia/Shanghai
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 500MB
|
||||
max-request-size: 600MB
|
||||
datasource:
|
||||
url: jdbc:postgresql://127.0.0.1:5432/unis_crm
|
||||
url: jdbc:postgresql://192.168.124.202:5432/unis_crm
|
||||
username: postgres
|
||||
password: 199628
|
||||
password: unis@123
|
||||
driver-class-name: org.postgresql.Driver
|
||||
hikari:
|
||||
connection-init-sql: SET TIME ZONE 'Asia/Shanghai'
|
||||
data:
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
host: 192.168.124.202
|
||||
port: 6379
|
||||
password: 199628@tlw
|
||||
database: 14
|
||||
password: zghz@123
|
||||
database: 12
|
||||
|
||||
mybatis-plus:
|
||||
mapper-locations: classpath*:/mapper/**/*.xml
|
||||
|
|
|
|||
|
|
@ -4,6 +4,14 @@
|
|||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.unis.crm.mapper.WorkMapper">
|
||||
|
||||
<sql id="dailyReportBusinessDateExpression">
|
||||
case
|
||||
when r.submit_time is not null and (r.submit_time at time zone 'Asia/Shanghai')::time < time '10:00'
|
||||
then (r.submit_time at time zone 'Asia/Shanghai')::date - 1
|
||||
else coalesce((r.submit_time at time zone 'Asia/Shanghai')::date, r.report_date)
|
||||
end
|
||||
</sql>
|
||||
|
||||
<sql id="checkInExportFilters">
|
||||
<if test="startDate != null">
|
||||
and c.checkin_date >= #{startDate}
|
||||
|
|
@ -34,10 +42,22 @@
|
|||
|
||||
<sql id="dailyReportExportFilters">
|
||||
<if test="startDate != null">
|
||||
and r.report_date >= #{startDate}
|
||||
and (
|
||||
case
|
||||
when r.submit_time is not null and (r.submit_time at time zone 'Asia/Shanghai')::time < time '10:00'
|
||||
then (r.submit_time at time zone 'Asia/Shanghai')::date - 1
|
||||
else coalesce((r.submit_time at time zone 'Asia/Shanghai')::date, r.report_date)
|
||||
end
|
||||
) >= #{startDate}
|
||||
</if>
|
||||
<if test="endDate != null">
|
||||
and r.report_date <= #{endDate}
|
||||
and (
|
||||
case
|
||||
when r.submit_time is not null and (r.submit_time at time zone 'Asia/Shanghai')::time < time '10:00'
|
||||
then (r.submit_time at time zone 'Asia/Shanghai')::date - 1
|
||||
else coalesce((r.submit_time at time zone 'Asia/Shanghai')::date, r.report_date)
|
||||
end
|
||||
) <= #{endDate}
|
||||
</if>
|
||||
<if test="keyword != null and keyword != ''">
|
||||
and (
|
||||
|
|
@ -320,7 +340,7 @@
|
|||
select
|
||||
r.id,
|
||||
'日报' as type,
|
||||
to_char(r.report_date, 'YYYY-MM-DD') as date,
|
||||
to_char(<include refid="dailyReportBusinessDateExpression"/>, 'YYYY-MM-DD') as date,
|
||||
to_char(r.submit_time, 'HH24:MI') as time,
|
||||
case
|
||||
when coalesce(nullif(btrim(u.display_name), ''), nullif(btrim(u.username), '')) is not null
|
||||
|
|
@ -343,7 +363,11 @@
|
|||
end as status,
|
||||
rc.score,
|
||||
rc.comment_content as comment,
|
||||
coalesce(r.report_date::timestamp + r.submit_time::time, r.created_at) as sort_time
|
||||
coalesce(
|
||||
(<include refid="dailyReportBusinessDateExpression"/>)::timestamp
|
||||
+ (r.submit_time at time zone 'Asia/Shanghai')::time,
|
||||
r.created_at
|
||||
) as sort_time
|
||||
from work_daily_report r
|
||||
left join sys_user u on u.user_id = r.user_id and u.is_deleted = 0
|
||||
left join (
|
||||
|
|
@ -362,7 +386,7 @@
|
|||
select
|
||||
r.id,
|
||||
'日报' as type,
|
||||
to_char(r.report_date, 'YYYY-MM-DD') as date,
|
||||
to_char(<include refid="dailyReportBusinessDateExpression"/>, 'YYYY-MM-DD') as date,
|
||||
to_char(r.submit_time, 'HH24:MI') as time,
|
||||
case
|
||||
when coalesce(nullif(btrim(u.display_name), ''), nullif(btrim(u.username), '')) is not null
|
||||
|
|
@ -385,7 +409,11 @@
|
|||
end as status,
|
||||
rc.score,
|
||||
rc.comment_content as comment,
|
||||
coalesce(r.report_date::timestamp + r.submit_time::time, r.created_at) as sort_time
|
||||
coalesce(
|
||||
(<include refid="dailyReportBusinessDateExpression"/>)::timestamp
|
||||
+ (r.submit_time at time zone 'Asia/Shanghai')::time,
|
||||
r.created_at
|
||||
) as sort_time
|
||||
from work_daily_report r
|
||||
left join sys_user u on u.user_id = r.user_id and u.is_deleted = 0
|
||||
left join (
|
||||
|
|
@ -408,7 +436,7 @@
|
|||
select
|
||||
r.id,
|
||||
'日报' as type,
|
||||
to_char(r.report_date, 'YYYY-MM-DD') as date,
|
||||
to_char(<include refid="dailyReportBusinessDateExpression"/>, 'YYYY-MM-DD') as date,
|
||||
to_char(r.submit_time, 'HH24:MI') as time,
|
||||
case
|
||||
when coalesce(nullif(btrim(u.display_name), ''), nullif(btrim(u.username), '')) is not null
|
||||
|
|
@ -431,7 +459,11 @@
|
|||
end as status,
|
||||
rc.score,
|
||||
rc.comment_content as comment,
|
||||
coalesce(r.report_date::timestamp + r.submit_time::time, r.created_at) as sort_time
|
||||
coalesce(
|
||||
(<include refid="dailyReportBusinessDateExpression"/>)::timestamp
|
||||
+ (r.submit_time at time zone 'Asia/Shanghai')::time,
|
||||
r.created_at
|
||||
) as sort_time
|
||||
from work_daily_report r
|
||||
left join sys_user u on u.user_id = r.user_id and u.is_deleted = 0
|
||||
left join (
|
||||
|
|
@ -459,7 +491,7 @@
|
|||
select
|
||||
r.id,
|
||||
'日报' as type,
|
||||
to_char(r.report_date, 'YYYY-MM-DD') as date,
|
||||
to_char(<include refid="dailyReportBusinessDateExpression"/>, 'YYYY-MM-DD') as date,
|
||||
to_char(r.submit_time, 'HH24:MI') as time,
|
||||
case
|
||||
when coalesce(nullif(btrim(u.display_name), ''), nullif(btrim(u.username), '')) is not null
|
||||
|
|
@ -482,7 +514,11 @@
|
|||
end as status,
|
||||
rc.score,
|
||||
rc.comment_content as comment,
|
||||
coalesce(r.report_date::timestamp + r.submit_time::time, r.created_at) as sort_time
|
||||
coalesce(
|
||||
(<include refid="dailyReportBusinessDateExpression"/>)::timestamp
|
||||
+ (r.submit_time at time zone 'Asia/Shanghai')::time,
|
||||
r.created_at
|
||||
) as sort_time
|
||||
from work_daily_report r
|
||||
left join sys_user u on u.user_id = r.user_id and u.is_deleted = 0
|
||||
left join (
|
||||
|
|
@ -573,7 +609,14 @@
|
|||
<select id="selectDailyReportExportRows" resultType="com.unis.crm.dto.work.WorkDailyReportExportDTO">
|
||||
select
|
||||
r.id,
|
||||
to_char(r.report_date, 'YYYY-MM-DD') as reportDate,
|
||||
to_char(
|
||||
case
|
||||
when r.submit_time is not null and (r.submit_time at time zone 'Asia/Shanghai')::time < time '10:00'
|
||||
then (r.submit_time at time zone 'Asia/Shanghai')::date - 1
|
||||
else coalesce((r.submit_time at time zone 'Asia/Shanghai')::date, r.report_date)
|
||||
end,
|
||||
'YYYY-MM-DD'
|
||||
) as reportDate,
|
||||
to_char(r.submit_time, 'YYYY-MM-DD HH24:MI') as submitTime,
|
||||
coalesce(nullif(btrim(u.display_name), ''), nullif(btrim(u.username), ''), '') as userName,
|
||||
coalesce(nullif(btrim(org_info.org_names), ''), '') as deptName,
|
||||
|
|
@ -618,7 +661,14 @@
|
|||
<select id="selectDailyReportExportRowsByUserIds" resultType="com.unis.crm.dto.work.WorkDailyReportExportDTO">
|
||||
select
|
||||
r.id,
|
||||
to_char(r.report_date, 'YYYY-MM-DD') as reportDate,
|
||||
to_char(
|
||||
case
|
||||
when r.submit_time is not null and (r.submit_time at time zone 'Asia/Shanghai')::time < time '10:00'
|
||||
then (r.submit_time at time zone 'Asia/Shanghai')::date - 1
|
||||
else coalesce((r.submit_time at time zone 'Asia/Shanghai')::date, r.report_date)
|
||||
end,
|
||||
'YYYY-MM-DD'
|
||||
) as reportDate,
|
||||
to_char(r.submit_time, 'YYYY-MM-DD HH24:MI') as submitTime,
|
||||
coalesce(nullif(btrim(u.display_name), ''), nullif(btrim(u.username), ''), '') as userName,
|
||||
coalesce(nullif(btrim(org_info.org_names), ''), '') as deptName,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import com.unis.crm.dto.work.WorkReportLineItemRequest;
|
|||
import com.unis.crm.dto.work.WorkTomorrowPlanItemRequest;
|
||||
import com.unis.crm.mapper.OpportunityMapper;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import com.unis.crm.mapper.ProfileMapper;
|
||||
import com.unis.crm.mapper.WorkMapper;
|
||||
import com.unis.crm.service.CrmDataVisibilityService;
|
||||
|
|
@ -718,6 +719,20 @@ class WorkServiceImplTest {
|
|||
eq(17L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveBusinessDate_shouldUsePreviousDateBeforeTenOClock() {
|
||||
assertEquals(
|
||||
LocalDate.of(2026, 7, 21),
|
||||
WorkServiceImpl.resolveBusinessDate(LocalDateTime.of(2026, 7, 22, 9, 59, 59)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveBusinessDate_shouldUseCurrentDateFromTenOClock() {
|
||||
assertEquals(
|
||||
LocalDate.of(2026, 7, 22),
|
||||
WorkServiceImpl.resolveBusinessDate(LocalDateTime.of(2026, 7, 22, 10, 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveDailyReport_shouldNotSyncOpportunitySnapshotForNonSalesRole() {
|
||||
CreateWorkDailyReportRequest request = new CreateWorkDailyReportRequest();
|
||||
|
|
|
|||
|
|
@ -219,9 +219,30 @@ const FALLBACK_OPPORTUNITY_TYPE_OPTIONS = [
|
|||
{ value: "替换", label: "替换" },
|
||||
] as const;
|
||||
|
||||
function getCurrentReportDate(now = new Date()): string {
|
||||
const parts = new Intl.DateTimeFormat("en-CA", {
|
||||
timeZone: "Asia/Shanghai",
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
hourCycle: "h23",
|
||||
}).formatToParts(now);
|
||||
const values = Object.fromEntries(parts.map((part) => [part.type, part.value]));
|
||||
const reportDate = new Date(Date.UTC(Number(values.year), Number(values.month) - 1, Number(values.day)));
|
||||
if (Number(values.hour) < 10) {
|
||||
reportDate.setUTCDate(reportDate.getUTCDate() - 1);
|
||||
}
|
||||
return [
|
||||
reportDate.getUTCFullYear(),
|
||||
String(reportDate.getUTCMonth() + 1).padStart(2, "0"),
|
||||
String(reportDate.getUTCDate()).padStart(2, "0"),
|
||||
].join("-");
|
||||
}
|
||||
|
||||
function createEmptyReportLine(): WorkReportLineItem {
|
||||
return {
|
||||
workDate: format(new Date(), "yyyy-MM-dd"),
|
||||
workDate: getCurrentReportDate(),
|
||||
bizType: "sales",
|
||||
bizId: "",
|
||||
bizName: "",
|
||||
|
|
@ -790,7 +811,7 @@ export default function Work() {
|
|||
const isMobileViewport = useIsMobileViewport();
|
||||
const isWecomInternalBrowser = useIsWecomBrowser();
|
||||
const disableMobileMotion = isMobileViewport || isWecomInternalBrowser;
|
||||
const currentWorkDate = format(new Date(), "yyyy-MM-dd");
|
||||
const currentWorkDate = getCurrentReportDate();
|
||||
const hasAutoRefreshedLocation = useRef(false);
|
||||
const photoInputRef = useRef<HTMLInputElement | null>(null);
|
||||
const historyLoadMoreRef = useRef<HTMLDivElement | null>(null);
|
||||
|
|
@ -3767,7 +3788,11 @@ function HistoryCard({
|
|||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-slate-900 dark:text-white">{item.type}</h3>
|
||||
<p className="text-[10px] text-slate-500 dark:text-slate-400">{[item.date, item.time].filter(Boolean).join(" ")}</p>
|
||||
<p className="text-[10px] text-slate-500 dark:text-slate-400">
|
||||
{item.type === "日报"
|
||||
? `日报日期:${item.date || "未标注日期"}`
|
||||
: [item.date, item.time].filter(Boolean).join(" ")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-end gap-1">
|
||||
|
|
@ -4330,7 +4355,7 @@ function ReportPanel({
|
|||
</div>
|
||||
<div className="flex w-full items-center justify-between gap-2 lg:w-auto lg:justify-end">
|
||||
<span className="crm-pill crm-pill-neutral text-[11px]">
|
||||
日期 {currentWorkDate}
|
||||
日报日期 {currentWorkDate}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -4715,7 +4740,9 @@ function HistoryDetailModal({
|
|||
<div className="flex-1 overflow-y-auto px-4 py-4 pb-[calc(env(safe-area-inset-bottom)+20px)] sm:px-6 sm:py-5">
|
||||
<div>
|
||||
<p className="text-xs font-medium text-slate-400 dark:text-slate-500">
|
||||
{[item.date, item.time].filter(Boolean).join(" ") || "无时间信息"}
|
||||
{item.type === "日报"
|
||||
? `日报日期:${item.date || "未标注日期"}`
|
||||
: [item.date, item.time].filter(Boolean).join(" ") || "无时间信息"}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue