zhl-methods 2.0.0 → 2.0.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.
@@ -0,0 +1,3 @@
1
+ {
2
+ "recommendations": ["Vue.volar"]
3
+ }
@@ -0,0 +1,5 @@
1
+ # Vue 3 + TypeScript + Vite
2
+
3
+ This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
4
+
5
+ Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
@@ -0,0 +1,5 @@
1
+ .ant-modal-body {
2
+ max-height: 80vh;
3
+ overflow-y: auto;
4
+ overflow-x: hidden;
5
+ }
@@ -0,0 +1,74 @@
1
+ <!--
2
+ 弹窗
3
+ @author zhl
4
+ @date 2026/03/11
5
+ -->
6
+ <template>
7
+ <vxe-modal
8
+ :title="props.title"
9
+ v-model="state.showModal"
10
+ :loading="state.loading"
11
+ maskClosable
12
+ escClosable
13
+ :height="props.height"
14
+ :width="props.width"
15
+ :showFooter="props.showFooter"
16
+ show-cancel-button
17
+ show-confirm-button
18
+ destroy-on-close
19
+ :confirm-closable="false"
20
+ @confirm="emits('confirm')"
21
+ @cancel="emits('close')"
22
+ @close="emits('close')"
23
+ >
24
+ <slot></slot>
25
+ </vxe-modal>
26
+ </template>
27
+ <script setup lang="ts">
28
+ import { VxeModal } from "vxe-pc-ui";
29
+ import { reactive } from "vue";
30
+ const emits = defineEmits(["confirm", "close"]);
31
+ /**
32
+ * title 弹窗显示标题
33
+ * width 弹窗宽度 字符串 100px 100 100% 50vw calc(50vw - 50px)
34
+ * height 弹窗宽度 字符串 100px 100 100% 50vh calc(50vh - 50px)
35
+ * maskClosable 是否允许点击遮罩层关闭窗口
36
+ * escClosable 是否允许按 Esc 键关闭窗口
37
+ * showFooter 是否显示底部按钮 自定义footer会直接覆盖默认footer
38
+ */
39
+ const props = defineProps({
40
+ title: { type: String },
41
+ width: { type: String },
42
+ height: { type: String },
43
+ maskClosable: {
44
+ type: Boolean,
45
+ default: () => true,
46
+ },
47
+ escClosable: {
48
+ type: Boolean,
49
+ default: () => true,
50
+ },
51
+ showFooter: {
52
+ type: Boolean,
53
+ default: () => true,
54
+ },
55
+ });
56
+ const state = reactive({
57
+ loading: false,
58
+ showModal: false,
59
+ });
60
+ const open = () => {
61
+ state.showModal = true;
62
+ };
63
+ const close = () => {
64
+ state.showModal = false;
65
+ };
66
+ const setLoading = (loading: boolean) => {
67
+ state.loading = loading;
68
+ };
69
+ defineExpose({
70
+ open,
71
+ close,
72
+ setLoading,
73
+ });
74
+ </script>
@@ -0,0 +1,102 @@
1
+ <template>
2
+ <vxe-column field="66" title="66" width="225">
3
+ <div style="display: flex; align-items: center">
4
+ <div :style="{ width: actionList.length > 4 ? '153px' : '100%' }">
5
+ <div style="display: flex; margin-bottom: 10px">
6
+ <vxe-button
7
+ style="width: 74px"
8
+ size="mini"
9
+ mode="text"
10
+ :status="actionList[0].status"
11
+ v-if="actionList[0]"
12
+ @click="
13
+ actionList[0].callback ? actionList[0].callback() : () => {}
14
+ "
15
+ >
16
+ {{ actionList[0].title }}
17
+ </vxe-button>
18
+ <vxe-button
19
+ style="width: 74px"
20
+ size="mini"
21
+ mode="text"
22
+ :status="actionList[1].status"
23
+ v-if="actionList[1]"
24
+ @click="
25
+ actionList[1].callback ? actionList[1].callback() : () => {}
26
+ "
27
+ >
28
+ {{ actionList[1].title }}
29
+ </vxe-button>
30
+ </div>
31
+ <div style="display: flex">
32
+ <vxe-button
33
+ style="width: 74px"
34
+ size="mini"
35
+ mode="text"
36
+ :status="actionList[2].status"
37
+ v-if="actionList[2]"
38
+ @click="
39
+ actionList[2].callback ? actionList[2].callback() : () => {}
40
+ "
41
+ >
42
+ {{ actionList[2].title }}
43
+ </vxe-button>
44
+ <vxe-button
45
+ style="width: 74px"
46
+ size="mini"
47
+ mode="text"
48
+ v-if="actionList[3]"
49
+ :status="actionList[3].status"
50
+ @click="
51
+ actionList[3].callback ? actionList[3].callback() : () => {}
52
+ "
53
+ >
54
+ {{ actionList[3].title }}
55
+ </vxe-button>
56
+ </div>
57
+ </div>
58
+ <vxe-button
59
+ mode="text"
60
+ v-if="menuList.length"
61
+ :options="
62
+ menuList.map((item) => ({
63
+ ...item,
64
+ content: item.title,
65
+ }))
66
+ "
67
+ />
68
+ </div>
69
+ </vxe-column>
70
+ </template>
71
+ <script lang="ts" setup>
72
+ import { reactive, computed } from "vue";
73
+ // import { authMethod } from "@/directives/auth/authMethod.ts";
74
+
75
+ const props = defineProps<{
76
+ listData: {
77
+ callback: Function;
78
+ title: string;
79
+ auth?: string;
80
+ vIf?: Boolean;
81
+ status?: "primary" | "success" | "warning" | "error";
82
+ }[];
83
+ }>();
84
+ const actionList = computed(() => {
85
+ return props.listData.filter((item) => {
86
+ let type: Boolean | undefined = true;
87
+ if (item.vIf != undefined) type = item.vIf;
88
+ // if (item.auth) type = type && authMethod(item.auth);
89
+ if (type) {
90
+ return true;
91
+ } else {
92
+ return false;
93
+ }
94
+ });
95
+ });
96
+ const menuList = computed(() => {
97
+ if (actionList.value.length > 4) {
98
+ return actionList.value.slice(4, actionList.value.length);
99
+ }
100
+ return [];
101
+ });
102
+ </script>
@@ -0,0 +1,36 @@
1
+ <template>
2
+ <a-table :dataSource="dataSource" :columns="columns" />
3
+ </template>
4
+ <script setup>
5
+ const dataSource = [
6
+ {
7
+ key: "1",
8
+ name: "胡彦斌",
9
+ age: 32,
10
+ address: "西湖区湖底公园1号",
11
+ },
12
+ {
13
+ key: "2",
14
+ name: "胡彦祖",
15
+ age: 42,
16
+ address: "西湖区湖底公园1号",
17
+ },
18
+ ];
19
+ const columns = [
20
+ {
21
+ title: "姓名",
22
+ dataIndex: "name",
23
+ key: "name",
24
+ },
25
+ {
26
+ title: "年龄",
27
+ dataIndex: "age",
28
+ key: "age",
29
+ },
30
+ {
31
+ title: "住址",
32
+ dataIndex: "address",
33
+ key: "address",
34
+ },
35
+ ];
36
+ </script>
@@ -0,0 +1,165 @@
1
+ <!--
2
+ 图片上传 单个 多个
3
+ @author zhl
4
+ @date 2026/01/28
5
+ -->
6
+ <template>
7
+ <a-upload
8
+ :disabled="props.disabled"
9
+ list-type="picture-card"
10
+ :file-list="showUploadList"
11
+ :action="URL + '/admin.upload/upload'"
12
+ :accept="props.fileType"
13
+ :headers="headers"
14
+ :data="{
15
+ scene: props.scene,
16
+ ...data,
17
+ }"
18
+ :before-upload="beforeUpload"
19
+ :on-success="onSuccess"
20
+ :on-error="onError"
21
+ @remove="removeImg"
22
+ @preview="handlePreview"
23
+ >
24
+ <template v-if="!disabled">
25
+ <template v-if="showUploadList.length < imgLimit">
26
+ <LoadingOutlined v-if="state.loading" />
27
+ <plus-outlined v-else />
28
+ </template>
29
+ </template>
30
+ </a-upload>
31
+ <a-modal
32
+ :open="state.showModal"
33
+ title="预览"
34
+ :footer="null"
35
+ @cancel="state.showModal = false"
36
+ >
37
+ <img alt="example" style="width: 100%" :src="state.showImgUrl" />
38
+ </a-modal>
39
+ </template>
40
+ <script setup lang="ts">
41
+ import { message } from "ant-design-vue";
42
+ import { PlusOutlined, LoadingOutlined } from "@ant-design/icons-vue";
43
+ import { reactive, computed } from "vue";
44
+ import { URL } from "@/utils/request";
45
+ const headers = {
46
+ Authorization: localStorage.getItem("TOKEN"),
47
+ brand: "1",
48
+ };
49
+ const emits = defineEmits([
50
+ "update:modelValue",
51
+ "onSuccess",
52
+ "getImgUrl",
53
+ "beforeUpload",
54
+ ]);
55
+ /**
56
+ * 传递参数
57
+ * @params scene 场景值 必穿 shop store 等
58
+ * @params data 更多参数 对象格式
59
+ * @params fileType 选择图片类型 默认所有格式图片
60
+ * @author zhl
61
+ * @date 2023/12/06
62
+ */
63
+ const props = defineProps({
64
+ modelValue: {},
65
+ disabled: {
66
+ type: Boolean,
67
+ },
68
+ imgLimit: {
69
+ type: Number,
70
+ default: () => 1,
71
+ },
72
+ scene: {
73
+ type: String,
74
+ required: true,
75
+ },
76
+ data: {
77
+ type: Object,
78
+ },
79
+ fileType: {
80
+ type: String,
81
+ default: () => "image/*",
82
+ },
83
+ });
84
+ const state = reactive({
85
+ loading: false,
86
+ showImgUrl: "",
87
+ showModal: false,
88
+ });
89
+ const handlePreview = async (file) => {
90
+ state.showImgUrl = file.url;
91
+ state.showModal = true;
92
+ };
93
+ /**
94
+ * 是否显示上传列表
95
+ * 单图片 多图片显示
96
+ * @author zhl
97
+ * @date 2023/12/08
98
+ */
99
+ const showUploadList = computed(() => {
100
+ if (typeof props.modelValue === "string") {
101
+ if (props.modelValue) {
102
+ return [{ url: props.modelValue }];
103
+ } else {
104
+ return [];
105
+ }
106
+ } else {
107
+ return props.modelValue.map((item) => {
108
+ return { url: item };
109
+ });
110
+ }
111
+ });
112
+ /**
113
+ * 上传前
114
+ * @author zhl
115
+ * @date 2023/12/06
116
+ */
117
+ const beforeUpload = (file) => {
118
+ state.loading = true;
119
+ emits("beforeUpload", file);
120
+ return true;
121
+ };
122
+ /**
123
+ * 上传成功
124
+ * @author zhl
125
+ * @date 2023/12/06
126
+ */
127
+ const onSuccess = (res) => {
128
+ state.loading = false;
129
+ if (res.code == 200) {
130
+ if (props.imgLimit > 1) {
131
+ // let data = JSON.parse(JSON.stringify(props.modelValue))
132
+ // data.push(res.data.url)
133
+ // emits('update:modelValue', data)
134
+ props.modelValue.push(res.data.url);
135
+ } else {
136
+ emits("update:modelValue", res.data.url);
137
+ emits("getImgUrl", res.data.url);
138
+ }
139
+ } else {
140
+ message.error(res.msg);
141
+ }
142
+ };
143
+ /**
144
+ * 上传失败
145
+ * @author zhl
146
+ * @date 2023/12/06
147
+ */
148
+ const onError = () => {
149
+ state.loading = false;
150
+ message.error("上传失败");
151
+ };
152
+ const removeImg = (file) => {
153
+ if (props.imgLimit > 1) {
154
+ showUploadList.value.forEach((item, index) => {
155
+ if (item.url == file.url) {
156
+ showUploadList.value.splice(index, 1);
157
+ props.modelValue.splice(index, 1);
158
+ }
159
+ });
160
+ } else {
161
+ emits("update:modelValue", "");
162
+ }
163
+ };
164
+ </script>
165
+ <style lang="scss"></style>
@@ -0,0 +1,11 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ </head>
7
+ <body>
8
+ <div id="app"></div>
9
+ <script type="module" src="/src/main.ts"></script>
10
+ </body>
11
+ </html>
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "jinglijing_wholesale_pc",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vue-tsc -b && vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "@vxe-ui/plugin-export-xlsx": "4.5.1",
13
+ "ant-design-vue": "4.x",
14
+ "consola": "^3.4.2",
15
+ "exceljs": "4.4.0",
16
+ "vite-plugin-lazy-import": "^1.0.7",
17
+ "vite-plugin-style-import": "^2.0.0",
18
+ "vue": "^3.5.24",
19
+ "vxe-pc-ui": "4.12.16",
20
+ "vxe-table": "4.17.46",
21
+ "xe-utils": "3.9.1"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^24.10.1",
25
+ "@vitejs/plugin-vue": "^6.0.1",
26
+ "@vue/tsconfig": "^0.8.1",
27
+ "typescript": "~5.9.3",
28
+ "vite": "^7.2.4",
29
+ "vue-tsc": "^3.1.4"
30
+ }
31
+ }
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <button @click="clickOpen">弹窗</button>
3
+ <ModalView ref="ModalViewRef">555</ModalView>
4
+ </template>
5
+ <script setup lang="ts">
6
+ import { ref } from "vue";
7
+ import ModalView from "../components/modalView/index.vue";
8
+ const ModalViewRef = ref();
9
+ const clickOpen = () => {
10
+ ModalViewRef.value.open();
11
+ };
12
+ </script>
@@ -0,0 +1,12 @@
1
+ import { createApp } from "vue";
2
+ import App from "./App.vue";
3
+ import "../components/index.css";
4
+ // import VxeUIBase, { VxeUI } from "vxe-pc-ui";
5
+ import "vxe-pc-ui/es/style.css";
6
+ // import VxeUITable from "vxe-table";
7
+ import "vxe-table/es/style.css";
8
+ // import VxeUIPluginExportXLSX from "@vxe-ui/plugin-export-xlsx";
9
+ // import ExcelJS from "exceljs";
10
+ // VxeUI.use(VxeUIPluginExportXLSX, { ExcelJS });
11
+ createApp(App).mount("#app");
12
+ // createApp(App).use(VxeUIBase).use(VxeUITable).mount("#app");
@@ -0,0 +1,7 @@
1
+ <template>
2
+ <vxe-column field="name" title="Name">
3
+ <template #default="{ row }">
4
+ {{ row }}
5
+ </template>
6
+ </vxe-column>
7
+ </template>
@@ -0,0 +1,17 @@
1
+ {
2
+ "extends": "@vue/tsconfig/tsconfig.dom.json",
3
+ "compilerOptions": {
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
5
+ "types": ["vite/client"],
6
+ "baseUrl": "./",
7
+ "paths": { "@/*": ["src/*"] },
8
+ /* Linting */
9
+ "strict": true,
10
+ "noUnusedLocals": true,
11
+ "noUnusedParameters": true,
12
+ "erasableSyntaxOnly": true,
13
+ "noFallthroughCasesInSwitch": true,
14
+ "noUncheckedSideEffectImports": true
15
+ },
16
+ "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.vue"]
17
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "types": ["node"],
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "erasableSyntaxOnly": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "noUncheckedSideEffectImports": true
24
+ },
25
+ "include": ["vite.config.ts"]
26
+ }
@@ -0,0 +1,24 @@
1
+ import { defineConfig } from "vite";
2
+ import path from "path";
3
+ import vue from "@vitejs/plugin-vue";
4
+ import { createStyleImportPlugin } from "vite-plugin-style-import";
5
+ export default defineConfig({
6
+ base: "./",
7
+ plugins: [
8
+ vue(),
9
+ createStyleImportPlugin({
10
+ libs: [
11
+ {
12
+ libraryName: "vxe-table",
13
+ esModule: true,
14
+ resolveStyle: (name) => {
15
+ // 自动转换样式导入路径
16
+ return `vxe-table/es/${name}/style.css`;
17
+ },
18
+ },
19
+ ],
20
+ }),
21
+ ],
22
+ server: { port: 5000 },
23
+ resolve: { alias: { "@": path.resolve(__dirname, "./src") } },
24
+ });
package/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "zhl-methods",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "license": "ISC",
5
5
  "dependencies": {
6
- "dayjs": "^1.11.15",
7
- "vue": "^3.5.12"
6
+ "dayjs": "^1.11.15"
8
7
  }
9
8
  }