@shwfed/config 3.0.12 → 3.0.13
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.
- package/dist/module.json +1 -1
- package/dist/runtime/components/config/blocks/2026-06-17/com.shwfed.block.tree.single/config.d.vue.ts +18 -18
- package/dist/runtime/components/config/blocks/2026-06-17/com.shwfed.block.tree.single/config.vue.d.ts +18 -18
- package/dist/runtime/components/config/blocks/2026-06-17/com.shwfed.block.tree.single/runtime.d.vue.ts +18 -18
- package/dist/runtime/components/config/blocks/2026-06-17/com.shwfed.block.tree.single/runtime.vue.d.ts +18 -18
- package/dist/runtime/components/config/blocks/2026-07-17/com.shwfed.block.invoice.digital/config.d.vue.ts +8 -8
- package/dist/runtime/components/config/blocks/2026-07-17/com.shwfed.block.invoice.digital/config.vue +264 -286
- package/dist/runtime/components/config/blocks/2026-07-17/com.shwfed.block.invoice.digital/config.vue.d.ts +8 -8
- package/dist/runtime/components/config/blocks/2026-07-17/com.shwfed.block.invoice.digital/runtime.d.vue.ts +8 -8
- package/dist/runtime/components/config/blocks/2026-07-17/com.shwfed.block.invoice.digital/runtime.vue +91 -291
- package/dist/runtime/components/config/blocks/2026-07-17/com.shwfed.block.invoice.digital/runtime.vue.d.ts +8 -8
- package/dist/runtime/components/config/blocks/2026-07-17/com.shwfed.block.invoice.digital/schema.d.ts +3 -28
- package/dist/runtime/components/config/blocks/2026-07-17/com.shwfed.block.invoice.digital/schema.js +9 -33
- package/dist/runtime/components/config/index.d.vue.ts +2 -2
- package/dist/runtime/components/config/index.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-22/com.shwfed.form.field.textarea/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-22/com.shwfed.form.field.textarea/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/utils/validation.js +9 -7
- package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/config.d.vue.ts +8 -8
- package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/config.vue.d.ts +8 -8
- package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/config.d.vue.ts +8 -8
- package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/config.vue.d.ts +8 -8
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/config.d.vue.ts +8 -8
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/config.vue.d.ts +8 -8
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/config.d.vue.ts +8 -8
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/config.vue.d.ts +8 -8
- package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-multi/config.d.vue.ts +8 -8
- package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-multi/config.vue.d.ts +8 -8
- package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-single/config.d.vue.ts +8 -8
- package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-single/config.vue.d.ts +8 -8
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/config.vue +57 -247
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/prompt.md +2 -2
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/runtime.vue +21 -124
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/schema.d.ts +5 -27
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/schema.js +10 -37
- package/dist/runtime/components/ui/invoice/InvoiceSheet.d.vue.ts +66 -0
- package/dist/runtime/components/ui/invoice/InvoiceSheet.vue +182 -0
- package/dist/runtime/components/ui/invoice/InvoiceSheet.vue.d.ts +66 -0
- package/dist/runtime/components/ui/invoice/index.d.ts +1 -0
- package/dist/runtime/components/ui/invoice/index.js +1 -0
- package/dist/runtime/components/ui/invoice-config/InvoiceConfigShell.d.vue.ts +36 -0
- package/dist/runtime/components/ui/invoice-config/InvoiceConfigShell.vue +41 -0
- package/dist/runtime/components/ui/invoice-config/InvoiceConfigShell.vue.d.ts +36 -0
- package/dist/runtime/components/{config/blocks/2026-07-17/com.shwfed.block.invoice.digital/expr-field.vue → ui/invoice-config/InvoiceExprField.vue} +4 -4
- package/dist/runtime/components/{config/blocks/2026-07-17/com.shwfed.block.invoice.digital/json-scope-provider.vue → ui/invoice-config/InvoiceJsonScope.vue} +3 -3
- package/dist/runtime/components/{config/blocks/2026-07-17/com.shwfed.block.invoice.digital/row-scope-provider.vue → ui/invoice-config/InvoiceRowScope.vue} +2 -2
- package/dist/runtime/components/ui/invoice-config/index.d.ts +4 -0
- package/dist/runtime/components/ui/invoice-config/index.js +4 -0
- package/dist/runtime/share/invoice-eval.d.ts +13 -0
- package/dist/runtime/share/invoice-eval.js +88 -0
- package/dist/runtime/share/invoice.d.ts +68 -0
- package/dist/runtime/share/invoice.js +35 -0
- package/package.json +1 -1
- /package/dist/runtime/components/{config/blocks/2026-07-17/com.shwfed.block.invoice.digital/expr-field.d.vue.ts → ui/invoice-config/InvoiceExprField.d.vue.ts} +0 -0
- /package/dist/runtime/components/{config/blocks/2026-07-17/com.shwfed.block.invoice.digital/expr-field.vue.d.ts → ui/invoice-config/InvoiceExprField.vue.d.ts} +0 -0
- /package/dist/runtime/components/{config/blocks/2026-07-17/com.shwfed.block.invoice.digital/json-scope-provider.d.vue.ts → ui/invoice-config/InvoiceJsonScope.d.vue.ts} +0 -0
- /package/dist/runtime/components/{config/blocks/2026-07-17/com.shwfed.block.invoice.digital/json-scope-provider.vue.d.ts → ui/invoice-config/InvoiceJsonScope.vue.d.ts} +0 -0
- /package/dist/runtime/components/{config/blocks/2026-07-17/com.shwfed.block.invoice.digital/row-scope-provider.d.vue.ts → ui/invoice-config/InvoiceRowScope.d.vue.ts} +0 -0
- /package/dist/runtime/components/{config/blocks/2026-07-17/com.shwfed.block.invoice.digital/row-scope-provider.vue.d.ts → ui/invoice-config/InvoiceRowScope.vue.d.ts} +0 -0
- /package/dist/runtime/{components/config/blocks/2026-07-17/com.shwfed.block.invoice.digital → share}/rmb.d.ts +0 -0
- /package/dist/runtime/{components/config/blocks/2026-07-17/com.shwfed.block.invoice.digital → share}/rmb.js +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数电票的票面骨架。国家税务总局的数电票是**一张底版 + 逐业务的差异**:抬头(双线标题 /
|
|
3
|
+
* 发票号码 / 开票日期)、购销双方、明细三表对齐、合计、价税合计大小写、备注框、开票人
|
|
4
|
+
* 在全家族逐像素相同;只有「业务标签」「明细有哪些列」「备注里有哪些栏」逐票不同。
|
|
5
|
+
* 这里收口相同的那部分,差异走 slot。
|
|
6
|
+
*
|
|
7
|
+
* 列宽(`colgroup`)刻意由调用方给:明细列逐业务不同,但**同一张票的三张表必须共用同
|
|
8
|
+
* 一份 colgroup** 才对得齐,所以它属于「块自己写一份、三处都用」,不属于骨架。同理
|
|
9
|
+
* 合计行(`items-foot`)—— 金额 / 税额落在第几列取决于该票的列,骨架不该猜。
|
|
10
|
+
*/
|
|
11
|
+
type __VLS_Props = {
|
|
12
|
+
/** 票面标题全文,如 `电子发票(增值税专用发票)`。骨架不认识票种。 */
|
|
13
|
+
title: string;
|
|
14
|
+
invoiceNumber: string;
|
|
15
|
+
issueDate: string;
|
|
16
|
+
buyer: {
|
|
17
|
+
name: string;
|
|
18
|
+
taxId: string;
|
|
19
|
+
};
|
|
20
|
+
seller: {
|
|
21
|
+
name: string;
|
|
22
|
+
taxId: string;
|
|
23
|
+
};
|
|
24
|
+
/** 价税合计(小写)。已格式化,空串即不打印 `¥`。 */
|
|
25
|
+
grandTotal: string;
|
|
26
|
+
/** 价税合计(大写)。空串即留空 —— 见 `useInvoiceEval` 的 `capital`。 */
|
|
27
|
+
grandTotalCapital: string;
|
|
28
|
+
issuer?: string;
|
|
29
|
+
/** 为真时票面中央叠加「红字发票」水印。 */
|
|
30
|
+
redLetter?: boolean;
|
|
31
|
+
/** 明细列数 —— 只用来给填充空行的 `colspan` 定宽。 */
|
|
32
|
+
columnCount: number;
|
|
33
|
+
/** 实际明细行数 —— 骨架据此补足填充空行。 */
|
|
34
|
+
rowCount: number;
|
|
35
|
+
/** 明细区最大高度(CSS 长度)。留空则明细区随行数增长,滚动条永不出现。 */
|
|
36
|
+
itemsMaxHeight?: string;
|
|
37
|
+
};
|
|
38
|
+
declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_13: {}, __VLS_15: {}, __VLS_17: {}, __VLS_19: {}, __VLS_21: {};
|
|
39
|
+
type __VLS_Slots = {} & {
|
|
40
|
+
business?: (props: typeof __VLS_1) => any;
|
|
41
|
+
} & {
|
|
42
|
+
colgroup?: (props: typeof __VLS_3) => any;
|
|
43
|
+
} & {
|
|
44
|
+
'items-head'?: (props: typeof __VLS_5) => any;
|
|
45
|
+
} & {
|
|
46
|
+
colgroup?: (props: typeof __VLS_13) => any;
|
|
47
|
+
} & {
|
|
48
|
+
'items-body'?: (props: typeof __VLS_15) => any;
|
|
49
|
+
} & {
|
|
50
|
+
colgroup?: (props: typeof __VLS_17) => any;
|
|
51
|
+
} & {
|
|
52
|
+
'items-foot'?: (props: typeof __VLS_19) => any;
|
|
53
|
+
} & {
|
|
54
|
+
remark?: (props: typeof __VLS_21) => any;
|
|
55
|
+
};
|
|
56
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
57
|
+
redLetter: boolean;
|
|
58
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
59
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
60
|
+
declare const _default: typeof __VLS_export;
|
|
61
|
+
export default _default;
|
|
62
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
63
|
+
new (): {
|
|
64
|
+
$slots: S;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as InvoiceSheet } from './InvoiceSheet.vue.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as InvoiceSheet } from "./InvoiceSheet.vue";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 票面配置面的外壳:左栏是票面分区导航,右栏是当前分区的栏位。分区**有哪些**逐票
|
|
3
|
+
* 不同(不动产系多一个「不动产信息」分区),但「按票面自上而下的阅读顺序分区、左选
|
|
4
|
+
* 右填」这套是全家族一致的,故收口在此。
|
|
5
|
+
*
|
|
6
|
+
* 右栏内容整个走默认 slot —— 调用方按自己的 `section` 分支渲染。壳不认识分区语义,
|
|
7
|
+
* 只负责选中态与布局。
|
|
8
|
+
*/
|
|
9
|
+
type __VLS_Props = {
|
|
10
|
+
sections: ReadonlyArray<{
|
|
11
|
+
key: string;
|
|
12
|
+
label: string;
|
|
13
|
+
icon: string;
|
|
14
|
+
}>;
|
|
15
|
+
};
|
|
16
|
+
type __VLS_ModelProps = {
|
|
17
|
+
'section': string;
|
|
18
|
+
};
|
|
19
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
20
|
+
declare var __VLS_12: {};
|
|
21
|
+
type __VLS_Slots = {} & {
|
|
22
|
+
default?: (props: typeof __VLS_12) => any;
|
|
23
|
+
};
|
|
24
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
25
|
+
"update:section": (value: string) => any;
|
|
26
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
27
|
+
"onUpdate:section"?: ((value: string) => any) | undefined;
|
|
28
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
29
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
30
|
+
declare const _default: typeof __VLS_export;
|
|
31
|
+
export default _default;
|
|
32
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
33
|
+
new (): {
|
|
34
|
+
$slots: S;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { Icon } from "@iconify/vue";
|
|
3
|
+
import { ScrollArea } from "../scroll-area";
|
|
4
|
+
defineOptions({ name: "ShwfedInvoiceConfigShell" });
|
|
5
|
+
defineProps({
|
|
6
|
+
sections: { type: Array, required: true }
|
|
7
|
+
});
|
|
8
|
+
const section = defineModel("section", { type: String, ...{ required: true } });
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<div class="flex min-w-0 gap-2 min-h-128">
|
|
13
|
+
<!-- 左栏:票面分区 -->
|
|
14
|
+
<div class="flex w-44 shrink-0 flex-col">
|
|
15
|
+
<ScrollArea class="flex-1">
|
|
16
|
+
<div
|
|
17
|
+
v-for="s in sections"
|
|
18
|
+
:key="s.key"
|
|
19
|
+
class="row"
|
|
20
|
+
:class="section === s.key ? 'bg-[color-mix(in_srgb,var(--primary)_10%,white)] text-(--primary)' : 'text-zinc-700 hover:bg-zinc-50'"
|
|
21
|
+
@click="section = s.key"
|
|
22
|
+
>
|
|
23
|
+
<Icon
|
|
24
|
+
:icon="s.icon"
|
|
25
|
+
class="size-4 shrink-0"
|
|
26
|
+
/>
|
|
27
|
+
<span class="flex-1 truncate">{{ s.label }}</span>
|
|
28
|
+
</div>
|
|
29
|
+
</ScrollArea>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<!-- 右栏 -->
|
|
33
|
+
<div class="flex min-w-0 flex-1 flex-col gap-3">
|
|
34
|
+
<slot />
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<style scoped>
|
|
40
|
+
.row{align-items:center;border-radius:.25rem;cursor:pointer;display:flex;font-size:.875rem;gap:.375rem;padding-block:.375rem;padding-left:.5rem;padding-right:.5rem;position:relative;transition:background-color .1s ease;-webkit-user-select:none;-moz-user-select:none;user-select:none}
|
|
41
|
+
</style>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 票面配置面的外壳:左栏是票面分区导航,右栏是当前分区的栏位。分区**有哪些**逐票
|
|
3
|
+
* 不同(不动产系多一个「不动产信息」分区),但「按票面自上而下的阅读顺序分区、左选
|
|
4
|
+
* 右填」这套是全家族一致的,故收口在此。
|
|
5
|
+
*
|
|
6
|
+
* 右栏内容整个走默认 slot —— 调用方按自己的 `section` 分支渲染。壳不认识分区语义,
|
|
7
|
+
* 只负责选中态与布局。
|
|
8
|
+
*/
|
|
9
|
+
type __VLS_Props = {
|
|
10
|
+
sections: ReadonlyArray<{
|
|
11
|
+
key: string;
|
|
12
|
+
label: string;
|
|
13
|
+
icon: string;
|
|
14
|
+
}>;
|
|
15
|
+
};
|
|
16
|
+
type __VLS_ModelProps = {
|
|
17
|
+
'section': string;
|
|
18
|
+
};
|
|
19
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
20
|
+
declare var __VLS_12: {};
|
|
21
|
+
type __VLS_Slots = {} & {
|
|
22
|
+
default?: (props: typeof __VLS_12) => any;
|
|
23
|
+
};
|
|
24
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
25
|
+
"update:section": (value: string) => any;
|
|
26
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
27
|
+
"onUpdate:section"?: ((value: string) => any) | undefined;
|
|
28
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
29
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
30
|
+
declare const _default: typeof __VLS_export;
|
|
31
|
+
export default _default;
|
|
32
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
33
|
+
new (): {
|
|
34
|
+
$slots: S;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { ExpressionEditor } from "
|
|
3
|
-
import { Field, FieldLabel } from "
|
|
4
|
-
import { Markdown } from "
|
|
5
|
-
defineOptions({ name: "
|
|
2
|
+
import { ExpressionEditor } from "../expression-editor";
|
|
3
|
+
import { Field, FieldLabel } from "../field";
|
|
4
|
+
import { Markdown } from "../markdown";
|
|
5
|
+
defineOptions({ name: "ShwfedInvoiceExprField" });
|
|
6
6
|
defineProps({
|
|
7
7
|
label: { type: String, required: true },
|
|
8
8
|
description: { type: String, required: false },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { injectCELContext, provideCELContext } from "
|
|
3
|
-
import { JSON_VAR } from "
|
|
4
|
-
defineOptions({ name: "
|
|
2
|
+
import { injectCELContext, provideCELContext } from "../../../utils/cel-context";
|
|
3
|
+
import { JSON_VAR } from "../../../share/invoice";
|
|
4
|
+
defineOptions({ name: "ShwfedInvoiceJsonScope" });
|
|
5
5
|
if (!injectCELContext().json) {
|
|
6
6
|
provideCELContext({
|
|
7
7
|
json: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { provideCELContext } from "
|
|
3
|
-
defineOptions({ name: "
|
|
2
|
+
import { provideCELContext } from "../../../utils/cel-context";
|
|
3
|
+
defineOptions({ name: "ShwfedInvoiceRowScope" });
|
|
4
4
|
provideCELContext({
|
|
5
5
|
item: {
|
|
6
6
|
type: "dyn",
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as InvoiceConfigShell } from './InvoiceConfigShell.vue.js';
|
|
2
|
+
export { default as InvoiceExprField } from './InvoiceExprField.vue.js';
|
|
3
|
+
export { default as InvoiceJsonScope } from './InvoiceJsonScope.vue.js';
|
|
4
|
+
export { default as InvoiceRowScope } from './InvoiceRowScope.vue.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as InvoiceConfigShell } from "./InvoiceConfigShell.vue";
|
|
2
|
+
export { default as InvoiceExprField } from "./InvoiceExprField.vue";
|
|
3
|
+
export { default as InvoiceJsonScope } from "./InvoiceJsonScope.vue";
|
|
4
|
+
export { default as InvoiceRowScope } from "./InvoiceRowScope.vue";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param requestExpr 读「请求」表达式的 getter(可选字段,未配置时返回 `undefined`)。
|
|
3
|
+
* getter 而不是值 —— 编辑器里改表达式要能重取,composable 自己 watch 它。
|
|
4
|
+
*/
|
|
5
|
+
export declare function useInvoiceEval(requestExpr: () => string | undefined): {
|
|
6
|
+
json: import("vue").Ref<unknown, unknown>;
|
|
7
|
+
evaluate: (expression: string | undefined, scope?: Record<string, unknown>) => unknown;
|
|
8
|
+
text: (expression: string | undefined, scope?: Record<string, unknown>) => string;
|
|
9
|
+
money: (expression: string | undefined, scope?: Record<string, unknown>) => string;
|
|
10
|
+
plain: (expression: string | undefined, scope?: Record<string, unknown>) => string;
|
|
11
|
+
bool: (expression: string | undefined, scope?: Record<string, unknown>) => boolean;
|
|
12
|
+
capital: (expression: string | undefined) => string;
|
|
13
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { computed, onMounted, ref, watch } from "vue";
|
|
2
|
+
import { Effect, Option } from "effect";
|
|
3
|
+
import { Fetch } from "fx-fetch";
|
|
4
|
+
import { cel } from "../utils/cel.js";
|
|
5
|
+
import { celBindings, injectCELContext } from "../utils/cel-context.js";
|
|
6
|
+
import { fetchJsonOption } from "./request.js";
|
|
7
|
+
import { toCapital } from "./rmb.js";
|
|
8
|
+
const MONEY_FORMAT = new Intl.NumberFormat("zh-CN", {
|
|
9
|
+
minimumFractionDigits: 2,
|
|
10
|
+
maximumFractionDigits: 2
|
|
11
|
+
});
|
|
12
|
+
function toFiniteNumber(v) {
|
|
13
|
+
if (typeof v === "number") return Number.isFinite(v) ? v : null;
|
|
14
|
+
if (typeof v === "string" && v.trim() !== "") {
|
|
15
|
+
const n = Number(v);
|
|
16
|
+
return Number.isFinite(n) ? n : null;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
export function useInvoiceEval(requestExpr) {
|
|
21
|
+
const inheritedContext = injectCELContext();
|
|
22
|
+
const json = ref(void 0);
|
|
23
|
+
const jsonOption = computed(
|
|
24
|
+
() => json.value === void 0 ? Option.none() : Option.some(json.value)
|
|
25
|
+
);
|
|
26
|
+
const hasRequest = computed(() => {
|
|
27
|
+
const expr = requestExpr();
|
|
28
|
+
return !!expr && expr.trim().length > 0;
|
|
29
|
+
});
|
|
30
|
+
function baseContext() {
|
|
31
|
+
const inherited = celBindings(inheritedContext);
|
|
32
|
+
if (!hasRequest.value && "json" in inherited) return inherited;
|
|
33
|
+
return { ...inherited, json: jsonOption.value };
|
|
34
|
+
}
|
|
35
|
+
async function refresh() {
|
|
36
|
+
const expr = requestExpr();
|
|
37
|
+
if (!expr || expr.trim().length === 0) {
|
|
38
|
+
json.value = void 0;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const program = Effect.gen(function* () {
|
|
42
|
+
const body = yield* fetchJsonOption(
|
|
43
|
+
yield* cel(expr, celBindings(inheritedContext))
|
|
44
|
+
);
|
|
45
|
+
return Option.getOrUndefined(body);
|
|
46
|
+
});
|
|
47
|
+
try {
|
|
48
|
+
json.value = await Effect.runPromise(Effect.provide(program, Fetch.layer));
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.warn("[shwfed-invoice] request failed", err);
|
|
51
|
+
json.value = void 0;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
onMounted(() => void refresh());
|
|
55
|
+
watch(() => requestExpr() ?? "", () => void refresh());
|
|
56
|
+
function evaluate(expression, scope) {
|
|
57
|
+
if (!expression || expression.trim().length === 0) return void 0;
|
|
58
|
+
try {
|
|
59
|
+
return Effect.runSync(cel(expression, { ...baseContext(), ...scope }));
|
|
60
|
+
} catch (err) {
|
|
61
|
+
console.warn("[shwfed-invoice] expression evaluation failed", expression, err);
|
|
62
|
+
return void 0;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function text(expression, scope) {
|
|
66
|
+
const v = evaluate(expression, scope);
|
|
67
|
+
return v === null || v === void 0 ? "" : String(v);
|
|
68
|
+
}
|
|
69
|
+
function money(expression, scope) {
|
|
70
|
+
const v = evaluate(expression, scope);
|
|
71
|
+
if (v === null || v === void 0) return "";
|
|
72
|
+
if (typeof v === "number") return Number.isFinite(v) ? MONEY_FORMAT.format(v) : "";
|
|
73
|
+
return String(v);
|
|
74
|
+
}
|
|
75
|
+
function plain(expression, scope) {
|
|
76
|
+
const v = evaluate(expression, scope);
|
|
77
|
+
if (v === null || v === void 0) return "";
|
|
78
|
+
return String(v);
|
|
79
|
+
}
|
|
80
|
+
function bool(expression, scope) {
|
|
81
|
+
return evaluate(expression, scope) === true;
|
|
82
|
+
}
|
|
83
|
+
function capital(expression) {
|
|
84
|
+
const n = toFiniteNumber(evaluate(expression));
|
|
85
|
+
return n === null ? "" : toCapital(n) ?? "";
|
|
86
|
+
}
|
|
87
|
+
return { json, evaluate, text, money, plain, bool, capital };
|
|
88
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
|
+
import type { Environment } from '../vendor/cel-js/lib/index.js';
|
|
3
|
+
import type { ResultType } from './expression.js';
|
|
4
|
+
/**
|
|
5
|
+
* The pieces every 数电票 block shares. The 税总 invoice family (通用数电票、不动产
|
|
6
|
+
* 经营租赁服务、不动产销售、建筑服务…) is one 版式 with a per-业务 label, per-业务
|
|
7
|
+
* 明细 columns and a per-业务 备注 — everything else (抬头 / 购销双方 / 合计 /
|
|
8
|
+
* 价税合计 / 开票人) is byte-identical across members. This module holds the schema
|
|
9
|
+
* half of that overlap; `ui/invoice` holds the rendering half and `share/
|
|
10
|
+
* invoice-eval.ts` the per-栏 evaluation.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately NOT a "common fields" factory: each block composes its own
|
|
13
|
+
* `Schema.Struct` so that `type` / `compatibilityDate` stay literal `Schema.tag`s
|
|
14
|
+
* at the folder that owns them. A factory would have to take those as arguments
|
|
15
|
+
* and hand back a half-built struct — more indirection than the duplication it
|
|
16
|
+
* would remove.
|
|
17
|
+
*/
|
|
18
|
+
export type Configure = (env: Environment) => void;
|
|
19
|
+
/**
|
|
20
|
+
* 票面绝大多数栏位是文本。上下文取值的表达式常被 CEL 推断为 `dyn`(只在运行时收
|
|
21
|
+
* 窄),所以与 animated-number / card 的字符串字段一样容忍 `dyn` / `optional`。
|
|
22
|
+
*/
|
|
23
|
+
export declare const textResult: ResultType;
|
|
24
|
+
/**
|
|
25
|
+
* 金额类栏位同时接受 `number` 与 `string`:格式化规则是「返回 string 原样打印,
|
|
26
|
+
* 返回 number 按票面惯例格式化」(见 `share/invoice-eval.ts` 的 `money`)。后端常以
|
|
27
|
+
* string 传小数以免丢精度,作者也可借此完全接管格式。
|
|
28
|
+
*/
|
|
29
|
+
export declare const moneyResult: ResultType;
|
|
30
|
+
export declare const listResult: ResultType;
|
|
31
|
+
export declare const boolResult: ResultType;
|
|
32
|
+
/**
|
|
33
|
+
* 票面自己的(可选)取数:`request` 求值出的 HTTP 响应体,票面**每一栏**都能读。
|
|
34
|
+
*
|
|
35
|
+
* 与「不内建 DataSource」的边界不冲突 —— 只有 `request`,没有 `data`:票面各栏本来
|
|
36
|
+
* 就是逐栏 CEL 映射,`json` 只是多了一个可读的上下文变量,而不是又一层「列表 → 行」
|
|
37
|
+
* 的取数抽象。不配置时 `json` 为 `none`,票面照旧从外层上下文(`item` / 详情页变量)
|
|
38
|
+
* 取值。
|
|
39
|
+
*
|
|
40
|
+
* 也导出给各块的 `config.vue` —— 它直接渲染 `ExpressionEditor`(不经过 schema),
|
|
41
|
+
* 不共享这份声明的话,编辑器会把 `json` 误报成 `Unknown variable`。镜像 card 块的
|
|
42
|
+
* `JSON_VAR`。
|
|
43
|
+
*/
|
|
44
|
+
export declare const JSON_VAR: {
|
|
45
|
+
readonly type: "optional<dyn>";
|
|
46
|
+
readonly label: "HTTP 响应体";
|
|
47
|
+
readonly description: "HTTP 响应体(配置了「请求」时为已解析 JSON,否则为 none)";
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* 登记 `json`,但外层 `configure` 已经声明过就跳过 —— 宿主(详情页)本来就可能把自己
|
|
51
|
+
* 的响应体以 `json` 喂进来,重复声明会被 CEL 注册表拒掉(`'json' is already
|
|
52
|
+
* registered`),整个配置面直接抛错。与 `registerLoopVariablesIfAbsent` 同解。
|
|
53
|
+
*
|
|
54
|
+
* 外层已有时以**外层的声明为准**(类型通常是 `dyn` 而不是这里的 `optional<dyn>`)。
|
|
55
|
+
* 运行期的对应规则见 `share/invoice-eval.ts` 的 `baseContext`:配了「请求」本块的
|
|
56
|
+
* 响应体遮蔽外层的 `json`,没配则外层的 `json` 原样透传。
|
|
57
|
+
*/
|
|
58
|
+
export declare function registerJsonIfAbsent(env: Environment): void;
|
|
59
|
+
/**
|
|
60
|
+
* 购买方 / 销售方信息栏。票面只有「名称」与「统一社会信用代码/纳税人识别号」两栏 ——
|
|
61
|
+
* 开户行与账号在真实发票上属于「备注」栏的自由文本(不是独立栏位),因此不建模,
|
|
62
|
+
* 由各块的备注承载。整个发票家族逐字相同,故在此共享。
|
|
63
|
+
*/
|
|
64
|
+
export declare function partySchema(configure: Configure, role: '购买方' | '销售方'): Schema.Struct<{
|
|
65
|
+
name: Schema.Schema<string, string, never>;
|
|
66
|
+
taxId: Schema.Schema<string, string, never>;
|
|
67
|
+
}>;
|
|
68
|
+
export type PartyValue = Schema.Schema.Type<ReturnType<typeof partySchema>>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { Expression } from "./expression.js";
|
|
3
|
+
export const textResult = (t) => t === "string" || t === "dyn" || t.startsWith("optional");
|
|
4
|
+
export const moneyResult = (t) => t === "number" || t === "string" || t === "dyn" || t.startsWith("optional");
|
|
5
|
+
export const listResult = (t) => t === "dyn" || t.startsWith("list") || t.startsWith("optional");
|
|
6
|
+
export const boolResult = (t) => t === "bool" || t === "dyn" || t.startsWith("optional");
|
|
7
|
+
export const JSON_VAR = {
|
|
8
|
+
type: "optional<dyn>",
|
|
9
|
+
label: "HTTP \u54CD\u5E94\u4F53",
|
|
10
|
+
description: "HTTP \u54CD\u5E94\u4F53\uFF08\u914D\u7F6E\u4E86\u300C\u8BF7\u6C42\u300D\u65F6\u4E3A\u5DF2\u89E3\u6790 JSON\uFF0C\u5426\u5219\u4E3A none\uFF09"
|
|
11
|
+
};
|
|
12
|
+
export function registerJsonIfAbsent(env) {
|
|
13
|
+
const declared = env.getDefinitions().variables.some((v) => v.name === "json");
|
|
14
|
+
if (declared) return;
|
|
15
|
+
env.registerVariable("json", JSON_VAR.type, {
|
|
16
|
+
label: JSON_VAR.label,
|
|
17
|
+
description: JSON_VAR.description
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export function partySchema(configure, role) {
|
|
21
|
+
const CelText = Expression({ configure, resultType: textResult });
|
|
22
|
+
return Schema.Struct({
|
|
23
|
+
name: CelText.annotations({
|
|
24
|
+
title: "\u540D\u79F0",
|
|
25
|
+
description: `\u8FD4\u56DE${role}\u540D\u79F0\uFF08\`string\`\uFF09\u7684 CEL \u8868\u8FBE\u5F0F`
|
|
26
|
+
}),
|
|
27
|
+
taxId: CelText.annotations({
|
|
28
|
+
title: "\u7EDF\u4E00\u793E\u4F1A\u4FE1\u7528\u4EE3\u7801/\u7EB3\u7A0E\u4EBA\u8BC6\u522B\u53F7",
|
|
29
|
+
description: `\u8FD4\u56DE${role}\u7EDF\u4E00\u793E\u4F1A\u4FE1\u7528\u4EE3\u7801\u6216\u7EB3\u7A0E\u4EBA\u8BC6\u522B\u53F7\uFF08\`string\`\uFF09\u7684 CEL \u8868\u8FBE\u5F0F`
|
|
30
|
+
})
|
|
31
|
+
}).annotations({
|
|
32
|
+
title: `${role}\u4FE1\u606F`,
|
|
33
|
+
description: `${role}\u7684\u540D\u79F0\u4E0E\u7EB3\u7A0E\u4EBA\u8BC6\u522B\u53F7\uFF1B\u5F00\u6237\u884C / \u8D26\u53F7\u8BF7\u5199\u5165\u300C\u5907\u6CE8\u300D`
|
|
34
|
+
});
|
|
35
|
+
}
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|