@yaoxiu/marketing-dsl 2.5.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1835,7 +1835,8 @@ var changelog = [
1835
1835
  "`zIndex` \u73B0\u5728\u4F1A\u81EA\u52A8\u5E26\u4E0A\u5B9A\u4F4D\u65B9\u5F0F\uFF1A`z-index` \u5BF9\u9759\u6001\u5143\u7D20\u662F\u6B7B\u58F0\u660E\uFF0C\u5199\u4E86\u4E0D\u751F\u6548\u3002\u6D41\u5F0F\u6392\u7248\u91CC\u9760\u8D1F `marginTop` \u5F80\u4E0A\u76D6\u7684\u5757\uFF08\u5982\u538B\u4F4F\u7EA2\u5934\u4E0B\u6CBF\u7684\u767D\u8272\u4E3B\u4F53\uFF09\u5FC5\u987B\u6709\u5C42\u7EA7\u624D\u76D6\u5F97\u4F4F\uFF0C\u914D\u4E86 `zIndex` \u5373\u53EF\uFF0C\u4E0D\u7528\uFF08\u4E5F\u6CA1\u6CD5\uFF09\u53E6\u914D `position`",
1836
1836
  "\u3010\u4FEE\u590D\u3011\u5F39\u51FA\u7B2C\u4E8C\u5C42\u5F39\u7A97\uFF08\u5982\u4E8C\u6B21\u633D\u7559\uFF09\u518D\u5173\u6389\u65F6\uFF0C\u4E0B\u5C42\u5F39\u7A97\u7684\u906E\u7F69\u5165\u573A\u52A8\u753B\u4F1A\u91CD\u64AD\u4E00\u904D\uFF0C\u80CC\u666F\u300C\u95EA\u300D\u4E00\u4E0B\u91CD\u65B0\u6DE1\u5165\u3002\u73B0\u5DF2\u4FEE\u6B63\uFF0C\u914D\u7F6E\u5199\u6CD5\u4E0D\u7528\u6539",
1837
1837
  "\u3010\u4FEE\u590D\u3011\u5207\u89C6\u56FE / \u5207 tab / `visibleWhen` \u7FFB\u8F6C\u65F6\uFF0C\u9875\u9762\u4E0A\u6B63\u5728\u8DD1\u7684\u5FAA\u73AF\u52A8\u753B\u4F1A\u5168\u90E8\u91CD\u5934\u64AD\u4E00\u904D\u3002\u73B0\u5DF2\u4FEE\u6B63",
1838
- "`hoverStyle` \u91CC\u7684 `{{ }}` \u53EA\u5728\u9996\u5C4F\u6C42\u503C\u4E00\u6B21\uFF0C\u4E4B\u540E\u4E0D\u968F state \u53D8\u5316\u2014\u2014\u8981\u8DDF\u7740\u72B6\u6001\u53D8\u7684\u6837\u5F0F\u5199\u5728 `style` \u91CC\uFF08\u90A3\u6761\u8DEF\u5F84\u6BCF\u5E27\u90FD\u4F1A\u91CD\u7B97\uFF09"
1838
+ "`hoverStyle` \u91CC\u7684 `{{ }}` \u53EA\u5728\u9996\u5C4F\u6C42\u503C\u4E00\u6B21\uFF0C\u4E4B\u540E\u4E0D\u968F state \u53D8\u5316\u2014\u2014\u8981\u8DDF\u7740\u72B6\u6001\u53D8\u7684\u6837\u5F0F\u5199\u5728 `style` \u91CC\uFF08\u90A3\u6761\u8DEF\u5F84\u6BCF\u5E27\u90FD\u4F1A\u91CD\u7B97\uFF09",
1839
+ "\u65B0\u589E\u793A\u4F8B \u246C \u642C\u5BB6\u6B21\u6570\u5C06\u5C3D\uFF1A\u989D\u5EA6\u8FDB\u5EA6\u6761\u7684\u6807\u51C6\u5199\u6CD5\uFF08\u5916\u5C42 flex \u5F53\u8F68\u9053 + \u5185\u5C42 box \u5F53\u586B\u5145\u6761 + `width` \u5199\u6210\u63D2\u503C\u8868\u8FBE\u5F0F\u73B0\u7B97\u767E\u5206\u6BD4\uFF09\uFF0C\u8981\u753B\u4EFB\u4F55\u6BD4\u4F8B\u6761\u90FD\u6284\u8FD9\u4EFD\u3002\u6CE8\u610F\u5B83\u7684\u603B\u989D\u5EA6\u662F\u8FD0\u8425\u624B\u586B\u7684\u2014\u2014\u7EDF\u8BA1\u63A5\u53E3\u76EE\u524D\u53EA\u6709\u4F59\u989D\u3001\u6CA1\u6709\u603B\u989D\u5EA6\uFF0C\u5957\u9910\u989D\u5EA6\u53D8\u4E86\u5FC5\u987B\u624B\u52A8\u6539\u7269\u6599"
1839
1840
  ]
1840
1841
  },
1841
1842
  {
@@ -4754,6 +4755,538 @@ var giftRedPacket = {
4754
4755
  };
4755
4756
  var gift_red_packet_default = giftRedPacket;
4756
4757
 
4758
+ // src/docs/examples/quota-low.ts
4759
+ var ORANGE4 = "linear-gradient(90deg,#ff7a00,#faad14)";
4760
+ var USED = "{{ total - user.collectCount }}";
4761
+ var achieveCell3 = (verb, value, unit, label) => ({
4762
+ type: "flex",
4763
+ style: {
4764
+ direction: "column",
4765
+ // grid 不在白名单,用 flex wrap + 半宽复刻 grid-template-columns: 1fr 1fr(gap 9)
4766
+ width: "calc(50% - 5px)",
4767
+ background: "rgba(255,255,255,0.16)",
4768
+ borderWidth: 1,
4769
+ borderStyle: "solid",
4770
+ borderColor: "rgba(255,255,255,0.2)",
4771
+ radius: 10,
4772
+ // .period-price-modal .ac 把基础规则的 9px 11px 覆盖成 10px 13px
4773
+ padding: "10px 13px"
4774
+ },
4775
+ children: [
4776
+ {
4777
+ // .ac .n:line-height 1.1 × 20px = 22px,显式给死,
4778
+ // 否则 20px 数字的默认行高(≈1.5)会把格子撑高 8px 左右
4779
+ type: "flex",
4780
+ style: { align: "baseline", height: 22, whiteSpace: "nowrap" },
4781
+ children: [
4782
+ {
4783
+ type: "text",
4784
+ content: verb,
4785
+ style: {
4786
+ fontSize: 11.5,
4787
+ fontWeight: "600",
4788
+ lineHeight: 1.1,
4789
+ letterSpacing: 0.2,
4790
+ marginRight: 3,
4791
+ // demo 是 opacity .7 叠在 .m-top 的白字上,等价于这个色值
4792
+ color: "rgba(255,255,255,0.7)"
4793
+ }
4794
+ },
4795
+ {
4796
+ type: "text",
4797
+ content: value,
4798
+ style: { fontSize: 20, fontWeight: "800", lineHeight: 1.1, color: "#ffffff" }
4799
+ },
4800
+ {
4801
+ type: "text",
4802
+ content: ` ${unit}`,
4803
+ style: {
4804
+ fontSize: 12,
4805
+ fontWeight: "600",
4806
+ lineHeight: 1.1,
4807
+ // demo 是 opacity .85
4808
+ color: "rgba(255,255,255,0.85)"
4809
+ }
4810
+ }
4811
+ ]
4812
+ },
4813
+ {
4814
+ type: "text",
4815
+ content: label,
4816
+ style: {
4817
+ fontSize: 11,
4818
+ lineHeight: 1.4,
4819
+ marginTop: 2,
4820
+ color: "rgba(255,255,255,0.85)"
4821
+ }
4822
+ }
4823
+ ]
4824
+ });
4825
+ var loseRow3 = {
4826
+ type: "flex",
4827
+ style: { align: "flex-start", gap: 10, padding: "7px 0" },
4828
+ children: [
4829
+ {
4830
+ type: "text",
4831
+ content: "",
4832
+ style: {
4833
+ width: 6,
4834
+ height: 6,
4835
+ radius: "50%",
4836
+ background: "#f53f3f",
4837
+ marginTop: 7,
4838
+ // demo 的 flex: none —— 文案换行时圆点不许被压扁
4839
+ flexShrink: "0"
4840
+ }
4841
+ },
4842
+ {
4843
+ type: "flex",
4844
+ style: { align: "baseline", gap: 4, wrap: true, flex: "1" },
4845
+ children: [
4846
+ {
4847
+ type: "text",
4848
+ content: "{{ item.b }}",
4849
+ style: {
4850
+ fontSize: 12.5,
4851
+ fontWeight: "700",
4852
+ lineHeight: 1.55,
4853
+ color: "#1f2533"
4854
+ }
4855
+ },
4856
+ {
4857
+ type: "text",
4858
+ content: "\u2014 {{ item.t }}",
4859
+ style: { fontSize: 12.5, lineHeight: 1.55, color: "#4a4038" }
4860
+ }
4861
+ ]
4862
+ }
4863
+ ]
4864
+ };
4865
+ var tierCard3 = {
4866
+ type: "box",
4867
+ style: {
4868
+ flex: "1",
4869
+ height: 119,
4870
+ radius: 12,
4871
+ background: "{{ item.key == current.key ? '#fffaf0' : '#ffffff' }}",
4872
+ borderStyle: "solid",
4873
+ borderWidth: "{{ item.key == current.key ? '2px' : '1px' }}",
4874
+ borderColor: "{{ item.key == current.key ? '#f0a000' : '#e5e8ed' }}",
4875
+ shadow: "{{ item.key == current.key ? '0 7px 18px rgba(240,160,0,0.1)' : 'none' }}",
4876
+ cursor: "pointer",
4877
+ transition: "border-color 0.15s, background 0.15s, box-shadow 0.15s"
4878
+ },
4879
+ // .tcol:hover { border-color: var(--gold) }
4880
+ hoverStyle: { borderColor: "#faad14" },
4881
+ action: {
4882
+ type: "sequence",
4883
+ actions: [
4884
+ { type: "setState", key: "period", value: "{{ index }}" },
4885
+ {
4886
+ type: "track",
4887
+ event: "popup_period_select",
4888
+ params: { period: "{{ item.key }}" }
4889
+ }
4890
+ ]
4891
+ },
4892
+ children: [
4893
+ {
4894
+ // .thot:top -9、字号 11、padding 2px 8px、radius 6。
4895
+ // 宽 38 = 2 字 × 11px + 左右 8px;居中靠 left: calc(50% - 19px)
4896
+ type: "text",
4897
+ rect: ["calc(50% - 19px)", -9, 38, 22],
4898
+ content: "\u63A8\u8350",
4899
+ visibleWhen: "item.hot",
4900
+ style: {
4901
+ background: ORANGE4,
4902
+ color: "#ffffff",
4903
+ fontSize: 11,
4904
+ fontWeight: "800",
4905
+ radius: 6,
4906
+ textAlign: "center",
4907
+ lineHeight: 22,
4908
+ whiteSpace: "nowrap"
4909
+ }
4910
+ },
4911
+ {
4912
+ type: "text",
4913
+ rect: [0, 12, "100%", 19],
4914
+ content: "{{ item.p }}",
4915
+ style: { fontSize: 13, lineHeight: 1.45, color: "#8a909c", textAlign: "center" }
4916
+ },
4917
+ {
4918
+ type: "flex",
4919
+ rect: [0, 36, "100%", 26],
4920
+ style: { justify: "center", align: "baseline" },
4921
+ children: [
4922
+ {
4923
+ // .tpr i:符号比数字小一号、字重 600
4924
+ type: "text",
4925
+ content: "\xA5",
4926
+ style: {
4927
+ fontSize: 14,
4928
+ fontWeight: "600",
4929
+ lineHeight: 1.2,
4930
+ color: "{{ item.key == current.key ? '#d46b08' : '#1f2533' }}"
4931
+ }
4932
+ },
4933
+ {
4934
+ type: "text",
4935
+ content: "{{ item.price }}",
4936
+ style: {
4937
+ fontSize: 21,
4938
+ fontWeight: "800",
4939
+ lineHeight: 1.2,
4940
+ color: "{{ item.key == current.key ? '#d46b08' : '#1f2533' }}"
4941
+ }
4942
+ }
4943
+ ]
4944
+ },
4945
+ {
4946
+ type: "text",
4947
+ rect: [4, 63, "calc(100% - 8px)", 32],
4948
+ content: "{{ item.per }}",
4949
+ style: {
4950
+ fontSize: 11,
4951
+ lineHeight: 1.5,
4952
+ textAlign: "center",
4953
+ color: "{{ item.key == current.key ? '#d46b08' : '#8a909c' }}",
4954
+ fontWeight: "{{ item.key == current.key ? '600' : '400' }}"
4955
+ }
4956
+ },
4957
+ {
4958
+ // .tflag 的 margin-top: auto(贴底)在绝对定位里直接写死 y = 119 - 9 - 15
4959
+ type: "text",
4960
+ rect: [0, 95, "100%", 15],
4961
+ content: "{{ item.flag }}",
4962
+ visibleWhen: "item.flag != ''",
4963
+ style: { fontSize: 11, lineHeight: 1.35, color: "#8a909c", textAlign: "center" }
4964
+ }
4965
+ ]
4966
+ };
4967
+ var quotaLow = {
4968
+ version: 1,
4969
+ type: "popup",
4970
+ meta: { name: "\u642C\u5BB6\u6B21\u6570\u5C06\u5C3D \xB7 \u989D\u5EA6\u8FDB\u5EA6\u6761\uFF08\u590D\u523B\u8FD0\u8425 demo\uFF09" },
4971
+ stage: {
4972
+ // .modal.period-price-modal { width: min(520px, calc(100vw - 24px)) }
4973
+ width: 520,
4974
+ height: "auto",
4975
+ layout: "flow",
4976
+ mask: true,
4977
+ maskClosable: false,
4978
+ closeButton: {
4979
+ // .m-close:24×24 的半透明白圆点,字符 ×、15px
4980
+ show: true,
4981
+ position: "top-right",
4982
+ offset: [14, 14],
4983
+ size: 24,
4984
+ icon: "\xD7",
4985
+ style: { background: "rgba(255,255,255,0.3)", fontSize: 15, color: "#ffffff" }
4986
+ },
4987
+ // .modal 的圆角与投影(--shadow-lg)
4988
+ style: { radius: 18, shadow: "0 28px 72px rgba(16,27,51,0.24)" },
4989
+ // demo 的 animation: pop .38s cubic-bezier(.16,1,.3,1) both
4990
+ // 注意 easing 的小数必须写成 0.16 —— 校验的正则不认 CSS 允许的 .16 简写
4991
+ animate: {
4992
+ name: "pop",
4993
+ duration: 380,
4994
+ easing: "cubic-bezier(0.16, 1, 0.3, 1)",
4995
+ fill: "both"
4996
+ }
4997
+ },
4998
+ keyframes: {
4999
+ pop: {
5000
+ from: { opacity: 0, transform: "translateY(14px) scale(0.96)" },
5001
+ to: { opacity: 1, transform: "none" }
5002
+ }
5003
+ },
5004
+ data: {
5005
+ // 实时统计走后端数据源。$source 填的是宿主注册过的数据源名(不是接口地址),
5006
+ // userStatistics 返回扁平对象,字段名就是后端的 snake_case
5007
+ stat: { $source: "userStatistics" },
5008
+ // 总额度:运营按当前套餐手填。为什么不走接口、以后怎么换,见文件头注释
5009
+ total: 30,
5010
+ // 三条都没有状态标签 —— demo 这一屏的 lose 配置里就没有 tag 字段
5011
+ lose: [
5012
+ { b: "\u6279\u91CF\u642C\u5BB6", t: "\u989D\u5EA6\u5F52\u96F6\u540E\u65E0\u6CD5\u7EE7\u7EED\u4E0A\u8D27" },
5013
+ { b: "1688 \u4E00\u4EF6\u4EE3\u53D1", t: "\u6E90\u5934\u8D27\u6E90\u65AD\u4F9B\uFF0C\u9009\u54C1\u3001\u94FA\u8D27\u3001\u4EE3\u53D1\u90FD\u8981\u624B\u52A8\u505A" },
5014
+ { b: "AI \u81EA\u52A8\u4F18\u5316", t: "\u65B0\u5546\u54C1\u4E0D\u518D\u8865\u4E3B\u6807\u9898 / \u77ED\u6807\u9898 / \u767D\u5E95\u56FE" }
5015
+ ],
5016
+ // 价格档位从后端数据源取,后端返回几档就渲染几档,配置时不用知道数量
5017
+ tiers: { $source: "listRenewTiers", params: { scene: "quota_low" } }
5018
+ },
5019
+ state: { period: 1 },
5020
+ derived: { current: { list: "tiers", indexBy: "period" } },
5021
+ nodes: [
5022
+ // ===== .m-top 深色渐变头部:(标签 + 额度条)同排 + 2×2 成果格 =====
5023
+ {
5024
+ type: "flex",
5025
+ style: {
5026
+ direction: "column",
5027
+ background: "linear-gradient(135deg,#2b0f0f,#3a1414)",
5028
+ padding: "20px 22px 16px"
5029
+ },
5030
+ children: [
5031
+ {
5032
+ // .m-top-head:右侧留 30px 给关闭按钮让位
5033
+ type: "flex",
5034
+ style: {
5035
+ align: "center",
5036
+ justify: "space-between",
5037
+ gap: 14,
5038
+ padding: "0 30px 0 0"
5039
+ },
5040
+ children: [
5041
+ {
5042
+ // .tag:flex: none,按内容宽度,不许被额度条挤扁
5043
+ type: "text",
5044
+ content: "\u26A1 \u642C\u5BB6\u6B21\u6570\u5373\u5C06\u7528\u5B8C",
5045
+ style: {
5046
+ background: "rgba(255,255,255,0.18)",
5047
+ color: "#ffffff",
5048
+ fontSize: 12,
5049
+ fontWeight: "700",
5050
+ radius: 6,
5051
+ padding: "3px 10px",
5052
+ flexShrink: "0",
5053
+ whiteSpace: "nowrap"
5054
+ }
5055
+ },
5056
+ {
5057
+ // ===== 额度进度条(本示例的重点)。.m-top .quota 反白配色版 =====
5058
+ type: "flex",
5059
+ style: {
5060
+ direction: "column",
5061
+ flex: "1",
5062
+ maxWidth: 280,
5063
+ background: "rgba(255,255,255,0.12)",
5064
+ borderWidth: 1,
5065
+ borderStyle: "solid",
5066
+ borderColor: "rgba(255,255,255,0.16)",
5067
+ radius: 7,
5068
+ padding: "3px 10px 4px"
5069
+ },
5070
+ children: [
5071
+ {
5072
+ // .qh:左「搬家次数剩余」,右加粗的剩余次数
5073
+ type: "flex",
5074
+ style: { align: "baseline", justify: "space-between" },
5075
+ children: [
5076
+ {
5077
+ type: "text",
5078
+ content: "\u642C\u5BB6\u6B21\u6570\u5269\u4F59",
5079
+ style: {
5080
+ fontSize: 10.5,
5081
+ lineHeight: 1.25,
5082
+ color: "rgba(255,255,255,0.85)"
5083
+ }
5084
+ },
5085
+ {
5086
+ type: "text",
5087
+ content: "{{ user.collectCount }} \u6B21",
5088
+ style: {
5089
+ fontSize: 12.5,
5090
+ fontWeight: "800",
5091
+ lineHeight: 1.15,
5092
+ color: "#ffb066"
5093
+ }
5094
+ }
5095
+ ]
5096
+ },
5097
+ {
5098
+ // .qbar 轨道。用 flex 而不是 box —— box 的子节点走绝对定位、必须给 rect,
5099
+ // 填充条要的是「跟着父级流」;overflow: hidden 必须写,
5100
+ // 否则填充条的直角会戳出轨道的圆角外面
5101
+ type: "flex",
5102
+ style: {
5103
+ height: 3,
5104
+ radius: 4,
5105
+ background: "rgba(255,255,255,0.2)",
5106
+ margin: "2px 0 1px",
5107
+ overflow: "hidden"
5108
+ },
5109
+ children: [
5110
+ {
5111
+ // 填充条。宽度是算出来的:已用 ÷ 总额度 × 100,节点 style 里的
5112
+ // 字符串同样走插值,所以百分比不需要后端多下发一个字段
5113
+ type: "box",
5114
+ style: {
5115
+ width: "{{ (total - user.collectCount) / total * 100 }}%",
5116
+ height: "100%",
5117
+ background: "linear-gradient(90deg,#f53f3f,#ff7a45)"
5118
+ }
5119
+ }
5120
+ ]
5121
+ },
5122
+ {
5123
+ // .qn
5124
+ type: "text",
5125
+ content: `\u5DF2\u7528 ${USED} / {{ total }} \u6B21`,
5126
+ style: {
5127
+ fontSize: 9,
5128
+ lineHeight: 1.25,
5129
+ color: "rgba(255,255,255,0.6)"
5130
+ }
5131
+ }
5132
+ ]
5133
+ }
5134
+ ]
5135
+ },
5136
+ {
5137
+ // .achieve:四格并列写死(扁平对象没法 bind 遍历),flex + wrap 复刻 2×2 grid。
5138
+ // 第一格的数字不是统计字段,而是「总额度 − 剩余次数」现算出来的
5139
+ type: "flex",
5140
+ style: { gap: 9, wrap: true, marginTop: 14 },
5141
+ children: [
5142
+ achieveCell3("\u5DF2\u7528", USED, "\u6B21", "\u642C\u5BB6\u6B21\u6570"),
5143
+ achieveCell3("\u5DF2\u4E0A\u67B6", "{{ stat.move_success_count }}", "\u4E2A", "\u7D2F\u8BA1\u4E0A\u67B6\u5546\u54C1"),
5144
+ achieveCell3("\u65E5\u5747", "{{ stat.avg_daily_move_count }}", "\u4E2A", "\u5E73\u5747\u6BCF\u5929\u4E0A\u67B6"),
5145
+ achieveCell3(
5146
+ "\u5DF2\u8865\u9F50",
5147
+ "{{ stat.white_image_fill_count }}",
5148
+ "\u5F20",
5149
+ "\u767D\u5E95\u56FE \xB7 \u5408\u89C4\u53EF\u62A5\u6D3B\u52A8"
5150
+ )
5151
+ ]
5152
+ }
5153
+ ]
5154
+ },
5155
+ // ===== .m-body 白底 =====
5156
+ {
5157
+ type: "flex",
5158
+ style: { direction: "column", background: "#ffffff", padding: "22px 26px 24px" },
5159
+ children: [
5160
+ {
5161
+ // .m-copy-panel
5162
+ type: "text",
5163
+ content: "\u642C\u5BB6\u6B21\u6570\u7528\u5B8C\uFF0C\u4EA7\u54C1\u80FD\u529B\u5C06\u53D7\u9650\uFF1A",
5164
+ style: {
5165
+ fontSize: 15,
5166
+ fontWeight: "800",
5167
+ lineHeight: 1.55,
5168
+ letterSpacing: -0.15,
5169
+ color: "#1f2533"
5170
+ }
5171
+ },
5172
+ {
5173
+ // .lose
5174
+ type: "repeat",
5175
+ bind: "lose",
5176
+ template: loseRow3,
5177
+ style: {
5178
+ direction: "column",
5179
+ marginTop: 14,
5180
+ background: "#ffe9e6",
5181
+ borderWidth: 1,
5182
+ borderStyle: "solid",
5183
+ borderColor: "#ffd0ca",
5184
+ radius: 12,
5185
+ padding: "7px 13px"
5186
+ }
5187
+ },
5188
+ {
5189
+ // .tiers 的 border-top:白名单没有 borderTop,用 1px 实心分隔条代替
5190
+ type: "box",
5191
+ style: { height: 1, background: "#eceef3", marginTop: 18 }
5192
+ },
5193
+ {
5194
+ // .tv:lead 被 normalizeTrialPricing 置空,所以整行都在 <b> 里
5195
+ //(字重 800、墨色),后面跟价格口径标记 .tv-tag
5196
+ type: "flex",
5197
+ style: { align: "center", gap: 8, marginTop: 17, marginBottom: 11 },
5198
+ children: [
5199
+ {
5200
+ type: "text",
5201
+ content: "\u4E13\u5C5E\u4F18\u60E0 \xB7 \u5012\u8BA1\u65F6",
5202
+ style: { fontSize: 13.5, fontWeight: "800", color: "#1f2533" }
5203
+ },
5204
+ {
5205
+ type: "text",
5206
+ content: "\u65B0\u4EBA\u9996\u8D2D\u4EF7",
5207
+ style: {
5208
+ alignSelf: "center",
5209
+ background: ORANGE4,
5210
+ color: "#ffffff",
5211
+ fontSize: 11,
5212
+ fontWeight: "800",
5213
+ radius: 5,
5214
+ padding: "2px 8px"
5215
+ }
5216
+ }
5217
+ ]
5218
+ },
5219
+ // .tcols:wide 版 gap 8
5220
+ { type: "repeat", bind: "tiers", style: { gap: 8 }, template: tierCard3 },
5221
+ {
5222
+ // .m-cta(th-loss 主题的红橙渐变)
5223
+ type: "flex",
5224
+ style: {
5225
+ justify: "center",
5226
+ align: "baseline",
5227
+ gap: 5,
5228
+ padding: "13px",
5229
+ radius: 11,
5230
+ background: "linear-gradient(90deg,#f53f3f,#ff7a45)",
5231
+ marginTop: 20,
5232
+ shadow: "0 8px 18px rgba(245,63,63,0.14)",
5233
+ transition: "transform 0.18s, box-shadow 0.18s",
5234
+ cursor: "pointer"
5235
+ },
5236
+ hoverStyle: {
5237
+ transform: "translateY(-1px)",
5238
+ shadow: "0 10px 22px rgba(245,63,63,0.2)"
5239
+ },
5240
+ action: {
5241
+ type: "sequence",
5242
+ actions: [
5243
+ {
5244
+ type: "track",
5245
+ event: "popup_renew_click",
5246
+ params: { period: "{{ current.key }}", stage: "quota_low" }
5247
+ },
5248
+ { type: "navigate", url: "{{ current.url }}" }
5249
+ ]
5250
+ },
5251
+ children: [
5252
+ {
5253
+ // .m-cta .ct
5254
+ type: "text",
5255
+ content: "\u7EED\u6EE1\u989D\u5EA6 \xB7",
5256
+ style: {
5257
+ fontSize: 14,
5258
+ fontWeight: "800",
5259
+ letterSpacing: -0.2,
5260
+ color: "#ffffff"
5261
+ }
5262
+ },
5263
+ {
5264
+ // .m-cta .cp —— demo 的 syncCTAPrice() 把它同步成「选中档位名 + 价格」
5265
+ type: "text",
5266
+ content: "{{ current.p }} \xA5{{ current.price }}",
5267
+ style: { fontSize: 16.5, fontWeight: "800", color: "#ffffff" }
5268
+ }
5269
+ ]
5270
+ },
5271
+ {
5272
+ // .m-ghost
5273
+ type: "text",
5274
+ content: "\u5347\u7EA7\u6216\u67E5\u770B\u66F4\u591A\u4EA7\u54C1\u5957\u9910",
5275
+ style: {
5276
+ fontSize: 12,
5277
+ color: "#8a909c",
5278
+ textAlign: "center",
5279
+ marginTop: 10,
5280
+ cursor: "pointer"
5281
+ },
5282
+ action: { type: "track", event: "popup_more_plans" }
5283
+ }
5284
+ ]
5285
+ }
5286
+ ]
5287
+ };
5288
+ var quota_low_default = quotaLow;
5289
+
4757
5290
  // src/docs/examples/index.ts
4758
5291
  var HOTSPOT_BG = "rgba(255,68,51,0.16)";
4759
5292
  var imageHotspot = {
@@ -5005,6 +5538,11 @@ var examples = [
5005
5538
  label: "\u246B \u590D\u523B\u7EBF\u4E0A\u5F39\u7A97 \xB7 1 \u5206\u94B1\u534A\u5E74\u5361\uFF08\u52A8\u753B\u6700\u5BC6\u7684\u4E00\u4EFD\uFF09",
5006
5539
  value: "giftRedPacket",
5007
5540
  dsl: gift_red_packet_default
5541
+ },
5542
+ {
5543
+ label: "\u246C \u590D\u523B\u8FD0\u8425 demo \xB7 \u642C\u5BB6\u6B21\u6570\u5C06\u5C3D\uFF08\u989D\u5EA6\u8FDB\u5EA6\u6761\uFF09",
5544
+ value: "quotaLow",
5545
+ dsl: quota_low_default
5008
5546
  }
5009
5547
  ];
5010
5548
  var examples_default = examples;
@@ -96,7 +96,8 @@ declare const meta: DocMeta;
96
96
  *
97
97
  * ①② 是最小骨架,③④ 是运营 demo 真实弹窗的完整复刻,⑤⑥ 是多视图,⑦ 是换肤换布局,
98
98
  * ⑧ 是通栏 banner(宽度由页面决定、只能声明比例),⑨⑩ 是商品编辑抽屉里两个**固定尺寸**坑位,
99
- * ⑪⑫ 是搬家成功页两个线上弹窗的一比一复刻(动画、hover、相对时长倒计时的完整用法)。
99
+ * ⑪⑫ 是搬家成功页两个线上弹窗的一比一复刻(动画、hover、相对时长倒计时的完整用法),
100
+ * ⑬ 是额度进度条(用表达式算填充宽度,要画任何比例条都抄这份)。
100
101
  * 后端数据源($source)用法见 ③。
101
102
  */
102
103
 
@@ -96,7 +96,8 @@ declare const meta: DocMeta;
96
96
  *
97
97
  * ①② 是最小骨架,③④ 是运营 demo 真实弹窗的完整复刻,⑤⑥ 是多视图,⑦ 是换肤换布局,
98
98
  * ⑧ 是通栏 banner(宽度由页面决定、只能声明比例),⑨⑩ 是商品编辑抽屉里两个**固定尺寸**坑位,
99
- * ⑪⑫ 是搬家成功页两个线上弹窗的一比一复刻(动画、hover、相对时长倒计时的完整用法)。
99
+ * ⑪⑫ 是搬家成功页两个线上弹窗的一比一复刻(动画、hover、相对时长倒计时的完整用法),
100
+ * ⑬ 是额度进度条(用表达式算填充宽度,要画任何比例条都抄这份)。
100
101
  * 后端数据源($source)用法见 ③。
101
102
  */
102
103
 
@@ -1674,7 +1674,8 @@ var changelog = [
1674
1674
  "`zIndex` \u73B0\u5728\u4F1A\u81EA\u52A8\u5E26\u4E0A\u5B9A\u4F4D\u65B9\u5F0F\uFF1A`z-index` \u5BF9\u9759\u6001\u5143\u7D20\u662F\u6B7B\u58F0\u660E\uFF0C\u5199\u4E86\u4E0D\u751F\u6548\u3002\u6D41\u5F0F\u6392\u7248\u91CC\u9760\u8D1F `marginTop` \u5F80\u4E0A\u76D6\u7684\u5757\uFF08\u5982\u538B\u4F4F\u7EA2\u5934\u4E0B\u6CBF\u7684\u767D\u8272\u4E3B\u4F53\uFF09\u5FC5\u987B\u6709\u5C42\u7EA7\u624D\u76D6\u5F97\u4F4F\uFF0C\u914D\u4E86 `zIndex` \u5373\u53EF\uFF0C\u4E0D\u7528\uFF08\u4E5F\u6CA1\u6CD5\uFF09\u53E6\u914D `position`",
1675
1675
  "\u3010\u4FEE\u590D\u3011\u5F39\u51FA\u7B2C\u4E8C\u5C42\u5F39\u7A97\uFF08\u5982\u4E8C\u6B21\u633D\u7559\uFF09\u518D\u5173\u6389\u65F6\uFF0C\u4E0B\u5C42\u5F39\u7A97\u7684\u906E\u7F69\u5165\u573A\u52A8\u753B\u4F1A\u91CD\u64AD\u4E00\u904D\uFF0C\u80CC\u666F\u300C\u95EA\u300D\u4E00\u4E0B\u91CD\u65B0\u6DE1\u5165\u3002\u73B0\u5DF2\u4FEE\u6B63\uFF0C\u914D\u7F6E\u5199\u6CD5\u4E0D\u7528\u6539",
1676
1676
  "\u3010\u4FEE\u590D\u3011\u5207\u89C6\u56FE / \u5207 tab / `visibleWhen` \u7FFB\u8F6C\u65F6\uFF0C\u9875\u9762\u4E0A\u6B63\u5728\u8DD1\u7684\u5FAA\u73AF\u52A8\u753B\u4F1A\u5168\u90E8\u91CD\u5934\u64AD\u4E00\u904D\u3002\u73B0\u5DF2\u4FEE\u6B63",
1677
- "`hoverStyle` \u91CC\u7684 `{{ }}` \u53EA\u5728\u9996\u5C4F\u6C42\u503C\u4E00\u6B21\uFF0C\u4E4B\u540E\u4E0D\u968F state \u53D8\u5316\u2014\u2014\u8981\u8DDF\u7740\u72B6\u6001\u53D8\u7684\u6837\u5F0F\u5199\u5728 `style` \u91CC\uFF08\u90A3\u6761\u8DEF\u5F84\u6BCF\u5E27\u90FD\u4F1A\u91CD\u7B97\uFF09"
1677
+ "`hoverStyle` \u91CC\u7684 `{{ }}` \u53EA\u5728\u9996\u5C4F\u6C42\u503C\u4E00\u6B21\uFF0C\u4E4B\u540E\u4E0D\u968F state \u53D8\u5316\u2014\u2014\u8981\u8DDF\u7740\u72B6\u6001\u53D8\u7684\u6837\u5F0F\u5199\u5728 `style` \u91CC\uFF08\u90A3\u6761\u8DEF\u5F84\u6BCF\u5E27\u90FD\u4F1A\u91CD\u7B97\uFF09",
1678
+ "\u65B0\u589E\u793A\u4F8B \u246C \u642C\u5BB6\u6B21\u6570\u5C06\u5C3D\uFF1A\u989D\u5EA6\u8FDB\u5EA6\u6761\u7684\u6807\u51C6\u5199\u6CD5\uFF08\u5916\u5C42 flex \u5F53\u8F68\u9053 + \u5185\u5C42 box \u5F53\u586B\u5145\u6761 + `width` \u5199\u6210\u63D2\u503C\u8868\u8FBE\u5F0F\u73B0\u7B97\u767E\u5206\u6BD4\uFF09\uFF0C\u8981\u753B\u4EFB\u4F55\u6BD4\u4F8B\u6761\u90FD\u6284\u8FD9\u4EFD\u3002\u6CE8\u610F\u5B83\u7684\u603B\u989D\u5EA6\u662F\u8FD0\u8425\u624B\u586B\u7684\u2014\u2014\u7EDF\u8BA1\u63A5\u53E3\u76EE\u524D\u53EA\u6709\u4F59\u989D\u3001\u6CA1\u6709\u603B\u989D\u5EA6\uFF0C\u5957\u9910\u989D\u5EA6\u53D8\u4E86\u5FC5\u987B\u624B\u52A8\u6539\u7269\u6599"
1678
1679
  ]
1679
1680
  },
1680
1681
  {
@@ -4593,6 +4594,538 @@ var giftRedPacket = {
4593
4594
  };
4594
4595
  var gift_red_packet_default = giftRedPacket;
4595
4596
 
4597
+ // src/docs/examples/quota-low.ts
4598
+ var ORANGE4 = "linear-gradient(90deg,#ff7a00,#faad14)";
4599
+ var USED = "{{ total - user.collectCount }}";
4600
+ var achieveCell3 = (verb, value, unit, label) => ({
4601
+ type: "flex",
4602
+ style: {
4603
+ direction: "column",
4604
+ // grid 不在白名单,用 flex wrap + 半宽复刻 grid-template-columns: 1fr 1fr(gap 9)
4605
+ width: "calc(50% - 5px)",
4606
+ background: "rgba(255,255,255,0.16)",
4607
+ borderWidth: 1,
4608
+ borderStyle: "solid",
4609
+ borderColor: "rgba(255,255,255,0.2)",
4610
+ radius: 10,
4611
+ // .period-price-modal .ac 把基础规则的 9px 11px 覆盖成 10px 13px
4612
+ padding: "10px 13px"
4613
+ },
4614
+ children: [
4615
+ {
4616
+ // .ac .n:line-height 1.1 × 20px = 22px,显式给死,
4617
+ // 否则 20px 数字的默认行高(≈1.5)会把格子撑高 8px 左右
4618
+ type: "flex",
4619
+ style: { align: "baseline", height: 22, whiteSpace: "nowrap" },
4620
+ children: [
4621
+ {
4622
+ type: "text",
4623
+ content: verb,
4624
+ style: {
4625
+ fontSize: 11.5,
4626
+ fontWeight: "600",
4627
+ lineHeight: 1.1,
4628
+ letterSpacing: 0.2,
4629
+ marginRight: 3,
4630
+ // demo 是 opacity .7 叠在 .m-top 的白字上,等价于这个色值
4631
+ color: "rgba(255,255,255,0.7)"
4632
+ }
4633
+ },
4634
+ {
4635
+ type: "text",
4636
+ content: value,
4637
+ style: { fontSize: 20, fontWeight: "800", lineHeight: 1.1, color: "#ffffff" }
4638
+ },
4639
+ {
4640
+ type: "text",
4641
+ content: ` ${unit}`,
4642
+ style: {
4643
+ fontSize: 12,
4644
+ fontWeight: "600",
4645
+ lineHeight: 1.1,
4646
+ // demo 是 opacity .85
4647
+ color: "rgba(255,255,255,0.85)"
4648
+ }
4649
+ }
4650
+ ]
4651
+ },
4652
+ {
4653
+ type: "text",
4654
+ content: label,
4655
+ style: {
4656
+ fontSize: 11,
4657
+ lineHeight: 1.4,
4658
+ marginTop: 2,
4659
+ color: "rgba(255,255,255,0.85)"
4660
+ }
4661
+ }
4662
+ ]
4663
+ });
4664
+ var loseRow3 = {
4665
+ type: "flex",
4666
+ style: { align: "flex-start", gap: 10, padding: "7px 0" },
4667
+ children: [
4668
+ {
4669
+ type: "text",
4670
+ content: "",
4671
+ style: {
4672
+ width: 6,
4673
+ height: 6,
4674
+ radius: "50%",
4675
+ background: "#f53f3f",
4676
+ marginTop: 7,
4677
+ // demo 的 flex: none —— 文案换行时圆点不许被压扁
4678
+ flexShrink: "0"
4679
+ }
4680
+ },
4681
+ {
4682
+ type: "flex",
4683
+ style: { align: "baseline", gap: 4, wrap: true, flex: "1" },
4684
+ children: [
4685
+ {
4686
+ type: "text",
4687
+ content: "{{ item.b }}",
4688
+ style: {
4689
+ fontSize: 12.5,
4690
+ fontWeight: "700",
4691
+ lineHeight: 1.55,
4692
+ color: "#1f2533"
4693
+ }
4694
+ },
4695
+ {
4696
+ type: "text",
4697
+ content: "\u2014 {{ item.t }}",
4698
+ style: { fontSize: 12.5, lineHeight: 1.55, color: "#4a4038" }
4699
+ }
4700
+ ]
4701
+ }
4702
+ ]
4703
+ };
4704
+ var tierCard3 = {
4705
+ type: "box",
4706
+ style: {
4707
+ flex: "1",
4708
+ height: 119,
4709
+ radius: 12,
4710
+ background: "{{ item.key == current.key ? '#fffaf0' : '#ffffff' }}",
4711
+ borderStyle: "solid",
4712
+ borderWidth: "{{ item.key == current.key ? '2px' : '1px' }}",
4713
+ borderColor: "{{ item.key == current.key ? '#f0a000' : '#e5e8ed' }}",
4714
+ shadow: "{{ item.key == current.key ? '0 7px 18px rgba(240,160,0,0.1)' : 'none' }}",
4715
+ cursor: "pointer",
4716
+ transition: "border-color 0.15s, background 0.15s, box-shadow 0.15s"
4717
+ },
4718
+ // .tcol:hover { border-color: var(--gold) }
4719
+ hoverStyle: { borderColor: "#faad14" },
4720
+ action: {
4721
+ type: "sequence",
4722
+ actions: [
4723
+ { type: "setState", key: "period", value: "{{ index }}" },
4724
+ {
4725
+ type: "track",
4726
+ event: "popup_period_select",
4727
+ params: { period: "{{ item.key }}" }
4728
+ }
4729
+ ]
4730
+ },
4731
+ children: [
4732
+ {
4733
+ // .thot:top -9、字号 11、padding 2px 8px、radius 6。
4734
+ // 宽 38 = 2 字 × 11px + 左右 8px;居中靠 left: calc(50% - 19px)
4735
+ type: "text",
4736
+ rect: ["calc(50% - 19px)", -9, 38, 22],
4737
+ content: "\u63A8\u8350",
4738
+ visibleWhen: "item.hot",
4739
+ style: {
4740
+ background: ORANGE4,
4741
+ color: "#ffffff",
4742
+ fontSize: 11,
4743
+ fontWeight: "800",
4744
+ radius: 6,
4745
+ textAlign: "center",
4746
+ lineHeight: 22,
4747
+ whiteSpace: "nowrap"
4748
+ }
4749
+ },
4750
+ {
4751
+ type: "text",
4752
+ rect: [0, 12, "100%", 19],
4753
+ content: "{{ item.p }}",
4754
+ style: { fontSize: 13, lineHeight: 1.45, color: "#8a909c", textAlign: "center" }
4755
+ },
4756
+ {
4757
+ type: "flex",
4758
+ rect: [0, 36, "100%", 26],
4759
+ style: { justify: "center", align: "baseline" },
4760
+ children: [
4761
+ {
4762
+ // .tpr i:符号比数字小一号、字重 600
4763
+ type: "text",
4764
+ content: "\xA5",
4765
+ style: {
4766
+ fontSize: 14,
4767
+ fontWeight: "600",
4768
+ lineHeight: 1.2,
4769
+ color: "{{ item.key == current.key ? '#d46b08' : '#1f2533' }}"
4770
+ }
4771
+ },
4772
+ {
4773
+ type: "text",
4774
+ content: "{{ item.price }}",
4775
+ style: {
4776
+ fontSize: 21,
4777
+ fontWeight: "800",
4778
+ lineHeight: 1.2,
4779
+ color: "{{ item.key == current.key ? '#d46b08' : '#1f2533' }}"
4780
+ }
4781
+ }
4782
+ ]
4783
+ },
4784
+ {
4785
+ type: "text",
4786
+ rect: [4, 63, "calc(100% - 8px)", 32],
4787
+ content: "{{ item.per }}",
4788
+ style: {
4789
+ fontSize: 11,
4790
+ lineHeight: 1.5,
4791
+ textAlign: "center",
4792
+ color: "{{ item.key == current.key ? '#d46b08' : '#8a909c' }}",
4793
+ fontWeight: "{{ item.key == current.key ? '600' : '400' }}"
4794
+ }
4795
+ },
4796
+ {
4797
+ // .tflag 的 margin-top: auto(贴底)在绝对定位里直接写死 y = 119 - 9 - 15
4798
+ type: "text",
4799
+ rect: [0, 95, "100%", 15],
4800
+ content: "{{ item.flag }}",
4801
+ visibleWhen: "item.flag != ''",
4802
+ style: { fontSize: 11, lineHeight: 1.35, color: "#8a909c", textAlign: "center" }
4803
+ }
4804
+ ]
4805
+ };
4806
+ var quotaLow = {
4807
+ version: 1,
4808
+ type: "popup",
4809
+ meta: { name: "\u642C\u5BB6\u6B21\u6570\u5C06\u5C3D \xB7 \u989D\u5EA6\u8FDB\u5EA6\u6761\uFF08\u590D\u523B\u8FD0\u8425 demo\uFF09" },
4810
+ stage: {
4811
+ // .modal.period-price-modal { width: min(520px, calc(100vw - 24px)) }
4812
+ width: 520,
4813
+ height: "auto",
4814
+ layout: "flow",
4815
+ mask: true,
4816
+ maskClosable: false,
4817
+ closeButton: {
4818
+ // .m-close:24×24 的半透明白圆点,字符 ×、15px
4819
+ show: true,
4820
+ position: "top-right",
4821
+ offset: [14, 14],
4822
+ size: 24,
4823
+ icon: "\xD7",
4824
+ style: { background: "rgba(255,255,255,0.3)", fontSize: 15, color: "#ffffff" }
4825
+ },
4826
+ // .modal 的圆角与投影(--shadow-lg)
4827
+ style: { radius: 18, shadow: "0 28px 72px rgba(16,27,51,0.24)" },
4828
+ // demo 的 animation: pop .38s cubic-bezier(.16,1,.3,1) both
4829
+ // 注意 easing 的小数必须写成 0.16 —— 校验的正则不认 CSS 允许的 .16 简写
4830
+ animate: {
4831
+ name: "pop",
4832
+ duration: 380,
4833
+ easing: "cubic-bezier(0.16, 1, 0.3, 1)",
4834
+ fill: "both"
4835
+ }
4836
+ },
4837
+ keyframes: {
4838
+ pop: {
4839
+ from: { opacity: 0, transform: "translateY(14px) scale(0.96)" },
4840
+ to: { opacity: 1, transform: "none" }
4841
+ }
4842
+ },
4843
+ data: {
4844
+ // 实时统计走后端数据源。$source 填的是宿主注册过的数据源名(不是接口地址),
4845
+ // userStatistics 返回扁平对象,字段名就是后端的 snake_case
4846
+ stat: { $source: "userStatistics" },
4847
+ // 总额度:运营按当前套餐手填。为什么不走接口、以后怎么换,见文件头注释
4848
+ total: 30,
4849
+ // 三条都没有状态标签 —— demo 这一屏的 lose 配置里就没有 tag 字段
4850
+ lose: [
4851
+ { b: "\u6279\u91CF\u642C\u5BB6", t: "\u989D\u5EA6\u5F52\u96F6\u540E\u65E0\u6CD5\u7EE7\u7EED\u4E0A\u8D27" },
4852
+ { b: "1688 \u4E00\u4EF6\u4EE3\u53D1", t: "\u6E90\u5934\u8D27\u6E90\u65AD\u4F9B\uFF0C\u9009\u54C1\u3001\u94FA\u8D27\u3001\u4EE3\u53D1\u90FD\u8981\u624B\u52A8\u505A" },
4853
+ { b: "AI \u81EA\u52A8\u4F18\u5316", t: "\u65B0\u5546\u54C1\u4E0D\u518D\u8865\u4E3B\u6807\u9898 / \u77ED\u6807\u9898 / \u767D\u5E95\u56FE" }
4854
+ ],
4855
+ // 价格档位从后端数据源取,后端返回几档就渲染几档,配置时不用知道数量
4856
+ tiers: { $source: "listRenewTiers", params: { scene: "quota_low" } }
4857
+ },
4858
+ state: { period: 1 },
4859
+ derived: { current: { list: "tiers", indexBy: "period" } },
4860
+ nodes: [
4861
+ // ===== .m-top 深色渐变头部:(标签 + 额度条)同排 + 2×2 成果格 =====
4862
+ {
4863
+ type: "flex",
4864
+ style: {
4865
+ direction: "column",
4866
+ background: "linear-gradient(135deg,#2b0f0f,#3a1414)",
4867
+ padding: "20px 22px 16px"
4868
+ },
4869
+ children: [
4870
+ {
4871
+ // .m-top-head:右侧留 30px 给关闭按钮让位
4872
+ type: "flex",
4873
+ style: {
4874
+ align: "center",
4875
+ justify: "space-between",
4876
+ gap: 14,
4877
+ padding: "0 30px 0 0"
4878
+ },
4879
+ children: [
4880
+ {
4881
+ // .tag:flex: none,按内容宽度,不许被额度条挤扁
4882
+ type: "text",
4883
+ content: "\u26A1 \u642C\u5BB6\u6B21\u6570\u5373\u5C06\u7528\u5B8C",
4884
+ style: {
4885
+ background: "rgba(255,255,255,0.18)",
4886
+ color: "#ffffff",
4887
+ fontSize: 12,
4888
+ fontWeight: "700",
4889
+ radius: 6,
4890
+ padding: "3px 10px",
4891
+ flexShrink: "0",
4892
+ whiteSpace: "nowrap"
4893
+ }
4894
+ },
4895
+ {
4896
+ // ===== 额度进度条(本示例的重点)。.m-top .quota 反白配色版 =====
4897
+ type: "flex",
4898
+ style: {
4899
+ direction: "column",
4900
+ flex: "1",
4901
+ maxWidth: 280,
4902
+ background: "rgba(255,255,255,0.12)",
4903
+ borderWidth: 1,
4904
+ borderStyle: "solid",
4905
+ borderColor: "rgba(255,255,255,0.16)",
4906
+ radius: 7,
4907
+ padding: "3px 10px 4px"
4908
+ },
4909
+ children: [
4910
+ {
4911
+ // .qh:左「搬家次数剩余」,右加粗的剩余次数
4912
+ type: "flex",
4913
+ style: { align: "baseline", justify: "space-between" },
4914
+ children: [
4915
+ {
4916
+ type: "text",
4917
+ content: "\u642C\u5BB6\u6B21\u6570\u5269\u4F59",
4918
+ style: {
4919
+ fontSize: 10.5,
4920
+ lineHeight: 1.25,
4921
+ color: "rgba(255,255,255,0.85)"
4922
+ }
4923
+ },
4924
+ {
4925
+ type: "text",
4926
+ content: "{{ user.collectCount }} \u6B21",
4927
+ style: {
4928
+ fontSize: 12.5,
4929
+ fontWeight: "800",
4930
+ lineHeight: 1.15,
4931
+ color: "#ffb066"
4932
+ }
4933
+ }
4934
+ ]
4935
+ },
4936
+ {
4937
+ // .qbar 轨道。用 flex 而不是 box —— box 的子节点走绝对定位、必须给 rect,
4938
+ // 填充条要的是「跟着父级流」;overflow: hidden 必须写,
4939
+ // 否则填充条的直角会戳出轨道的圆角外面
4940
+ type: "flex",
4941
+ style: {
4942
+ height: 3,
4943
+ radius: 4,
4944
+ background: "rgba(255,255,255,0.2)",
4945
+ margin: "2px 0 1px",
4946
+ overflow: "hidden"
4947
+ },
4948
+ children: [
4949
+ {
4950
+ // 填充条。宽度是算出来的:已用 ÷ 总额度 × 100,节点 style 里的
4951
+ // 字符串同样走插值,所以百分比不需要后端多下发一个字段
4952
+ type: "box",
4953
+ style: {
4954
+ width: "{{ (total - user.collectCount) / total * 100 }}%",
4955
+ height: "100%",
4956
+ background: "linear-gradient(90deg,#f53f3f,#ff7a45)"
4957
+ }
4958
+ }
4959
+ ]
4960
+ },
4961
+ {
4962
+ // .qn
4963
+ type: "text",
4964
+ content: `\u5DF2\u7528 ${USED} / {{ total }} \u6B21`,
4965
+ style: {
4966
+ fontSize: 9,
4967
+ lineHeight: 1.25,
4968
+ color: "rgba(255,255,255,0.6)"
4969
+ }
4970
+ }
4971
+ ]
4972
+ }
4973
+ ]
4974
+ },
4975
+ {
4976
+ // .achieve:四格并列写死(扁平对象没法 bind 遍历),flex + wrap 复刻 2×2 grid。
4977
+ // 第一格的数字不是统计字段,而是「总额度 − 剩余次数」现算出来的
4978
+ type: "flex",
4979
+ style: { gap: 9, wrap: true, marginTop: 14 },
4980
+ children: [
4981
+ achieveCell3("\u5DF2\u7528", USED, "\u6B21", "\u642C\u5BB6\u6B21\u6570"),
4982
+ achieveCell3("\u5DF2\u4E0A\u67B6", "{{ stat.move_success_count }}", "\u4E2A", "\u7D2F\u8BA1\u4E0A\u67B6\u5546\u54C1"),
4983
+ achieveCell3("\u65E5\u5747", "{{ stat.avg_daily_move_count }}", "\u4E2A", "\u5E73\u5747\u6BCF\u5929\u4E0A\u67B6"),
4984
+ achieveCell3(
4985
+ "\u5DF2\u8865\u9F50",
4986
+ "{{ stat.white_image_fill_count }}",
4987
+ "\u5F20",
4988
+ "\u767D\u5E95\u56FE \xB7 \u5408\u89C4\u53EF\u62A5\u6D3B\u52A8"
4989
+ )
4990
+ ]
4991
+ }
4992
+ ]
4993
+ },
4994
+ // ===== .m-body 白底 =====
4995
+ {
4996
+ type: "flex",
4997
+ style: { direction: "column", background: "#ffffff", padding: "22px 26px 24px" },
4998
+ children: [
4999
+ {
5000
+ // .m-copy-panel
5001
+ type: "text",
5002
+ content: "\u642C\u5BB6\u6B21\u6570\u7528\u5B8C\uFF0C\u4EA7\u54C1\u80FD\u529B\u5C06\u53D7\u9650\uFF1A",
5003
+ style: {
5004
+ fontSize: 15,
5005
+ fontWeight: "800",
5006
+ lineHeight: 1.55,
5007
+ letterSpacing: -0.15,
5008
+ color: "#1f2533"
5009
+ }
5010
+ },
5011
+ {
5012
+ // .lose
5013
+ type: "repeat",
5014
+ bind: "lose",
5015
+ template: loseRow3,
5016
+ style: {
5017
+ direction: "column",
5018
+ marginTop: 14,
5019
+ background: "#ffe9e6",
5020
+ borderWidth: 1,
5021
+ borderStyle: "solid",
5022
+ borderColor: "#ffd0ca",
5023
+ radius: 12,
5024
+ padding: "7px 13px"
5025
+ }
5026
+ },
5027
+ {
5028
+ // .tiers 的 border-top:白名单没有 borderTop,用 1px 实心分隔条代替
5029
+ type: "box",
5030
+ style: { height: 1, background: "#eceef3", marginTop: 18 }
5031
+ },
5032
+ {
5033
+ // .tv:lead 被 normalizeTrialPricing 置空,所以整行都在 <b> 里
5034
+ //(字重 800、墨色),后面跟价格口径标记 .tv-tag
5035
+ type: "flex",
5036
+ style: { align: "center", gap: 8, marginTop: 17, marginBottom: 11 },
5037
+ children: [
5038
+ {
5039
+ type: "text",
5040
+ content: "\u4E13\u5C5E\u4F18\u60E0 \xB7 \u5012\u8BA1\u65F6",
5041
+ style: { fontSize: 13.5, fontWeight: "800", color: "#1f2533" }
5042
+ },
5043
+ {
5044
+ type: "text",
5045
+ content: "\u65B0\u4EBA\u9996\u8D2D\u4EF7",
5046
+ style: {
5047
+ alignSelf: "center",
5048
+ background: ORANGE4,
5049
+ color: "#ffffff",
5050
+ fontSize: 11,
5051
+ fontWeight: "800",
5052
+ radius: 5,
5053
+ padding: "2px 8px"
5054
+ }
5055
+ }
5056
+ ]
5057
+ },
5058
+ // .tcols:wide 版 gap 8
5059
+ { type: "repeat", bind: "tiers", style: { gap: 8 }, template: tierCard3 },
5060
+ {
5061
+ // .m-cta(th-loss 主题的红橙渐变)
5062
+ type: "flex",
5063
+ style: {
5064
+ justify: "center",
5065
+ align: "baseline",
5066
+ gap: 5,
5067
+ padding: "13px",
5068
+ radius: 11,
5069
+ background: "linear-gradient(90deg,#f53f3f,#ff7a45)",
5070
+ marginTop: 20,
5071
+ shadow: "0 8px 18px rgba(245,63,63,0.14)",
5072
+ transition: "transform 0.18s, box-shadow 0.18s",
5073
+ cursor: "pointer"
5074
+ },
5075
+ hoverStyle: {
5076
+ transform: "translateY(-1px)",
5077
+ shadow: "0 10px 22px rgba(245,63,63,0.2)"
5078
+ },
5079
+ action: {
5080
+ type: "sequence",
5081
+ actions: [
5082
+ {
5083
+ type: "track",
5084
+ event: "popup_renew_click",
5085
+ params: { period: "{{ current.key }}", stage: "quota_low" }
5086
+ },
5087
+ { type: "navigate", url: "{{ current.url }}" }
5088
+ ]
5089
+ },
5090
+ children: [
5091
+ {
5092
+ // .m-cta .ct
5093
+ type: "text",
5094
+ content: "\u7EED\u6EE1\u989D\u5EA6 \xB7",
5095
+ style: {
5096
+ fontSize: 14,
5097
+ fontWeight: "800",
5098
+ letterSpacing: -0.2,
5099
+ color: "#ffffff"
5100
+ }
5101
+ },
5102
+ {
5103
+ // .m-cta .cp —— demo 的 syncCTAPrice() 把它同步成「选中档位名 + 价格」
5104
+ type: "text",
5105
+ content: "{{ current.p }} \xA5{{ current.price }}",
5106
+ style: { fontSize: 16.5, fontWeight: "800", color: "#ffffff" }
5107
+ }
5108
+ ]
5109
+ },
5110
+ {
5111
+ // .m-ghost
5112
+ type: "text",
5113
+ content: "\u5347\u7EA7\u6216\u67E5\u770B\u66F4\u591A\u4EA7\u54C1\u5957\u9910",
5114
+ style: {
5115
+ fontSize: 12,
5116
+ color: "#8a909c",
5117
+ textAlign: "center",
5118
+ marginTop: 10,
5119
+ cursor: "pointer"
5120
+ },
5121
+ action: { type: "track", event: "popup_more_plans" }
5122
+ }
5123
+ ]
5124
+ }
5125
+ ]
5126
+ };
5127
+ var quota_low_default = quotaLow;
5128
+
4596
5129
  // src/docs/examples/index.ts
4597
5130
  var HOTSPOT_BG = "rgba(255,68,51,0.16)";
4598
5131
  var imageHotspot = {
@@ -4844,6 +5377,11 @@ var examples = [
4844
5377
  label: "\u246B \u590D\u523B\u7EBF\u4E0A\u5F39\u7A97 \xB7 1 \u5206\u94B1\u534A\u5E74\u5361\uFF08\u52A8\u753B\u6700\u5BC6\u7684\u4E00\u4EFD\uFF09",
4845
5378
  value: "giftRedPacket",
4846
5379
  dsl: gift_red_packet_default
5380
+ },
5381
+ {
5382
+ label: "\u246C \u590D\u523B\u8FD0\u8425 demo \xB7 \u642C\u5BB6\u6B21\u6570\u5C06\u5C3D\uFF08\u989D\u5EA6\u8FDB\u5EA6\u6761\uFF09",
5383
+ value: "quotaLow",
5384
+ dsl: quota_low_default
4847
5385
  }
4848
5386
  ];
4849
5387
  var examples_default = examples;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yaoxiu/marketing-dsl",
3
- "version": "2.5.0",
3
+ "version": "2.6.1",
4
4
  "type": "module",
5
5
  "description": "营销弹窗 DSL 解释器核心,纯逻辑无框架依赖",
6
6
  "license": "MIT",