@kine-design/crud 0.0.1-beta.10 → 0.0.1-beta.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/components/crudPage/KCrudPage.tsx +19 -28
- package/components/crudPage/crudPage.css +0 -4
- package/components/formPage/KFormPage.tsx +40 -38
- package/components/formPage/formPage.css +14 -4
- package/composables/page/types.ts +4 -2
- package/composables/request/createRequest.ts +4 -0
- package/dist/composables/page/types.d.ts +4 -2
- package/dist/composables/request/createRequest.d.ts +2 -0
- package/dist/crud.css +221 -8
- package/dist/crud.js +348 -57
- package/package.json +3 -3
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
* 一个配置出一整个页面:标题 + 筛选 + 表格 + 分页 + 状态标签。
|
|
10
10
|
*/
|
|
11
11
|
import { defineComponent, type PropType } from 'vue';
|
|
12
|
-
import { useRouter } from 'vue-router';
|
|
13
12
|
import KTableColumn from 'kine-ui/components/tableColumn/KTableColumn.tsx';
|
|
14
13
|
import KTag from 'kine-ui/components/tag/KTag.tsx';
|
|
14
|
+
import KImage from 'kine-ui/components/image/KImage.tsx';
|
|
15
15
|
import KInput from 'kine-ui/components/input/KInput.tsx';
|
|
16
16
|
import KSelect from 'kine-ui/components/select/KSelect.tsx';
|
|
17
17
|
import KPageHeader from '../pageHeader/KPageHeader.tsx';
|
|
@@ -31,7 +31,6 @@ export default defineComponent({
|
|
|
31
31
|
},
|
|
32
32
|
|
|
33
33
|
setup(props, { slots }) {
|
|
34
|
-
const router = useRouter();
|
|
35
34
|
const {
|
|
36
35
|
page, pageSize, total, list, loading,
|
|
37
36
|
filters, onPageChange, onSearch, onReset,
|
|
@@ -67,32 +66,26 @@ export default defineComponent({
|
|
|
67
66
|
case 'status': return renderStatus(val);
|
|
68
67
|
case 'date': return formatDate(val);
|
|
69
68
|
case 'datetime': return formatDateTime(val);
|
|
69
|
+
case 'image': {
|
|
70
|
+
if (!val) return '';
|
|
71
|
+
const raw = String(val);
|
|
72
|
+
const resolver = props.config.imageResolver;
|
|
73
|
+
const src = resolver ? resolver(raw) : raw;
|
|
74
|
+
return (
|
|
75
|
+
<KImage
|
|
76
|
+
src={src}
|
|
77
|
+
previewSrcList={[src]}
|
|
78
|
+
width={40}
|
|
79
|
+
height={40}
|
|
80
|
+
fit="cover"
|
|
81
|
+
lazy
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
70
85
|
default: return val != null ? String(val) : '';
|
|
71
86
|
}
|
|
72
87
|
};
|
|
73
88
|
|
|
74
|
-
/** 行点击 → 跳转详情 */
|
|
75
|
-
const onRowClick = (e: MouseEvent) => {
|
|
76
|
-
const detailPath = props.config.detailPath;
|
|
77
|
-
if (!detailPath) return;
|
|
78
|
-
|
|
79
|
-
const tr = (e.target as HTMLElement).closest?.('tr');
|
|
80
|
-
if (!tr) return;
|
|
81
|
-
const tbody = tr.closest('tbody');
|
|
82
|
-
if (!tbody || tbody.classList.contains('k-table-empty')) return;
|
|
83
|
-
|
|
84
|
-
const rows = Array.from(tbody.querySelectorAll('tr'));
|
|
85
|
-
const index = rows.indexOf(tr as HTMLTableRowElement);
|
|
86
|
-
if (index < 0 || index >= list.value.length) return;
|
|
87
|
-
|
|
88
|
-
const row = list.value[index];
|
|
89
|
-
const key = props.config.rowKey ?? 'id';
|
|
90
|
-
const id = row[key];
|
|
91
|
-
if (id != null) {
|
|
92
|
-
router.push(`${detailPath}/${id}`);
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
|
|
96
89
|
/** 渲染筛选区表单项 */
|
|
97
90
|
const renderFilters = () => {
|
|
98
91
|
if (!props.config.filters?.length) return null;
|
|
@@ -126,13 +119,12 @@ export default defineComponent({
|
|
|
126
119
|
};
|
|
127
120
|
|
|
128
121
|
return () => (
|
|
129
|
-
<div class=
|
|
122
|
+
<div class="k-crud-page">
|
|
130
123
|
<KPageHeader title={props.config.title}>
|
|
131
124
|
{{ extra: slots.headerExtra }}
|
|
132
125
|
</KPageHeader>
|
|
133
126
|
|
|
134
|
-
<
|
|
135
|
-
<KSearchTable
|
|
127
|
+
<KSearchTable
|
|
136
128
|
data={list.value}
|
|
137
129
|
loading={loading.value}
|
|
138
130
|
total={total.value}
|
|
@@ -168,7 +160,6 @@ export default defineComponent({
|
|
|
168
160
|
empty: slots.empty,
|
|
169
161
|
}}
|
|
170
162
|
</KSearchTable>
|
|
171
|
-
</div>
|
|
172
163
|
</div>
|
|
173
164
|
);
|
|
174
165
|
},
|
|
@@ -52,50 +52,52 @@ export default defineComponent({
|
|
|
52
52
|
const title = isEdit.value ? `编辑${props.config.title}` : `新建${props.config.title}`;
|
|
53
53
|
|
|
54
54
|
return (
|
|
55
|
-
<div class="k-form-page">
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
<div class="k-fp-header
|
|
59
|
-
<
|
|
60
|
-
|
|
55
|
+
<div class="k-form-page-wrapper">
|
|
56
|
+
<div class="k-form-page">
|
|
57
|
+
{/* 页头 */}
|
|
58
|
+
<div class="k-fp-header">
|
|
59
|
+
<div class="k-fp-header-left">
|
|
60
|
+
<KButton text="←" onClick={goBack} />
|
|
61
|
+
<h1 class="k-fp-title">{title}</h1>
|
|
62
|
+
</div>
|
|
63
|
+
<div class="k-fp-header-right">
|
|
64
|
+
{slots.headerExtra?.()}
|
|
65
|
+
</div>
|
|
61
66
|
</div>
|
|
62
|
-
<div class="k-fp-header-right">
|
|
63
|
-
{slots.headerExtra?.()}
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
{/* 表单 */}
|
|
69
|
+
<KFormCard>
|
|
70
|
+
{slots.beforeFields?.({ formData })}
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
72
|
+
<div class={`k-fp-grid k-fp-grid--${cols}`}>
|
|
73
|
+
{props.config.fields.map(field => {
|
|
74
|
+
const span = field.span === 'full' ? cols : (field.span ?? 1);
|
|
75
|
+
return (
|
|
76
|
+
<div
|
|
77
|
+
key={field.param}
|
|
78
|
+
class="k-fp-field"
|
|
79
|
+
style={span > 1 ? { gridColumn: `span ${span}` } : undefined}
|
|
80
|
+
>
|
|
81
|
+
<label class="k-fp-label">
|
|
82
|
+
{field.label}
|
|
83
|
+
{field.required && <span class="k-fp-required">*</span>}
|
|
84
|
+
</label>
|
|
85
|
+
{renderFormField(field, formData, errors.value, validateField, slots)}
|
|
86
|
+
{errors.value[field.param] && (
|
|
87
|
+
<span class="k-fp-error">{errors.value[field.param]}</span>
|
|
88
|
+
)}
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
})}
|
|
92
|
+
</div>
|
|
92
93
|
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
{slots.afterFields?.({ formData })}
|
|
95
|
+
</KFormCard>
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
{slots.default?.({ formData })}
|
|
98
|
+
</div>
|
|
97
99
|
|
|
98
|
-
{/* 底部操作栏 */}
|
|
100
|
+
{/* 底部操作栏 — 在 max-width 容器外,撑满内容区 */}
|
|
99
101
|
<KStickyActionBar>
|
|
100
102
|
{{
|
|
101
103
|
default: () => slots.actions?.({ formData, submit, saveDraft, submitting }) ?? (
|
|
@@ -79,10 +79,10 @@
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
.k-form-card-body {
|
|
82
|
-
padding:
|
|
82
|
+
padding: var(--kine-spacing-10);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
/*
|
|
85
|
+
/* 有 header 时,body 顶部不需要额外间距(header 自带 padding-bottom) */
|
|
86
86
|
.k-form-card-header + .k-form-card-body {
|
|
87
87
|
padding-top: 0;
|
|
88
88
|
}
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
z-index: 10;
|
|
98
98
|
display: flex;
|
|
99
99
|
align-items: center;
|
|
100
|
-
justify-content:
|
|
100
|
+
justify-content: flex-end;
|
|
101
101
|
padding: var(--kine-spacing-6) var(--kine-spacing-12);
|
|
102
102
|
background: var(--kine-color-bg-tertiary, #fff);
|
|
103
103
|
border-top: 1px solid var(--kine-color-border-default, #e5e7eb);
|
|
@@ -247,9 +247,19 @@
|
|
|
247
247
|
KFormPage / KMasterDetailPage — 表单页布局
|
|
248
248
|
================================================================ */
|
|
249
249
|
|
|
250
|
+
/* wrapper: 全宽容器,承载 sticky bar 出血 */
|
|
251
|
+
.k-form-page-wrapper {
|
|
252
|
+
display: flex;
|
|
253
|
+
flex-direction: column;
|
|
254
|
+
min-height: 100%;
|
|
255
|
+
}
|
|
256
|
+
|
|
250
257
|
.k-form-page {
|
|
251
258
|
max-width: 960px;
|
|
252
|
-
|
|
259
|
+
width: 100%;
|
|
260
|
+
margin: 0 auto;
|
|
261
|
+
padding: 0 0 var(--kine-spacing-10);
|
|
262
|
+
flex: 1;
|
|
253
263
|
}
|
|
254
264
|
|
|
255
265
|
.k-master-detail-page {
|
|
@@ -16,7 +16,7 @@ export interface CrudColumnConfig {
|
|
|
16
16
|
/** 列宽 */
|
|
17
17
|
width?: string;
|
|
18
18
|
/** 列类型,影响渲染方式 */
|
|
19
|
-
type?: 'text' | 'status' | 'date' | 'datetime';
|
|
19
|
+
type?: 'text' | 'status' | 'date' | 'datetime' | 'image';
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/** 筛选项配置 */
|
|
@@ -55,6 +55,8 @@ export interface CrudPageConfig {
|
|
|
55
55
|
pageSize?: number;
|
|
56
56
|
/** 行主键字段,默认 'id' */
|
|
57
57
|
rowKey?: string;
|
|
58
|
-
/**
|
|
58
|
+
/** 详情页路由前缀,用于构建查看/编辑路由:`${detailPath}/${row[rowKey]}` */
|
|
59
59
|
detailPath?: string;
|
|
60
|
+
/** 图片列 src 转换函数,将原始值转为可访问 URL */
|
|
61
|
+
imageResolver?: (raw: string) => string;
|
|
60
62
|
}
|
|
@@ -17,6 +17,8 @@ import { RequestBuilder, type RequestBuilderContext } from './requestBuilder';
|
|
|
17
17
|
// ────────────────────────────────────────────────────────────────────────────
|
|
18
18
|
|
|
19
19
|
export interface RequestClient {
|
|
20
|
+
/** 请求基础 URL */
|
|
21
|
+
readonly baseURL: string;
|
|
20
22
|
/** 简便方法,直接返回 Promise<T> */
|
|
21
23
|
send<T>(method: RequestMethod, url: string, body?: unknown): Promise<T>;
|
|
22
24
|
/** GET 请求 */
|
|
@@ -85,6 +87,8 @@ export function createRequest(options: RequestOptions = {}): RequestClient {
|
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
const client: RequestClient = {
|
|
90
|
+
baseURL: context.baseURL,
|
|
91
|
+
|
|
88
92
|
send: <T>(method: RequestMethod, url: string, body?: unknown) =>
|
|
89
93
|
createBuilder(method, url, body).execute<T>(),
|
|
90
94
|
|
|
@@ -15,7 +15,7 @@ export interface CrudColumnConfig {
|
|
|
15
15
|
/** 列宽 */
|
|
16
16
|
width?: string;
|
|
17
17
|
/** 列类型,影响渲染方式 */
|
|
18
|
-
type?: 'text' | 'status' | 'date' | 'datetime';
|
|
18
|
+
type?: 'text' | 'status' | 'date' | 'datetime' | 'image';
|
|
19
19
|
}
|
|
20
20
|
/** 筛选项配置 */
|
|
21
21
|
export interface CrudFilterConfig {
|
|
@@ -54,6 +54,8 @@ export interface CrudPageConfig {
|
|
|
54
54
|
pageSize?: number;
|
|
55
55
|
/** 行主键字段,默认 'id' */
|
|
56
56
|
rowKey?: string;
|
|
57
|
-
/**
|
|
57
|
+
/** 详情页路由前缀,用于构建查看/编辑路由:`${detailPath}/${row[rowKey]}` */
|
|
58
58
|
detailPath?: string;
|
|
59
|
+
/** 图片列 src 转换函数,将原始值转为可访问 URL */
|
|
60
|
+
imageResolver?: (raw: string) => string;
|
|
59
61
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { RequestMethod, RequestOptions } from './types';
|
|
2
2
|
import { RequestBuilder } from './requestBuilder';
|
|
3
3
|
export interface RequestClient {
|
|
4
|
+
/** 请求基础 URL */
|
|
5
|
+
readonly baseURL: string;
|
|
4
6
|
/** 简便方法,直接返回 Promise<T> */
|
|
5
7
|
send<T>(method: RequestMethod, url: string, body?: unknown): Promise<T>;
|
|
6
8
|
/** GET 请求 */
|
package/dist/crud.css
CHANGED
|
@@ -737,6 +737,213 @@
|
|
|
737
737
|
pointer-events: none;
|
|
738
738
|
cursor: not-allowed;
|
|
739
739
|
}
|
|
740
|
+
/**
|
|
741
|
+
* @description kine-ui image 样式 — Phosphor 主题
|
|
742
|
+
* @author 阿怪
|
|
743
|
+
* @date 2026/2/26
|
|
744
|
+
* @version v1.0.0
|
|
745
|
+
*
|
|
746
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
747
|
+
*/
|
|
748
|
+
|
|
749
|
+
/* === 图片容器 === */
|
|
750
|
+
.k-image {
|
|
751
|
+
position: relative;
|
|
752
|
+
display: inline-block;
|
|
753
|
+
overflow: hidden;
|
|
754
|
+
width: 100%;
|
|
755
|
+
height: 100%;
|
|
756
|
+
background: var(--kine-color-bg-secondary);
|
|
757
|
+
border-radius: var(--kine-radius-xs);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/* 有预览时鼠标变指针 */
|
|
761
|
+
.k-image-previewable {
|
|
762
|
+
cursor: zoom-in;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/* === 实际图片元素 === */
|
|
766
|
+
.k-image-inner {
|
|
767
|
+
display: block;
|
|
768
|
+
width: 100%;
|
|
769
|
+
height: 100%;
|
|
770
|
+
transition: opacity var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.k-image-inner-hidden {
|
|
774
|
+
opacity: 0;
|
|
775
|
+
position: absolute;
|
|
776
|
+
top: 0;
|
|
777
|
+
left: 0;
|
|
778
|
+
pointer-events: none;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/* === 占位容器(loading / error 共用) === */
|
|
782
|
+
.k-image-placeholder {
|
|
783
|
+
display: flex;
|
|
784
|
+
flex-direction: column;
|
|
785
|
+
align-items: center;
|
|
786
|
+
justify-content: center;
|
|
787
|
+
gap: var(--kine-spacing-4);
|
|
788
|
+
min-width: 100px;
|
|
789
|
+
min-height: 100px;
|
|
790
|
+
width: 100%;
|
|
791
|
+
height: 100%;
|
|
792
|
+
font-family: var(--kine-font-family-mono);
|
|
793
|
+
font-size: var(--kine-font-size-sm);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
.k-image-placeholder-icon {
|
|
797
|
+
width: 40px;
|
|
798
|
+
height: 40px;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/* loading 状态:accent 微光 + 动画 */
|
|
802
|
+
.k-image-loading {
|
|
803
|
+
color: var(--kine-color-text-muted);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
.k-image-loading .k-image-placeholder-icon {
|
|
807
|
+
animation: k-image-pulse 1.6s ease-in-out infinite;
|
|
808
|
+
color: var(--kine-color-accent-default);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
@keyframes k-image-pulse {
|
|
812
|
+
0%, 100% { opacity: 0.3; }
|
|
813
|
+
50% { opacity: 1; }
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/* error 状态 */
|
|
817
|
+
.k-image-error {
|
|
818
|
+
color: var(--kine-color-semantic-error);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
.k-image-error-text {
|
|
822
|
+
color: var(--kine-color-text-muted);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
/* === 全屏预览遮罩层 === */
|
|
826
|
+
.k-image-preview-mask {
|
|
827
|
+
position: fixed;
|
|
828
|
+
inset: 0;
|
|
829
|
+
background: color-mix(in srgb, var(--kine-color-bg-primary) 90%, transparent);
|
|
830
|
+
display: flex;
|
|
831
|
+
align-items: center;
|
|
832
|
+
justify-content: center;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/* === 预览图片本体 === */
|
|
836
|
+
.k-image-preview-img {
|
|
837
|
+
max-width: 90vw;
|
|
838
|
+
max-height: 85vh;
|
|
839
|
+
object-fit: contain;
|
|
840
|
+
border-radius: var(--kine-radius-xs);
|
|
841
|
+
box-shadow: 0 0 40px color-mix(in srgb, var(--kine-color-accent-default) 20%, transparent);
|
|
842
|
+
transition: transform var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
|
|
843
|
+
user-select: none;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/* === 工具栏 === */
|
|
847
|
+
.k-image-preview-toolbar {
|
|
848
|
+
position: absolute;
|
|
849
|
+
top: var(--kine-spacing-8);
|
|
850
|
+
left: 50%;
|
|
851
|
+
transform: translateX(-50%);
|
|
852
|
+
display: flex;
|
|
853
|
+
align-items: center;
|
|
854
|
+
gap: var(--kine-spacing-2);
|
|
855
|
+
background: var(--kine-color-bg-secondary);
|
|
856
|
+
border: 1px solid var(--kine-color-border-default);
|
|
857
|
+
border-radius: var(--kine-radius-xs);
|
|
858
|
+
padding: var(--kine-spacing-2) var(--kine-spacing-4);
|
|
859
|
+
font-family: var(--kine-font-family-mono);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/* === 工具按钮 === */
|
|
863
|
+
.k-image-preview-btn {
|
|
864
|
+
display: inline-flex;
|
|
865
|
+
align-items: center;
|
|
866
|
+
justify-content: center;
|
|
867
|
+
width: 28px;
|
|
868
|
+
height: 28px;
|
|
869
|
+
border: none;
|
|
870
|
+
border-radius: var(--kine-radius-xs);
|
|
871
|
+
background: transparent;
|
|
872
|
+
color: var(--kine-color-text-secondary);
|
|
873
|
+
font-size: 16px;
|
|
874
|
+
cursor: pointer;
|
|
875
|
+
transition:
|
|
876
|
+
color var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
|
|
877
|
+
background var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.k-image-preview-btn:hover {
|
|
881
|
+
color: var(--kine-color-text-primary);
|
|
882
|
+
background: color-mix(in srgb, var(--kine-color-accent-default) 15%, transparent);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
.k-image-preview-close:hover {
|
|
886
|
+
color: var(--kine-color-semantic-error);
|
|
887
|
+
background: color-mix(in srgb, var(--kine-color-semantic-error) 15%, transparent);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/* 当前缩放比例显示 */
|
|
891
|
+
.k-image-preview-scale {
|
|
892
|
+
font-size: var(--kine-font-size-sm);
|
|
893
|
+
color: var(--kine-color-text-muted);
|
|
894
|
+
min-width: 40px;
|
|
895
|
+
text-align: center;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
/* === 预览切换箭头 === */
|
|
899
|
+
.k-image-preview-arrow {
|
|
900
|
+
position: absolute;
|
|
901
|
+
top: 50%;
|
|
902
|
+
transform: translateY(-50%);
|
|
903
|
+
display: flex;
|
|
904
|
+
align-items: center;
|
|
905
|
+
justify-content: center;
|
|
906
|
+
width: 44px;
|
|
907
|
+
height: 44px;
|
|
908
|
+
border: 1px solid var(--kine-color-border-default);
|
|
909
|
+
border-radius: 50%;
|
|
910
|
+
background: color-mix(in srgb, var(--kine-color-bg-secondary) 80%, transparent);
|
|
911
|
+
color: var(--kine-color-text-primary);
|
|
912
|
+
font-size: 26px;
|
|
913
|
+
cursor: pointer;
|
|
914
|
+
transition:
|
|
915
|
+
background var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
|
|
916
|
+
border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.k-image-preview-arrow:hover {
|
|
920
|
+
background: var(--kine-color-bg-secondary);
|
|
921
|
+
border-color: var(--kine-color-accent-default);
|
|
922
|
+
color: var(--kine-color-accent-default);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
.k-image-preview-arrow-prev {
|
|
926
|
+
left: 20px;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
.k-image-preview-arrow-next {
|
|
930
|
+
right: 20px;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/* === 图片计数 === */
|
|
934
|
+
.k-image-preview-counter {
|
|
935
|
+
position: absolute;
|
|
936
|
+
bottom: var(--kine-spacing-8);
|
|
937
|
+
left: 50%;
|
|
938
|
+
transform: translateX(-50%);
|
|
939
|
+
font-family: var(--kine-font-family-mono);
|
|
940
|
+
font-size: var(--kine-font-size-sm);
|
|
941
|
+
color: var(--kine-color-text-muted);
|
|
942
|
+
background: var(--kine-color-bg-secondary);
|
|
943
|
+
border: 1px solid var(--kine-color-border-default);
|
|
944
|
+
border-radius: var(--kine-radius-xs);
|
|
945
|
+
padding: var(--kine-spacing-1) var(--kine-spacing-5);
|
|
946
|
+
}
|
|
740
947
|
/**
|
|
741
948
|
* @description kine-ui input 样式
|
|
742
949
|
* @author 阿怪
|
|
@@ -1101,10 +1308,6 @@ textarea.k-input {
|
|
|
1101
1308
|
width: 100%;
|
|
1102
1309
|
}
|
|
1103
1310
|
|
|
1104
|
-
/* ===== 行可点击 ===== */
|
|
1105
|
-
.k-crud-page--clickable .k-tbody .k-tr {
|
|
1106
|
-
cursor: pointer;
|
|
1107
|
-
}
|
|
1108
1311
|
/**
|
|
1109
1312
|
* @description KLoginPage 登录页样式 — Phosphor 主题
|
|
1110
1313
|
* @author 阿怪
|
|
@@ -1846,10 +2049,10 @@ textarea.k-input {
|
|
|
1846
2049
|
}
|
|
1847
2050
|
|
|
1848
2051
|
.k-form-card-body {
|
|
1849
|
-
padding:
|
|
2052
|
+
padding: var(--kine-spacing-10);
|
|
1850
2053
|
}
|
|
1851
2054
|
|
|
1852
|
-
/*
|
|
2055
|
+
/* 有 header 时,body 顶部不需要额外间距(header 自带 padding-bottom) */
|
|
1853
2056
|
.k-form-card-header + .k-form-card-body {
|
|
1854
2057
|
padding-top: 0;
|
|
1855
2058
|
}
|
|
@@ -1864,7 +2067,7 @@ textarea.k-input {
|
|
|
1864
2067
|
z-index: 10;
|
|
1865
2068
|
display: flex;
|
|
1866
2069
|
align-items: center;
|
|
1867
|
-
justify-content:
|
|
2070
|
+
justify-content: flex-end;
|
|
1868
2071
|
padding: var(--kine-spacing-6) var(--kine-spacing-12);
|
|
1869
2072
|
background: var(--kine-color-bg-tertiary, #fff);
|
|
1870
2073
|
border-top: 1px solid var(--kine-color-border-default, #e5e7eb);
|
|
@@ -2014,9 +2217,19 @@ textarea.k-input {
|
|
|
2014
2217
|
KFormPage / KMasterDetailPage — 表单页布局
|
|
2015
2218
|
================================================================ */
|
|
2016
2219
|
|
|
2220
|
+
/* wrapper: 全宽容器,承载 sticky bar 出血 */
|
|
2221
|
+
.k-form-page-wrapper {
|
|
2222
|
+
display: flex;
|
|
2223
|
+
flex-direction: column;
|
|
2224
|
+
min-height: 100%;
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2017
2227
|
.k-form-page {
|
|
2018
2228
|
max-width: 960px;
|
|
2019
|
-
|
|
2229
|
+
width: 100%;
|
|
2230
|
+
margin: 0 auto;
|
|
2231
|
+
padding: 0 0 var(--kine-spacing-10);
|
|
2232
|
+
flex: 1;
|
|
2020
2233
|
}
|
|
2021
2234
|
|
|
2022
2235
|
.k-master-detail-page {
|
package/dist/crud.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Comment, Fragment, Teleport, computed, createApp, createTextVNode, createVNode, defineComponent, h, inject, isRef, mergeProps, nextTick, onBeforeUnmount, onMounted, onUnmounted, provide, reactive, ref, resolveComponent, shallowRef, toRef, triggerRef, watch } from "vue";
|
|
2
|
-
import { useRoute, useRouter } from "vue-router";
|
|
3
2
|
import { QueryClient, VueQueryPlugin, useMutation, useQuery, useQueryClient } from "@tanstack/vue-query";
|
|
4
3
|
import { createPinia, defineStore } from "pinia";
|
|
4
|
+
import { useRoute, useRouter } from "vue-router";
|
|
5
5
|
//#region \0rolldown/runtime.js
|
|
6
6
|
var __create = Object.create;
|
|
7
7
|
var __defProp = Object.defineProperty;
|
|
@@ -153,7 +153,7 @@ var KContent_default = /* @__PURE__ */ defineComponent({
|
|
|
153
153
|
});
|
|
154
154
|
//#endregion
|
|
155
155
|
//#region ../core/components/template/table/api.ts
|
|
156
|
-
var props$
|
|
156
|
+
var props$10 = {
|
|
157
157
|
data: {
|
|
158
158
|
type: Array,
|
|
159
159
|
default: () => []
|
|
@@ -268,8 +268,8 @@ function useTable() {
|
|
|
268
268
|
*
|
|
269
269
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
270
270
|
*/
|
|
271
|
-
var { props: props$
|
|
272
|
-
props: props$
|
|
271
|
+
var { props: props$9 } = {
|
|
272
|
+
props: props$10,
|
|
273
273
|
useTable
|
|
274
274
|
};
|
|
275
275
|
var KTable_default = /* @__PURE__ */ defineComponent((_props, { slots }) => {
|
|
@@ -336,11 +336,11 @@ var KTable_default = /* @__PURE__ */ defineComponent((_props, { slots }) => {
|
|
|
336
336
|
};
|
|
337
337
|
}, {
|
|
338
338
|
name: "KTable",
|
|
339
|
-
props: props$
|
|
339
|
+
props: props$9
|
|
340
340
|
});
|
|
341
341
|
//#endregion
|
|
342
342
|
//#region ../core/components/base/input/api.ts
|
|
343
|
-
var props$
|
|
343
|
+
var props$8 = {
|
|
344
344
|
type: {
|
|
345
345
|
type: String,
|
|
346
346
|
default: "text"
|
|
@@ -412,12 +412,12 @@ function useInput(props, ctx) {
|
|
|
412
412
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
413
413
|
*/
|
|
414
414
|
var InputCore = {
|
|
415
|
-
props: props$
|
|
415
|
+
props: props$8,
|
|
416
416
|
useInput
|
|
417
417
|
};
|
|
418
418
|
//#endregion
|
|
419
419
|
//#region ../core/components/base/button/api.ts
|
|
420
|
-
var props$
|
|
420
|
+
var props$7 = {
|
|
421
421
|
text: {
|
|
422
422
|
type: String,
|
|
423
423
|
default: ""
|
|
@@ -494,12 +494,12 @@ function useButton(props, { slots }) {
|
|
|
494
494
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
495
495
|
*/
|
|
496
496
|
var ButtonCore = {
|
|
497
|
-
props: props$
|
|
497
|
+
props: props$7,
|
|
498
498
|
useButton
|
|
499
499
|
};
|
|
500
500
|
//#endregion
|
|
501
501
|
//#region ../core/components/base/select/api.ts
|
|
502
|
-
var props$
|
|
502
|
+
var props$6 = {
|
|
503
503
|
modelValue: {
|
|
504
504
|
type: void 0,
|
|
505
505
|
default: ""
|
|
@@ -809,7 +809,7 @@ function useSelect$1(props, ctx) {
|
|
|
809
809
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
810
810
|
*/
|
|
811
811
|
var SelectCore = {
|
|
812
|
-
props: props$
|
|
812
|
+
props: props$6,
|
|
813
813
|
useSelect: useSelect$1
|
|
814
814
|
};
|
|
815
815
|
//#endregion
|
|
@@ -6159,7 +6159,7 @@ var computePosition = (reference, floating, options) => {
|
|
|
6159
6159
|
};
|
|
6160
6160
|
//#endregion
|
|
6161
6161
|
//#region ../core/components/template/pagination/api.ts
|
|
6162
|
-
var props$
|
|
6162
|
+
var props$4 = {
|
|
6163
6163
|
total: {
|
|
6164
6164
|
type: Number,
|
|
6165
6165
|
default: 0
|
|
@@ -6318,7 +6318,7 @@ function usePagination(props, currentValue) {
|
|
|
6318
6318
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
6319
6319
|
*/
|
|
6320
6320
|
var PaginationCore = {
|
|
6321
|
-
props: props$
|
|
6321
|
+
props: props$4,
|
|
6322
6322
|
usePagination
|
|
6323
6323
|
};
|
|
6324
6324
|
//#endregion
|
|
@@ -6761,6 +6761,154 @@ var TableColumnCore = { props: {
|
|
|
6761
6761
|
}
|
|
6762
6762
|
} };
|
|
6763
6763
|
//#endregion
|
|
6764
|
+
//#region ../core/components/base/image/api.ts
|
|
6765
|
+
var props$2 = {
|
|
6766
|
+
src: {
|
|
6767
|
+
type: String,
|
|
6768
|
+
required: true
|
|
6769
|
+
},
|
|
6770
|
+
alt: {
|
|
6771
|
+
type: String,
|
|
6772
|
+
default: ""
|
|
6773
|
+
},
|
|
6774
|
+
fit: {
|
|
6775
|
+
type: String,
|
|
6776
|
+
default: "cover",
|
|
6777
|
+
enum: [
|
|
6778
|
+
"contain",
|
|
6779
|
+
"cover",
|
|
6780
|
+
"fill",
|
|
6781
|
+
"none",
|
|
6782
|
+
"scale-down"
|
|
6783
|
+
]
|
|
6784
|
+
},
|
|
6785
|
+
width: {
|
|
6786
|
+
type: [String, Number],
|
|
6787
|
+
default: void 0
|
|
6788
|
+
},
|
|
6789
|
+
height: {
|
|
6790
|
+
type: [String, Number],
|
|
6791
|
+
default: void 0
|
|
6792
|
+
},
|
|
6793
|
+
lazy: {
|
|
6794
|
+
type: Boolean,
|
|
6795
|
+
default: false
|
|
6796
|
+
},
|
|
6797
|
+
previewSrcList: {
|
|
6798
|
+
type: Array,
|
|
6799
|
+
default: () => []
|
|
6800
|
+
},
|
|
6801
|
+
zIndex: {
|
|
6802
|
+
type: Number,
|
|
6803
|
+
default: 2e3
|
|
6804
|
+
}
|
|
6805
|
+
};
|
|
6806
|
+
//#endregion
|
|
6807
|
+
//#region ../core/components/base/image/useImage.ts
|
|
6808
|
+
/**
|
|
6809
|
+
* @description image hook
|
|
6810
|
+
* @author 阿怪
|
|
6811
|
+
* @date 2026/2/26
|
|
6812
|
+
* @version v1.0.0
|
|
6813
|
+
*
|
|
6814
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
6815
|
+
*/
|
|
6816
|
+
function useImage(props, emit) {
|
|
6817
|
+
const status = ref("loading");
|
|
6818
|
+
const previewVisible = ref(false);
|
|
6819
|
+
const previewIndex = ref(0);
|
|
6820
|
+
const previewScale = ref(1);
|
|
6821
|
+
const previewRotate = ref(0);
|
|
6822
|
+
/** 重置加载状态(src 变化时调用) */
|
|
6823
|
+
const reset = () => {
|
|
6824
|
+
status.value = "loading";
|
|
6825
|
+
};
|
|
6826
|
+
const handleLoad = (e) => {
|
|
6827
|
+
status.value = "loaded";
|
|
6828
|
+
emit("load", e);
|
|
6829
|
+
};
|
|
6830
|
+
const handleError = (e) => {
|
|
6831
|
+
status.value = "error";
|
|
6832
|
+
emit("error", e);
|
|
6833
|
+
};
|
|
6834
|
+
/** 打开全屏预览,定位到 src 在 previewSrcList 中的位置 */
|
|
6835
|
+
const openPreview = () => {
|
|
6836
|
+
if (!props.previewSrcList || props.previewSrcList.length === 0) return;
|
|
6837
|
+
const idx = props.previewSrcList.indexOf(props.src);
|
|
6838
|
+
previewIndex.value = idx >= 0 ? idx : 0;
|
|
6839
|
+
previewScale.value = 1;
|
|
6840
|
+
previewRotate.value = 0;
|
|
6841
|
+
previewVisible.value = true;
|
|
6842
|
+
};
|
|
6843
|
+
const closePreview = () => {
|
|
6844
|
+
previewVisible.value = false;
|
|
6845
|
+
};
|
|
6846
|
+
/** 预览切换到上一张 */
|
|
6847
|
+
const previewPrev = () => {
|
|
6848
|
+
const total = props.previewSrcList.length;
|
|
6849
|
+
if (total === 0) return;
|
|
6850
|
+
previewIndex.value = (previewIndex.value - 1 + total) % total;
|
|
6851
|
+
previewScale.value = 1;
|
|
6852
|
+
previewRotate.value = 0;
|
|
6853
|
+
emit("switch", previewIndex.value);
|
|
6854
|
+
};
|
|
6855
|
+
/** 预览切换到下一张 */
|
|
6856
|
+
const previewNext = () => {
|
|
6857
|
+
const total = props.previewSrcList.length;
|
|
6858
|
+
if (total === 0) return;
|
|
6859
|
+
previewIndex.value = (previewIndex.value + 1) % total;
|
|
6860
|
+
previewScale.value = 1;
|
|
6861
|
+
previewRotate.value = 0;
|
|
6862
|
+
emit("switch", previewIndex.value);
|
|
6863
|
+
};
|
|
6864
|
+
/** 预览放大 */
|
|
6865
|
+
const zoomIn = () => {
|
|
6866
|
+
previewScale.value = Math.min(previewScale.value + .25, 5);
|
|
6867
|
+
};
|
|
6868
|
+
/** 预览缩小 */
|
|
6869
|
+
const zoomOut = () => {
|
|
6870
|
+
previewScale.value = Math.max(previewScale.value - .25, .25);
|
|
6871
|
+
};
|
|
6872
|
+
/** 顺时针旋转 90° */
|
|
6873
|
+
const rotate = () => {
|
|
6874
|
+
previewRotate.value = (previewRotate.value + 90) % 360;
|
|
6875
|
+
};
|
|
6876
|
+
watch(() => props.src, reset);
|
|
6877
|
+
onMounted(() => {
|
|
6878
|
+
if (props.lazy) status.value = "loading";
|
|
6879
|
+
});
|
|
6880
|
+
return {
|
|
6881
|
+
status,
|
|
6882
|
+
previewVisible,
|
|
6883
|
+
previewIndex,
|
|
6884
|
+
previewScale,
|
|
6885
|
+
previewRotate,
|
|
6886
|
+
handleLoad,
|
|
6887
|
+
handleError,
|
|
6888
|
+
openPreview,
|
|
6889
|
+
closePreview,
|
|
6890
|
+
previewPrev,
|
|
6891
|
+
previewNext,
|
|
6892
|
+
zoomIn,
|
|
6893
|
+
zoomOut,
|
|
6894
|
+
rotate
|
|
6895
|
+
};
|
|
6896
|
+
}
|
|
6897
|
+
//#endregion
|
|
6898
|
+
//#region ../core/components/base/image/index.ts
|
|
6899
|
+
/**
|
|
6900
|
+
* @description image core 导出
|
|
6901
|
+
* @author 阿怪
|
|
6902
|
+
* @date 2026/2/26
|
|
6903
|
+
* @version v1.0.0
|
|
6904
|
+
*
|
|
6905
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
6906
|
+
*/
|
|
6907
|
+
var ImageCore = {
|
|
6908
|
+
props: props$2,
|
|
6909
|
+
useImage
|
|
6910
|
+
};
|
|
6911
|
+
//#endregion
|
|
6764
6912
|
//#region ../ui/components/pagination/KPagination.tsx
|
|
6765
6913
|
/**
|
|
6766
6914
|
* @description kine-ui pagination 组件
|
|
@@ -6986,7 +7134,7 @@ var KTableColumn_default = /* @__PURE__ */ defineComponent({
|
|
|
6986
7134
|
*
|
|
6987
7135
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
6988
7136
|
*/
|
|
6989
|
-
var { props } = TagCore;
|
|
7137
|
+
var { props: props$1 } = TagCore;
|
|
6990
7138
|
var KTag_default = /* @__PURE__ */ defineComponent((_props, { slots, emit }) => {
|
|
6991
7139
|
const props = _props;
|
|
6992
7140
|
return () => {
|
|
@@ -7020,10 +7168,153 @@ var KTag_default = /* @__PURE__ */ defineComponent((_props, { slots, emit }) =>
|
|
|
7020
7168
|
};
|
|
7021
7169
|
}, {
|
|
7022
7170
|
name: "KTag",
|
|
7023
|
-
props,
|
|
7171
|
+
props: props$1,
|
|
7024
7172
|
emits: ["close", "click"]
|
|
7025
7173
|
});
|
|
7026
7174
|
//#endregion
|
|
7175
|
+
//#region ../ui/components/image/KImage.tsx
|
|
7176
|
+
/**
|
|
7177
|
+
* @description kine-ui image 图片组件
|
|
7178
|
+
* @author 阿怪
|
|
7179
|
+
* @date 2026/2/26
|
|
7180
|
+
* @version v1.0.0
|
|
7181
|
+
*
|
|
7182
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
7183
|
+
*/
|
|
7184
|
+
var { props } = ImageCore;
|
|
7185
|
+
/** 加载中占位图标(sci-fi 风格) */
|
|
7186
|
+
var LoadingPlaceholder = () => createVNode("div", { "class": "k-image-placeholder k-image-loading" }, [createVNode("svg", {
|
|
7187
|
+
"viewBox": "0 0 24 24",
|
|
7188
|
+
"fill": "none",
|
|
7189
|
+
"class": "k-image-placeholder-icon"
|
|
7190
|
+
}, [
|
|
7191
|
+
createVNode("rect", {
|
|
7192
|
+
"x": "3",
|
|
7193
|
+
"y": "3",
|
|
7194
|
+
"width": "18",
|
|
7195
|
+
"height": "18",
|
|
7196
|
+
"rx": "2",
|
|
7197
|
+
"stroke": "currentColor",
|
|
7198
|
+
"stroke-width": "1.5"
|
|
7199
|
+
}, null),
|
|
7200
|
+
createVNode("circle", {
|
|
7201
|
+
"cx": "8.5",
|
|
7202
|
+
"cy": "8.5",
|
|
7203
|
+
"r": "1.5",
|
|
7204
|
+
"fill": "currentColor",
|
|
7205
|
+
"opacity": "0.5"
|
|
7206
|
+
}, null),
|
|
7207
|
+
createVNode("path", {
|
|
7208
|
+
"d": "M3 15l5-5 4 4 3-3 6 6",
|
|
7209
|
+
"stroke": "currentColor",
|
|
7210
|
+
"stroke-width": "1.5",
|
|
7211
|
+
"stroke-linecap": "round"
|
|
7212
|
+
}, null)
|
|
7213
|
+
])]);
|
|
7214
|
+
/** 加载失败占位图标 */
|
|
7215
|
+
var ErrorPlaceholder = () => createVNode("div", { "class": "k-image-placeholder k-image-error" }, [createVNode("svg", {
|
|
7216
|
+
"viewBox": "0 0 24 24",
|
|
7217
|
+
"fill": "none",
|
|
7218
|
+
"class": "k-image-placeholder-icon"
|
|
7219
|
+
}, [createVNode("rect", {
|
|
7220
|
+
"x": "3",
|
|
7221
|
+
"y": "3",
|
|
7222
|
+
"width": "18",
|
|
7223
|
+
"height": "18",
|
|
7224
|
+
"rx": "2",
|
|
7225
|
+
"stroke": "currentColor",
|
|
7226
|
+
"stroke-width": "1.5"
|
|
7227
|
+
}, null), createVNode("path", {
|
|
7228
|
+
"d": "M9 9l6 6M15 9l-6 6",
|
|
7229
|
+
"stroke": "currentColor",
|
|
7230
|
+
"stroke-width": "1.5",
|
|
7231
|
+
"stroke-linecap": "round"
|
|
7232
|
+
}, null)]), createVNode("span", { "class": "k-image-error-text" }, [createTextVNode("加载失败")])]);
|
|
7233
|
+
var KImage_default = /* @__PURE__ */ defineComponent((_props, { slots, emit }) => {
|
|
7234
|
+
const cProps = _props;
|
|
7235
|
+
const { status, previewVisible, previewIndex, previewScale, previewRotate, handleLoad, handleError, openPreview, closePreview, previewPrev, previewNext, zoomIn, zoomOut, rotate } = useImage(cProps, (event, payload) => emit(event, payload));
|
|
7236
|
+
const hasPreview = computed(() => cProps.previewSrcList && cProps.previewSrcList.length > 0);
|
|
7237
|
+
return () => {
|
|
7238
|
+
const currentPreviewSrc = hasPreview.value ? cProps.previewSrcList[previewIndex.value] : cProps.src;
|
|
7239
|
+
return createVNode(Fragment, null, [createVNode("div", {
|
|
7240
|
+
"class": ["k-image", status.value === "loaded" && hasPreview.value ? "k-image-previewable" : ""],
|
|
7241
|
+
"style": {
|
|
7242
|
+
width: cProps.width != null ? typeof cProps.width === "number" ? `${cProps.width}px` : cProps.width : void 0,
|
|
7243
|
+
height: cProps.height != null ? typeof cProps.height === "number" ? `${cProps.height}px` : cProps.height : void 0
|
|
7244
|
+
},
|
|
7245
|
+
"onClick": hasPreview.value ? openPreview : void 0
|
|
7246
|
+
}, [
|
|
7247
|
+
status.value === "loading" && (slots.placeholder ? slots.placeholder() : createVNode(LoadingPlaceholder, null, null)),
|
|
7248
|
+
status.value === "error" && (slots.error ? slots.error() : createVNode(ErrorPlaceholder, null, null)),
|
|
7249
|
+
createVNode("img", {
|
|
7250
|
+
"class": ["k-image-inner", status.value !== "loaded" ? "k-image-inner-hidden" : ""],
|
|
7251
|
+
"src": cProps.src,
|
|
7252
|
+
"alt": cProps.alt,
|
|
7253
|
+
"loading": cProps.lazy ? "lazy" : "eager",
|
|
7254
|
+
"style": { objectFit: cProps.fit },
|
|
7255
|
+
"onLoad": handleLoad,
|
|
7256
|
+
"onError": handleError
|
|
7257
|
+
}, null)
|
|
7258
|
+
]), hasPreview.value && previewVisible.value && createVNode(Teleport, { "to": "body" }, { default: () => [createVNode("div", {
|
|
7259
|
+
"class": "k-image-preview-mask",
|
|
7260
|
+
"style": { zIndex: cProps.zIndex },
|
|
7261
|
+
"onClick": (e) => {
|
|
7262
|
+
if (e.target === e.currentTarget) closePreview();
|
|
7263
|
+
}
|
|
7264
|
+
}, [
|
|
7265
|
+
createVNode("div", { "class": "k-image-preview-toolbar" }, [
|
|
7266
|
+
createVNode("button", {
|
|
7267
|
+
"class": "k-image-preview-btn",
|
|
7268
|
+
"onClick": zoomOut,
|
|
7269
|
+
"title": "缩小"
|
|
7270
|
+
}, [createTextVNode("-")]),
|
|
7271
|
+
createVNode("span", { "class": "k-image-preview-scale" }, [Math.round(previewScale.value * 100), createTextVNode("%")]),
|
|
7272
|
+
createVNode("button", {
|
|
7273
|
+
"class": "k-image-preview-btn",
|
|
7274
|
+
"onClick": zoomIn,
|
|
7275
|
+
"title": "放大"
|
|
7276
|
+
}, [createTextVNode("+")]),
|
|
7277
|
+
createVNode("button", {
|
|
7278
|
+
"class": "k-image-preview-btn",
|
|
7279
|
+
"onClick": rotate,
|
|
7280
|
+
"title": "旋转"
|
|
7281
|
+
}, [createTextVNode("↻")]),
|
|
7282
|
+
createVNode("button", {
|
|
7283
|
+
"class": "k-image-preview-btn k-image-preview-close",
|
|
7284
|
+
"onClick": closePreview,
|
|
7285
|
+
"title": "关闭"
|
|
7286
|
+
}, [createTextVNode("✕")])
|
|
7287
|
+
]),
|
|
7288
|
+
createVNode("img", {
|
|
7289
|
+
"class": "k-image-preview-img",
|
|
7290
|
+
"src": currentPreviewSrc,
|
|
7291
|
+
"style": { transform: `scale(${previewScale.value}) rotate(${previewRotate.value}deg)` },
|
|
7292
|
+
"alt": ""
|
|
7293
|
+
}, null),
|
|
7294
|
+
cProps.previewSrcList.length > 1 && createVNode(Fragment, null, [createVNode("button", {
|
|
7295
|
+
"class": "k-image-preview-arrow k-image-preview-arrow-prev",
|
|
7296
|
+
"onClick": previewPrev
|
|
7297
|
+
}, [createTextVNode("‹")]), createVNode("button", {
|
|
7298
|
+
"class": "k-image-preview-arrow k-image-preview-arrow-next",
|
|
7299
|
+
"onClick": previewNext
|
|
7300
|
+
}, [createTextVNode("›")])]),
|
|
7301
|
+
cProps.previewSrcList.length > 1 && createVNode("div", { "class": "k-image-preview-counter" }, [
|
|
7302
|
+
previewIndex.value + 1,
|
|
7303
|
+
createTextVNode(" / "),
|
|
7304
|
+
cProps.previewSrcList.length
|
|
7305
|
+
])
|
|
7306
|
+
])] })]);
|
|
7307
|
+
};
|
|
7308
|
+
}, {
|
|
7309
|
+
name: "KImage",
|
|
7310
|
+
props,
|
|
7311
|
+
emits: [
|
|
7312
|
+
"load",
|
|
7313
|
+
"error",
|
|
7314
|
+
"switch"
|
|
7315
|
+
]
|
|
7316
|
+
});
|
|
7317
|
+
//#endregion
|
|
7027
7318
|
//#region ../ui/components/input/KInput.tsx
|
|
7028
7319
|
/**
|
|
7029
7320
|
* @description kine-ui input 组件
|
|
@@ -8002,6 +8293,7 @@ function createRequest(options = {}) {
|
|
|
8002
8293
|
return builder;
|
|
8003
8294
|
}
|
|
8004
8295
|
const client = {
|
|
8296
|
+
baseURL: context.baseURL,
|
|
8005
8297
|
send: (method, url, body) => createBuilder(method, url, body).execute(),
|
|
8006
8298
|
get: (url, params) => createBuilder("GET", url, params).execute(),
|
|
8007
8299
|
post: (url, body) => createBuilder("POST", url, body).execute(),
|
|
@@ -8387,7 +8679,6 @@ var KCrudPage_default = /* @__PURE__ */ defineComponent({
|
|
|
8387
8679
|
required: true
|
|
8388
8680
|
} },
|
|
8389
8681
|
setup(props, { slots }) {
|
|
8390
|
-
const router = useRouter();
|
|
8391
8682
|
const { page, pageSize, total, list, loading, filters, onPageChange, onSearch, onReset } = useCrudPage(props.config);
|
|
8392
8683
|
/** 格式化日期 */
|
|
8393
8684
|
const formatDate = (val) => {
|
|
@@ -8419,22 +8710,23 @@ var KCrudPage_default = /* @__PURE__ */ defineComponent({
|
|
|
8419
8710
|
case "status": return renderStatus(val);
|
|
8420
8711
|
case "date": return formatDate(val);
|
|
8421
8712
|
case "datetime": return formatDateTime(val);
|
|
8713
|
+
case "image": {
|
|
8714
|
+
if (!val) return "";
|
|
8715
|
+
const raw = String(val);
|
|
8716
|
+
const resolver = props.config.imageResolver;
|
|
8717
|
+
const src = resolver ? resolver(raw) : raw;
|
|
8718
|
+
return createVNode(KImage_default, {
|
|
8719
|
+
"src": src,
|
|
8720
|
+
"previewSrcList": [src],
|
|
8721
|
+
"width": 40,
|
|
8722
|
+
"height": 40,
|
|
8723
|
+
"fit": "cover",
|
|
8724
|
+
"lazy": true
|
|
8725
|
+
}, null);
|
|
8726
|
+
}
|
|
8422
8727
|
default: return val != null ? String(val) : "";
|
|
8423
8728
|
}
|
|
8424
8729
|
};
|
|
8425
|
-
/** 行点击 → 跳转详情 */
|
|
8426
|
-
const onRowClick = (e) => {
|
|
8427
|
-
const detailPath = props.config.detailPath;
|
|
8428
|
-
if (!detailPath) return;
|
|
8429
|
-
const tr = e.target.closest?.("tr");
|
|
8430
|
-
if (!tr) return;
|
|
8431
|
-
const tbody = tr.closest("tbody");
|
|
8432
|
-
if (!tbody || tbody.classList.contains("k-table-empty")) return;
|
|
8433
|
-
const index = Array.from(tbody.querySelectorAll("tr")).indexOf(tr);
|
|
8434
|
-
if (index < 0 || index >= list.value.length) return;
|
|
8435
|
-
const id = list.value[index][props.config.rowKey ?? "id"];
|
|
8436
|
-
if (id != null) router.push(`${detailPath}/${id}`);
|
|
8437
|
-
};
|
|
8438
8730
|
/** 渲染筛选区表单项 */
|
|
8439
8731
|
const renderFilters = () => {
|
|
8440
8732
|
if (!props.config.filters?.length) return null;
|
|
@@ -8460,7 +8752,7 @@ var KCrudPage_default = /* @__PURE__ */ defineComponent({
|
|
|
8460
8752
|
}
|
|
8461
8753
|
}, null)]));
|
|
8462
8754
|
};
|
|
8463
|
-
return () => createVNode("div", { "class":
|
|
8755
|
+
return () => createVNode("div", { "class": "k-crud-page" }, [createVNode(KPageHeader_default, { "title": props.config.title }, { extra: slots.headerExtra }), createVNode(KSearchTable_default, {
|
|
8464
8756
|
"data": list.value,
|
|
8465
8757
|
"loading": loading.value,
|
|
8466
8758
|
"total": total.value,
|
|
@@ -8483,7 +8775,7 @@ var KCrudPage_default = /* @__PURE__ */ defineComponent({
|
|
|
8483
8775
|
}, { default: customSlot ? (scope) => customSlot(scope) : col.type ? (scope) => renderCell(col, scope.row) : void 0 });
|
|
8484
8776
|
}),
|
|
8485
8777
|
empty: slots.empty
|
|
8486
|
-
})])
|
|
8778
|
+
})]);
|
|
8487
8779
|
}
|
|
8488
8780
|
});
|
|
8489
8781
|
//#endregion
|
|
@@ -10688,7 +10980,7 @@ var KFormPage_default = /* @__PURE__ */ defineComponent({
|
|
|
10688
10980
|
return () => {
|
|
10689
10981
|
if (loading.value) return createVNode("div", { "class": "k-fp-loading" }, [createTextVNode("加载中...")]);
|
|
10690
10982
|
const title = isEdit.value ? `编辑${props.config.title}` : `新建${props.config.title}`;
|
|
10691
|
-
return createVNode("div", { "class": "k-form-page" }, [
|
|
10983
|
+
return createVNode("div", { "class": "k-form-page-wrapper" }, [createVNode("div", { "class": "k-form-page" }, [
|
|
10692
10984
|
createVNode("div", { "class": "k-fp-header" }, [createVNode("div", { "class": "k-fp-header-left" }, [createVNode(KButton_default, {
|
|
10693
10985
|
"text": "←",
|
|
10694
10986
|
"onClick": goBack
|
|
@@ -10709,31 +11001,30 @@ var KFormPage_default = /* @__PURE__ */ defineComponent({
|
|
|
10709
11001
|
})]),
|
|
10710
11002
|
slots.afterFields?.({ formData })
|
|
10711
11003
|
] }),
|
|
10712
|
-
slots.default?.({ formData })
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
]);
|
|
11004
|
+
slots.default?.({ formData })
|
|
11005
|
+
]), createVNode(KStickyActionBar_default, null, { default: () => slots.actions?.({
|
|
11006
|
+
formData,
|
|
11007
|
+
submit,
|
|
11008
|
+
saveDraft,
|
|
11009
|
+
submitting
|
|
11010
|
+
}) ?? createVNode(Fragment, null, [
|
|
11011
|
+
createVNode(KButton_default, {
|
|
11012
|
+
"text": "取消",
|
|
11013
|
+
"onClick": goBack
|
|
11014
|
+
}, null),
|
|
11015
|
+
props.config.showDraft && createVNode(KButton_default, {
|
|
11016
|
+
"text": "保存草稿",
|
|
11017
|
+
"disabled": submitting.value,
|
|
11018
|
+
"onClick": () => saveDraft()
|
|
11019
|
+
}, null),
|
|
11020
|
+
createVNode(KButton_default, {
|
|
11021
|
+
"type": "primary",
|
|
11022
|
+
"text": submitting.value ? "保存中..." : props.config.submitText ?? "保存",
|
|
11023
|
+
"disabled": submitting.value,
|
|
11024
|
+
"loading": submitting.value,
|
|
11025
|
+
"onClick": () => submit()
|
|
11026
|
+
}, null)
|
|
11027
|
+
]) })]);
|
|
10737
11028
|
};
|
|
10738
11029
|
}
|
|
10739
11030
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kine-design/crud",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/crud.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"pinia": "^3.0.3",
|
|
10
10
|
"vue": "^3.5.30",
|
|
11
11
|
"vue-router": "^5.0.3",
|
|
12
|
-
"
|
|
13
|
-
"kine-
|
|
12
|
+
"kine-ui": "0.0.1-beta.6",
|
|
13
|
+
"@kine-design/core": "0.0.1-beta.3"
|
|
14
14
|
},
|
|
15
15
|
"publishConfig": {
|
|
16
16
|
"access": "public",
|