diff --git a/app/Holiday.php b/app/Holiday.php index 0b43744..8e56262 100644 --- a/app/Holiday.php +++ b/app/Holiday.php @@ -42,13 +42,22 @@ final class Holiday public const CACHE_FAIL = 21600; // 6 小时 /** - * 公历固定日期的节日(月 => [日, 名字])。 + * 公历固定日期的节日:月 => [日, 名字, **放假天数**]。 * 只放**日期固定**的:清明是节气(4月4/5/6日浮动)要算,不在这里。 + * + * ⚠️ v24 第 11 批 #6(用户报「国庆节只有刚开始的一天有,这不合理」): + * 这里原来只标**一天**,于是日历上国庆只有 10-01 那一条 —— 而法定假是 7 天。 + * 现在把**法定放假天数**一起写上,内置规则按区间铺开。 + * 天数按《全国年节及纪念日放假办法》的法定假口径: + * 元旦 3 天(通常 1/1 + 周末调休,保守写 1 天由官方数据补)、 + * 劳动节 5 天、国庆节 7 天。 + * ⚠️ 这里的数字是**内置兜底**(官方数据一到就整体替换,见 fetchAndMerge), + * 所以宁可保守也不要编造调休:调休只有官方才准。 */ private const FIXED = [ - 1 => [1 => '元旦'], - 5 => [1 => '劳动节'], - 10 => [1 => '国庆节'], + 1 => [1 => ['元旦', 3]], + 5 => [1 => ['劳动节', 5]], + 10 => [1 => ['国庆节', 7]], ]; /** @@ -204,10 +213,17 @@ final class Holiday { $days = []; - // ---- 公历固定节日 ---- + // ---- 公历固定节日:按**放假天数**铺成一段 ---- + // ⚠️ 用户原话「国庆节只有刚开始的一天有,这不合理」——旧版每天只标一天。 foreach (self::FIXED as $m => $v) { - foreach ($v as $d => $name) { - $days[sprintf('%04d-%02d-%02d', $year, $m, $d)] = ['name' => $name, 'off' => true]; + foreach ($v as $d => $spec) { + [$name, $span] = $spec; + $start = sprintf('%04d-%02d-%02d', $year, $m, $d); + for ($i = 0; $i < max(1, (int)$span); $i++) { + $t = date('Y-m-d', strtotime($start . ' +' . $i . ' day')); + // 跨到下一年的(元旦 3 天可能压到 1/3)也照铺,键就是真实日期 + $days[$t] = ['name' => $name, 'off' => true]; + } } } diff --git a/app/Ledger.php b/app/Ledger.php index 4b3dfe1..dad7e8f 100644 --- a/app/Ledger.php +++ b/app/Ledger.php @@ -346,6 +346,28 @@ final class Ledger return ($neg ? '-' : '') . '¥' . $s; } + /** + * 图例色板(v24 第 11 批 #7)。 + * + * 用户原话:「图下面的条目不用显示详情,只需要显示每个账目的颜色, + * 就是说哪个颜色代表哪个账目,就可以了。」 + * + * 所以每条账目要有一个**稳定**的颜色 —— 按 id 取模落在色板上, + * 不随排序/刷新变化(否则用户没法靠颜色认账目,图例就白做了)。 + * 色板挑中低饱和的,压在宣纸底色上不刺眼,且与 .led-kind-chip 的观感一致。 + */ + public const LEGEND_COLORS = [ + '#B0342C', '#3F7D5A', '#7A4E8C', '#A65C30', + '#3078A6', '#8C6D3F', '#A6305C', '#4A7C82', + '#6BA630', '#9730A6', '#A68930', '#5B6B8C', + ]; + + public static function legendColor(int $entryId): string + { + $n = count(self::LEGEND_COLORS); + return self::LEGEND_COLORS[(($entryId % $n) + $n) % $n]; + } + public static function kind(string $k): string { return isset(self::KINDS[$k]) ? $k : 'other'; @@ -543,14 +565,27 @@ final class Ledger * * @return array */ - public static function entrySeries(int $entryId, int $currentCents): array + public static function entrySeries(int $entryId, int $currentCents, string $born = ''): array { $rows = self::history($entryId); $out = []; foreach ($rows as $r) { $out[] = ['date' => substr((string)$r['created_at'], 0, 10), 'cents' => (int)$r['amount_cents']]; } + // ⚠️ v24 第 11 批 #7(用户报「那个图,怎么数据都是 0 啊,没有盘点数据, + // 就用账目的初始数据就可以了,不一定非要有盘点数据」): + // 旧版"没有任何盘点"时只回**一个点**(今天=当前值)—— + // 单点折线图在页面上就是一根贴边的平线,两端标注还是同一个数, + // 看起来就像"数据都是 0"。用户要的是"用账目的初始数据画出来"。 + // 所以:没盘点过 → 从**账目创建日(那时是 0)**画到今天(当前值), + // 这条线表达的正是"这笔钱从无到有"。 if (!$out) { + $start = $born !== '' ? $born : date('Y-m-d'); + if ($start === date('Y-m-d')) { + // 今天建、今天看 → 给一个**前一天**当起点,否则还是单点 + $start = date('Y-m-d', strtotime('-1 day')); + } + $out[] = ['date' => $start, 'cents' => 0]; $out[] = ['date' => date('Y-m-d'), 'cents' => $currentCents]; } return $out; @@ -579,7 +614,12 @@ final class Ledger $eid = (int)$e['id']; $out[] = [ 'entry' => $e, - 'series' => self::entrySeries($eid, (int)$e['amount_cents']), + // 图例用的颜色:同一账目**每次都一样**(按 id 取模取色板), + // 否则刷新一次就换色,用户没法靠颜色认账目。 + 'color' => self::legendColor($eid), + 'series' => self::entrySeries( + $eid, (int)$e['amount_cents'], + substr((string)($e['created_at'] ?? ''), 0, 10)), ]; } return $out; diff --git a/app/chart.php b/app/chart.php index 5f7f619..3c7ef98 100644 --- a/app/chart.php +++ b/app/chart.php @@ -131,4 +131,119 @@ function chart_line(array $series, string $label, string $kind = 'asset', int $w } $out .= ''; return $out; -} \ No newline at end of file +} +/** + * **多条线**的折线图(v24 第 11 批 #7)。 + * + * 用户原话:「图下面的条目不用显示详情,只需要显示每个账目的颜色, + * 就是说哪个颜色代表哪个账目,就可以了。」 + * + * 所以把原来"每条账目一张小图"合并成**一张图**:每条账目一条线、各自一个颜色, + * 颜色由图例给出(Ledger::legendColor())。这样一眼能比较"哪条在涨、哪条在跌", + * 而不是逐张小图去脑补 —— 那是用户嫌"显示详情"没必要的真正原因。 + * + * ⚠️ 时间轴取所有曲线日期的**并集**,每条线在自己的日期上有值、 + * 没有的日期就"沿用上一次的值"(阶梯式),否则线会断成一段段虚线。 + * 这与 Ledger::timeline() 的口径一致:金额是"状态量",不是"发生量"。 + * + * @param array $charts Ledger::charts() 的返回值:[['entry'=>…, 'color'=>…, 'series'=>…], …] + * @param int $width 画布宽 + * @return string SVG(无可画内容时返回 '') + */ +function chart_multi(array $charts, int $width = 900): string +{ + if (!$charts) { + return ''; + } + // ---- 时间轴:所有日期的并集(升序)---- + $dateSet = []; + foreach ($charts as $ch) { + foreach ((array)($ch['series'] ?? []) as $p) { + $d = (string)($p['date'] ?? ''); + if ($d !== '') { $dateSet[$d] = true; } + } + } + $dates = array_keys($dateSet); + sort($dates); + $n = count($dates); + if ($n === 0) { + return ''; + } + + // ---- 值域:所有曲线所有点的 min/max(含 0,让"从 0 涨起来"看得出来)---- + $vals = [0]; + foreach ($charts as $ch) { + foreach ((array)($ch['series'] ?? []) as $p) { + $vals[] = (int)($p['cents'] ?? 0); + } + } + $min = min($vals); $max = max($vals); + $span = $max - $min; + if ($span <= 0) { $span = 1; } + + $w = max(200, $width); + $h = (int)round($w / 3.6); + $padL = 8; $padR = 8; $padT = 16; $padB = 18; + $iw = $w - $padL - $padR; + $ih = $h - $padT - $padB; + + $idxOf = array_flip($dates); // 日期 => 横轴序号 + + $out = ''; + // 底板与基线 + $out .= ''; + + foreach ($charts as $ch) { + $series = (array)($ch['series'] ?? []); + if (!$series) { continue; } + $color = (string)($ch['color'] ?? '#B0342C'); + // 把每个日期上的值铺齐(沿用上一次),再转成坐标 + $pts = []; + $last = null; + foreach ($dates as $d) { + // 取"这一天或之前最后一次的值"(状态量口径,与 timeline 一致) + foreach ($series as $p) { + if ((string)($p['date'] ?? '') <= $d) { $last = (int)($p['cents'] ?? 0); } + else { break; } + } + if ($last === null) { continue; } // 这条线还没开始(创建日之前) + + $i = $idxOf[$d]; + $x = $n === 1 ? ($padL + $iw / 2) : ($padL + $iw * $i / ($n - 1)); + $ratio = ($last - $min) / $span; + $y = $padT + $ih * (1 - $ratio); + $pts[] = [round($x, 2), round($y, 2)]; + } + if (!$pts) { continue; } + + if (count($pts) === 1) { + $out .= ''; + } else { + $poly = []; + foreach ($pts as $p) { $poly[] = $p[0] . ',' . $p[1]; } + $out .= ''; + // 每段转折点一个小点:有几个盘要点一眼看得出 + foreach ($pts as $p) { + $out .= ''; + } + } + } + + // 首尾日期(中间太密,标了反糊) + $out .= '' . e($dates[0]) . ''; + if ($n > 1) { + $out .= '' . e($dates[$n - 1]) . ''; + } + // 右上角标一下最高/最低,否则不知道纵轴量级 + $out .= '' . e(\App\Ledger::money($max)) + . ' / ' . e(\App\Ledger::money($min)) . ''; + $out .= ''; + return $out; +} diff --git a/assets/css/app.css b/assets/css/app.css index e1bfab0..5469e77 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -460,6 +460,38 @@ textarea.input { min-height: 76px; resize: vertical; } .detail-photo .name { font-size: 18px; font-weight: 600; margin: 14px 0 4px; } .detail-photo .sub { color: var(--muted); font-size: 13px; } +/* ---- v24 第 11 批 #3:详情页改「名片卡 + 全宽堆叠」---- + ⚠️ 旧的 .detail 是 260px + 1fr 两栏,头像卡比右栏矮得多 → 头像下面留一大片空白。 + 现在头像与基本信息并排成一张名片,其余内容全宽往下排。 */ +.pcard { + display: flex; align-items: flex-start; gap: 18px; + background: var(--surface); border: 1px solid var(--line); + border-radius: var(--radius); box-shadow: var(--shadow); + padding: 18px 20px; margin-bottom: 18px; +} +.pcard-avatar { flex: 0 0 auto; } +.pcard-avatar img { + width: 108px; height: 108px; object-fit: cover; + border-radius: 12px; display: block; background: var(--line-2); +} +.pcard-main { flex: 1 1 auto; min-width: 0; padding-top: 2px; } +.pcard-name { + display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; + font-size: 21px; font-weight: 600; margin-bottom: 8px; +} +.pcard-real { font-size: 13px; font-weight: 400; color: var(--muted); } +.pcard-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } +.pcard-chip { + display: inline-block; padding: 3px 10px; border-radius: 999px; + background: var(--line-2); color: var(--ink); font-size: 12.5px; +} +.detail-stack { display: flex; flex-direction: column; gap: 18px; } +.detail-stack > div { min-width: 0; } +@media (max-width: 640px) { + .pcard { flex-direction: column; align-items: center; text-align: center; } + .pcard-name, .pcard-meta { justify-content: center; } +} + .kv { display: flex; flex-direction: column; } .kv-row { display: grid; grid-template-columns: 96px 1fr; gap: 12px; @@ -1013,16 +1045,58 @@ body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb, 「分组」「移出名册」两份表单全页只渲染一份(原来每卡各一份,1184 人 = 2369 个 form / 27234 个 input,密码管理器逐个扫描把页面拖死)。 这里给共享浮层一个定位容器,面板由 JS 贴合触发按钮摆放。 */ -.roster-menus { position: fixed; inset: 0; z-index: 60; pointer-events: none; } -.roster-menus .rm-panel { - position: fixed; pointer-events: auto; +/* ---- v24 第 11 批 #2:名册卡片的动作**居中模态框** ---- + (第 10 批是"贴按钮的浮层",用户反馈分组"点第二次失效"且要求"像选观影人一样弹框", + 于是改成遮罩 + 居中面板,与 _person_picker 同一形态。) */ +.rm-modal { position: fixed; inset: 0; z-index: 60; display: flex; + align-items: center; justify-content: center; } +.rm-modal[hidden] { display: none; } +.rm-mask { position: absolute; inset: 0; background: rgba(47, 36, 30, .34); } +.rm-panel { + position: relative; z-index: 1; background: var(--surface); border: 1px solid var(--line); - border-radius: 10px; box-shadow: var(--shadow-l); - padding: 8px 0; min-width: 200px; + border-radius: 14px; box-shadow: var(--shadow-l); + width: min(360px, 92vw); max-height: min(78vh, 620px); + display: flex; flex-direction: column; } -.roster-menus .rm-panel .person-move { padding: 0 10px; } -.roster-menus .rm-panel .person-move.is-self { padding: 0 12px; } -.roster-menus[hidden] { display: none; } +.rm-panel[hidden] { display: none; } +.rm-head { + display: flex; align-items: center; gap: 10px; + padding: 12px 14px 10px; border-bottom: 1px solid var(--line-2); +} +.rm-head b { font-size: 14.5px; font-weight: 600; } +.rm-x { + margin-left: auto; border: 0; background: transparent; cursor: pointer; + font-size: 15px; line-height: 1; color: var(--muted); padding: 4px 6px; border-radius: 6px; +} +.rm-x:hover { background: var(--line-2); color: var(--ink); } +.rm-body { padding: 8px 6px; overflow-y: auto; } +.rm-foot { + display: flex; gap: 8px; justify-content: flex-end; + padding: 10px 14px; border-top: 1px solid var(--line-2); +} +.rm-warn { + margin: 0; padding: 10px 12px; font-size: 13px; line-height: 1.7; + background: #FDF2F0; border: 1px solid #F0D6D1; border-radius: 8px; color: #7A2A20; +} +.rm-modal .pg-menu { display: contents; } +.rm-modal .pd-form { display: contents; } +.rm-modal .person-move { display: block; padding: 6px 14px 10px; } +.rm-modal .person-move.is-kin { padding: 6px 14px 10px; } + +/* ---- v24 第 11 批 #2:详情页底部「删除」= 大按钮(与「开通账号」同规格,红色底)---- */ +.del-big { display: flex; flex-direction: column; gap: 12px; max-width: 420px; } +.del-big-tip { margin: 0; font-size: 13px; line-height: 1.75; color: var(--muted); } +.btn-block-lg { + display: flex; align-items: center; justify-content: center; + width: 100%; padding: 12px 16px; font-size: 14.5px; +} +.del-big-confirm { + display: flex; align-items: center; gap: 8px; flex-wrap: wrap; + padding: 10px 12px; background: #FDF2F0; + border: 1px solid #F0D6D1; border-radius: 8px; font-size: 13px; color: #7A2A20; +} +.del-big-confirm[hidden] { display: none; } .person-move { display: flex; gap: 6px; padding: 8px 12px; flex-wrap: wrap; } .person-move .select { flex: 1 1 auto; min-width: 0; padding: 6px 8px; font-size: 13px; } .person-move .btn { flex: 0 0 auto; } @@ -1244,6 +1318,13 @@ body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb, /* ---------------- 图片裁剪浮层 ---------------- */ /* 覆盖层默认不占空间;打开时铺满整屏,把底下的页面锁住(裁剪时不该能点到别处) */ +/* ---- 图片裁剪(v24 第 11 批 #5:改用 Cropper.js)---- + 用户的四条硬要求(原话见 assets/js/app.js 那段注释)在这里逐条落地: + ① 弹框**不要有任何滚动条** → 面板 overflow:hidden;画布尺寸固定,由 Cropper 缩放图片去适应。 + ② 图片无论多大都要缩放到框内 → 交给 Cropper 的 viewMode:1(container 自适应)。 + ③ **不要缩放条** → 原来那根 .crop-zoom-row 整块删掉了,改滚轮缩放。 + ④ 裁剪框要比弹框小、**所有触点都露出来** → 画布四周留出 22px 内边距, + Cropper 的四个角手柄画成实心白点,永远落在面板可见区内。 */ .crop-overlay { display: none; } .crop-overlay.is-open { display: flex; position: fixed; inset: 0; z-index: 100; @@ -1251,49 +1332,52 @@ body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb, padding: 20px; background: rgba(44, 35, 29, .55); } .crop-panel { - background: var(--surface); border-radius: var(--radius); + background: var(--surface); border-radius: 14px; box-shadow: var(--shadow-l); padding: 16px; - max-width: calc(100vw - 24px); max-height: calc(100vh - 24px); overflow: auto; + max-width: calc(100vw - 24px); max-height: calc(100vh - 24px); + /* ① 不许出滚动条:面板自己 overflow:hidden,画布尺寸按视口算死在下面 */ + overflow: hidden; + display: flex; flex-direction: column; } .crop-head { display: flex; align-items: baseline; gap: 8px; - font-size: 15px; font-weight: 600; margin-bottom: 12px; + font-size: 15px; font-weight: 600; margin-bottom: 12px; flex: 0 0 auto; } .crop-head .crop-shape { font-size: 12px; font-weight: 400; color: var(--muted); } -.crop-stage { - position: relative; margin: 0 auto; overflow: auto; - background: #F1E7D6; border-radius: var(--radius-s); - touch-action: none; /* 手机上拖框时别把页面一起滚走 */ - user-select: none; +.crop-x { + margin-left: auto; align-self: center; border: 0; background: transparent; + font-size: 15px; line-height: 1; color: var(--muted); + cursor: pointer; padding: 4px 6px; border-radius: 6px; } -/* 图片的宽高由 JS 按倍率写死(放大后比舞台大,靠舞台自身滚动看别处)—— - 所以这里**不能**写 width/height:100%,否则缩放就永远没效果。 */ -.crop-img { display: block; max-width: none; } -/* 缩放条 —— 用户明确要求"裁剪的时候要能缩放" */ -.crop-zoom-row { - display: flex; align-items: center; gap: 10px; - margin-top: 12px; font-size: 13px; color: var(--muted); +.crop-x:hover { background: var(--line-2); color: var(--ink); } +/* 画布:**固定尺寸**(不是 max-height),这样 Cropper 一定会把图片缩进来, + 而不会让容器去滚动。宽高都换算成"视口内还能放下的最大方块"。 + ⚠️ 留 22px 内边距是给裁剪框四个角的手柄留位(要求④)。 */ +.crop-canvas { + flex: 0 0 auto; position: relative; + width: min(560px, calc(100vw - 88px)); + height: min(66vh, 460px); + border-radius: var(--radius-s); overflow: hidden; + background: #2C231D; } -.crop-zoom { flex: 1; min-width: 120px; accent-color: var(--brand); } -.crop-zoom-val { font-variant-numeric: tabular-nums; min-width: 42px; text-align: right; } -/* 框外的部分压暗 —— 这是"你只留下框里这块"最直观的表达 */ -.crop-box { - position: absolute; cursor: move; - border: 2px solid #fff; - box-shadow: 0 0 0 9999px rgba(44, 35, 29, .5); +.crop-canvas img { display: block; max-width: 100%; } +.crop-tip { color: var(--muted); font-size: 12px; margin: 12px 0 0; flex: 0 0 auto; } +.crop-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px; flex: 0 0 auto; } + +/* ④ 触点全露出:Cropper 默认的手柄太细、颜色偏灰,在深色画布上不好抓。 + 这里加粗、改成白底品牌边,并**保证它们不被画布裁掉**(Cropper 自己会留 margin)。 */ +.cropper-view-box, +.cropper-face { border-radius: 2px; } +.cropper-line { background-color: rgba(255, 255, 255, .9); } +.cropper-point { + width: 12px; height: 12px; opacity: 1; + background-color: #fff; border: 2px solid var(--brand); + border-radius: 50%; } -.crop-box::before { - content: ''; position: absolute; inset: 0; - border: 1px dashed rgba(255, 255, 255, .75); pointer-events: none; -} -.crop-handle { - position: absolute; right: -8px; bottom: -8px; - width: 20px; height: 20px; border-radius: 50%; - background: #fff; border: 2px solid var(--brand); - cursor: nwse-resize; -} -.crop-tip { color: var(--muted); font-size: 12px; margin: 12px 0 0; } -.crop-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px; } +.cropper-point.point-se { width: 14px; height: 14px; } +.cropper-bg { background-image: none; background-color: #2C231D; } +.cropper-modal { background-color: rgba(20, 14, 10, .55); } + @media (max-width: 720px) { .order-move .btn { padding: 4px 10px; } @@ -1595,6 +1679,62 @@ body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb, .ck-head b { font-size: 14px; } .ck-svg { display: block; margin-top: 2px; } +/* ---- v24 第 11 批 #7:账目行的两个弹框(全页各一份)---- + 原来每行内联一套(form + 选人组件),账目一多就是几千个 form + —— 用户报的"账目页也卡、还是 Bitwarden 冲突"就是这个。 + 现在行上只有按钮,表单集中到 #ledPanels。 */ +.led-modal { + position: fixed; inset: 0; z-index: 75; + display: flex; align-items: center; justify-content: center; +} +.led-modal[hidden] { display: none; } +.led-mask { position: absolute; inset: 0; background: rgba(47, 36, 30, .34); } +.led-panel-lg { + position: relative; z-index: 1; + background: var(--surface); border: 1px solid var(--line); + border-radius: 14px; box-shadow: var(--shadow-l); + width: min(460px, 92vw); max-height: min(86vh, 660px); + display: flex; flex-direction: column; +} +.led-panel-lg[hidden] { display: none; } +.led-ph { + display: flex; align-items: center; gap: 10px; + padding: 12px 14px 10px; border-bottom: 1px solid var(--line-2); +} +.led-ph b { font-size: 14.5px; } +.led-x { + margin-left: auto; border: 0; background: transparent; cursor: pointer; + font-size: 15px; color: var(--muted); padding: 4px 6px; border-radius: 6px; +} +.led-x:hover { background: var(--line-2); color: var(--ink); } +.led-pb { padding: 12px 14px; overflow-y: auto; } +.led-pb .field { margin-bottom: 12px; } +.led-pb .field > label { display: block; font-size: 13px; color: var(--muted); margin-bottom: 5px; } +.led-pf { + display: flex; gap: 8px; justify-content: flex-end; + padding: 10px 14px; border-top: 1px solid var(--line-2); +} +/* 弹框里的选人组件别撑破面板 */ +.led-pb .pp { max-width: none; } +.led-panel-lg .led-hist { margin-top: 4px; } + +/* ---- v24 第 11 批 #7:图例(只显示"哪个颜色代表哪个账目")---- + 用户原话:「图下面的条目不用显示详情,只需要显示每个账目的颜色, + 就是说哪个颜色代表哪个账目,就可以了。」 + 所以从"每账目一张小卡"改成一行色块图例。 */ +.ck-legend { + display: flex; flex-wrap: wrap; gap: 6px 16px; + margin: 10px 2px 0; font-size: 13px; color: var(--ink); +} +.ck-lg-item { display: inline-flex; align-items: center; gap: 6px; } +.ck-lg-item[hidden] { display: none; } +.ck-lg-dot { + width: 11px; height: 11px; border-radius: 3px; flex: 0 0 auto; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12); +} +/* 多线图:比单条小图高一点,才看得出差异 */ +.ck-multi { margin-top: 4px; } + /* ---- v24 第 10 批 #3:总金额图在最前(跨整行),下面才是逐条账目 ---- */ .ck-total { margin-bottom: 14px; } .ck-total .ck-head b { font-size: 15px; } @@ -2428,6 +2568,92 @@ body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb, .dash-when { flex: 0 0 96px; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; } .dash-what { flex: 1 1 auto; min-width: 0; font-size: 14px; } .dash-tag { flex: 0 0 auto; font-size: 11px; color: var(--faint); } +/* ---- v24 第 11 批 #4:影院下拉(带色点)+ 新建影院弹框 ---- + 原生