ci-plus 1.1.0 → 1.1.2

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/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as components from './src/index';
2
2
  export * from './src/index';
3
3
  import { App } from 'vue';
4
+ export * as cifunction from './src/utils';
4
5
 
5
6
  export default {
6
7
  install: (app: App) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ci-plus",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "ci组件库",
5
5
  "main": "./index.ts",
6
6
  "scripts": {
@@ -20,7 +20,9 @@
20
20
  "less": "^4.2.0",
21
21
  "sortablejs": "^1.15.1",
22
22
  "vite-plugin-svg-icons": "^2.0.1",
23
- "vuedraggable": "^2.24.3"
23
+ "vuedraggable": "^2.24.3",
24
+ "jsbarcode": "^3.11.6",
25
+ "dayjs": "^1.11.9"
24
26
  },
25
27
  "devDependencies": {},
26
28
  "peerDependencies": {},
@@ -16,8 +16,11 @@ declare module '@vue/runtime-core' {
16
16
  CiSuffix: typeof components.Suffix;
17
17
  CiTable: typeof components.SorTables;
18
18
  CiHeadbtns: typeof components.Headbtns
19
+ CiHeaderInput: typeof components.HeaderInput
19
20
  CiSdialog: typeof components.Sdialog
20
21
  CiColumncell: typeof components.Columncell
22
+ CiUpload: typeof components.Upload
23
+ CiIdentificationCard: typeof components.IdentificationCard
21
24
  }
22
25
  }
23
26
  export { };
@@ -0,0 +1,7 @@
1
+ ## 附件相关组件:
2
+
3
+ ### 1. 文件上传组件:
4
+
5
+ ### 2.表格附件展示组件:
6
+
7
+ ### 3. 表单附件新增/修改组件:
@@ -0,0 +1,149 @@
1
+ <template>
2
+ <el-popover placement="bottom" :width="300" trigger="click">
3
+ <el-upload
4
+ ref="upload"
5
+ class="upload-demo"
6
+ :action="url + '_post/'"
7
+ :limit="1"
8
+ :on-exceed="handleExceed"
9
+ :auto-upload="false"
10
+ :on-success="onSuccess"
11
+ :on-error="onError"
12
+ :on-change="handleChange"
13
+ :data="datas"
14
+ >
15
+ <template #trigger>
16
+ <el-button size="small" type="primary" style="width: 166px" plain> 选择文件 </el-button>
17
+ </template>
18
+ <el-button
19
+ size="small"
20
+ @click="formwork"
21
+ style="float: left; margin: 0 12px 0 0; width: 95px"
22
+ >
23
+ 下载模板
24
+ </el-button>
25
+ </el-upload>
26
+
27
+ <div style="width: 100%; display: flex">
28
+ <el-button size="small" @click="visible = false" style="flex: 1"> 取消 </el-button>
29
+ <el-button size="small" type="primary" @click="submitUpload" style="flex: 2">
30
+ 上传
31
+ </el-button>
32
+ </div>
33
+ <template #reference>
34
+ <el-button type="success" plain @click="visible = true"> 导入 </el-button>
35
+ </template>
36
+ </el-popover>
37
+ </template>
38
+
39
+ <script setup lang="ts">
40
+ import { ref } from 'vue'
41
+ import { ElMessage, ElLoading, genFileId } from 'element-plus'
42
+ import axios from 'axios'
43
+ import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus'
44
+ const upload = ref<UploadInstance>()
45
+ const exporLoading = ref()
46
+ const visible = ref(false)
47
+ const filelist = ref([])
48
+ const props = defineProps<{
49
+ url: string
50
+ parameter?: object // 附件模板下载时的请求参数
51
+ data?: object // 附件上传时的请求参数
52
+ templateName?: string // 模板名称
53
+ templateDownloadFn?: (val: any) => Promise<any> //附件上传函数?: Function
54
+ }>()
55
+ const emits = defineEmits<{
56
+ (e: 'reloadTable'): void
57
+ }>()
58
+
59
+ const datas = ref(props.data)
60
+
61
+ //选择文件
62
+ const handleExceed: UploadProps['onExceed'] = (files) => {
63
+ upload.value!.clearFiles()
64
+ const file = files[0] as UploadRawFile
65
+ file.uid = genFileId()
66
+ upload.value!.handleStart(file)
67
+ }
68
+ const handleChange = (file: any, fileList: any) => {
69
+ filelist.value = fileList //更新文件列表数据
70
+ }
71
+ //上传文件
72
+ const submitUpload = () => {
73
+ console.log(filelist.value.length)
74
+ if (!filelist.value.length) return ElMessage.warning('请选择文件后在上传!')
75
+ exporLoading.value = ElLoading.service({ text: '导入中...' })
76
+ console.log('upload.value', upload.value)
77
+ upload.value!.submit()
78
+ visible.value = false
79
+ }
80
+ //文件上传成功回调
81
+ const onSuccess = (res: any, file: any, fileList: any) => {
82
+ // console.log('res: ', res)
83
+ // console.log('file: ', file)
84
+ // console.log('fileList: ', fileList)
85
+ exporLoading.value.close()
86
+ filelist.value.length = 0
87
+ upload.value!.clearFiles()
88
+
89
+ if (res.code !== 200) {
90
+ return ElMessage.warning(res.msg)
91
+ }
92
+
93
+ ElMessage.success(res.msg)
94
+ emits('reloadTable')
95
+ }
96
+ //文件上传失败回调
97
+ const onError = (response: any, file: any, fileList: any) => {
98
+ // console.log('fileList: ', fileList)
99
+ // console.log('response: ', response)
100
+ ElMessage.error(file.name + '上传失败')
101
+ filelist.value.length = 0
102
+ upload.value!.clearFiles() // 清空文件列表
103
+ exporLoading.value.close()
104
+ }
105
+
106
+ //下载模板
107
+ const formwork = () => {
108
+ if (props.templateDownloadFn) {
109
+ props
110
+ .templateDownloadFn({
111
+ responseType: 'blob',
112
+ params: props.parameter
113
+ })
114
+ .then((res) => {
115
+ const url = URL.createObjectURL(new Blob([res.data]))
116
+ let link: HTMLAnchorElement | null = document.createElement('a')
117
+ link.href = url
118
+ link.setAttribute('download', props.templateName || '模板.xlsx')
119
+ document.body.appendChild(link)
120
+ link.click()
121
+ link = null
122
+ })
123
+ .catch((error) => {
124
+ console.log(error)
125
+ })
126
+ } else {
127
+ axios({
128
+ method: 'get',
129
+ url: props.url + '_get/',
130
+ responseType: 'blob',
131
+ params: props.parameter
132
+ })
133
+ .then((res) => {
134
+ const url = URL.createObjectURL(new Blob([res.data]))
135
+ let link: HTMLAnchorElement | null = document.createElement('a')
136
+ link.href = url
137
+ link.setAttribute('download', props.templateName || '模板.xlsx')
138
+ document.body.appendChild(link)
139
+ link.click()
140
+ link = null
141
+ })
142
+ .catch((error) => {
143
+ console.log(error)
144
+ })
145
+ }
146
+ }
147
+ </script>
148
+
149
+ <style scoped></style>
@@ -0,0 +1,4 @@
1
+ import _Upload from '../ciupload.vue'
2
+ import { withInstall } from '../../utils/index';
3
+ export const Upload = withInstall(_Upload)
4
+ export default Upload
@@ -0,0 +1,160 @@
1
+ <!-- /**
2
+ * @module seeFile
3
+ * @author : 卖女孩的小火柴
4
+ * !description : 附件预览
5
+ * @version : 1.0.0
6
+ * @since : 创建时间 2024-02-19 10:13:32
7
+ */ -->
8
+
9
+ <template>
10
+ <el-popover
11
+ placement="bottom"
12
+ :width="200"
13
+ style="height: 200px; max-height: 400px; max-width: 250px"
14
+ trigger="click"
15
+ >
16
+ <template #reference>
17
+ <el-button type="success" plain size="small"> 附件 </el-button>
18
+ </template>
19
+ <template v-for="(item, i) in pathArr" :key="i">
20
+ <div class="list" v-if="item.name">
21
+ <div class="list-a" @click="downloadFile(item.oldName, item.name)">
22
+ {{ item.name || '下载' }}
23
+ </div>
24
+ </div>
25
+ </template>
26
+ </el-popover>
27
+ </template>
28
+
29
+ <script setup lang="ts">
30
+ import { ref, watch } from 'vue'
31
+ import axios from 'axios'
32
+ import { ElMessage } from 'element-plus'
33
+ const props = defineProps<{
34
+ url?: string[] // 传入要显示的附件地址数组
35
+ baseUrl?: string // 图片展示的基础路径
36
+ }>()
37
+ /*
38
+ 数据结构说明:
39
+ props.url:[
40
+ "media/material/3.1708222741.7763922.webp",
41
+ "media/material/3号(number-3)_爱给网_aigei_com.1708222741.7783866.png"
42
+ ]
43
+
44
+ 基础路径
45
+ props.baseUrl : http://10.20.72.231:9999/
46
+ */
47
+
48
+ // 定义一个函数,用于处理字符串
49
+ export const setFilePath = (arr: string[], url?: string) => {
50
+ // console.log('重新渲染数据', arr);
51
+ if (arr && arr.length > 0) {
52
+ let newArr: { name: string; oldName: string }[] = []
53
+ arr.forEach((item, i) => {
54
+ let segments = item.split('.')
55
+ let parts = segments[0].split('/') // 获取每名称
56
+ let name = parts[parts.length - 1] + '.' + segments[segments.length - 1]
57
+ let oldName = url ? url + item : item //原来的名称
58
+ // let url = segments[0] + '.' + segments[segments.length - 1]
59
+ newArr.push({ name, oldName })
60
+ })
61
+ return newArr
62
+ } else {
63
+ return [] // 如果数组为空,则返回空数组
64
+ }
65
+ }
66
+
67
+ // 将路径处理成附件的参数
68
+ export const fileArr = (url: string, pathArr: string[]) => {
69
+ if (pathArr && pathArr.length > 0) {
70
+ let objArr: any = []
71
+ if (pathArr.length > 0) {
72
+ pathArr.map((item: any) => {
73
+ objArr.push({
74
+ name: item.name,
75
+ oldName: item.oldName,
76
+ url: url + item.oldName
77
+ })
78
+ })
79
+ return objArr
80
+ } else {
81
+ return []
82
+ }
83
+ }
84
+ }
85
+
86
+ const emits = defineEmits(['onClick'])
87
+
88
+ // console.log('props', props.url)
89
+
90
+ const pathArr = ref<any[]>([])
91
+ // 对数组中的每个字符串应用处理函数
92
+ // @ts-ignore
93
+ pathArr.value = setFilePath(props.url, props.baseUrl || 'http://10.20.72.231:9999/')
94
+
95
+ // 监听props.url的变化
96
+ watch(
97
+ () => props.url,
98
+ (newVal) => {
99
+ // console.log('newVal: ', newVal)
100
+ // 对新值进行处理
101
+ // @ts-ignore
102
+ pathArr.value = setFilePath(newVal, props.baseUrl || 'http://10.20.72.231:9999/')
103
+ },
104
+ {
105
+ immediate: true, // 是否立即执行
106
+ deep: true // 是否深度监听
107
+ }
108
+ )
109
+
110
+ // 下载文件
111
+ const downloadFile = (url: string, name: string) => {
112
+ axios({
113
+ method: 'GET',
114
+ url: url,
115
+ responseType: 'blob'
116
+ }).then((res) => {
117
+ console.log('res: ', res)
118
+ if (res.status === 200) {
119
+ if (res.headers['Content-Type'] === 'application/json') {
120
+ let data
121
+ if (res.request) data = JSON.parse(res.request.responseText)
122
+ else data = { code: 500, msg: '文件获取失败' }
123
+ return ElMessage.warning(`${data.code}:${data.msg}`) // 文件获取失败
124
+ }
125
+ ElMessage.success('开始下载!')
126
+ const link = document.createElement('a') // 创建a标签
127
+ link.href = window.URL.createObjectURL(new Blob([res.data])) // 创建下载链接
128
+ link.setAttribute('download', name) // 设置下载文件名称(名称+后缀)
129
+ link.click() // 下载文件
130
+ window.URL.revokeObjectURL(link.href) // 释放内存
131
+ } else ElMessage.error(`${res.status}:${res.statusText}`) // 文件获取失败
132
+ })
133
+ }
134
+ </script>
135
+
136
+ <style lang="scss" scoped>
137
+ .list {
138
+ display: flex;
139
+ justify-content: space-between;
140
+ width: 100%;
141
+ height: 30px;
142
+ line-height: 30px;
143
+ border: 1px solid #ebeef5;
144
+ padding: 0 10px;
145
+ box-sizing: border-box;
146
+ font-size: 14px;
147
+ overflow: hidden;
148
+ text-overflow: ellipsis;
149
+ white-space: nowrap;
150
+ .list-a {
151
+ width: 100%;
152
+ overflow: hidden;
153
+ text-overflow: ellipsis;
154
+ &:hover {
155
+ background-color: #f5f7fa;
156
+ cursor: pointer;
157
+ }
158
+ }
159
+ }
160
+ </style>
@@ -0,0 +1,212 @@
1
+ <template>
2
+ <el-popover placement="bottom" :width="300">
3
+ <el-upload
4
+ ref="upload"
5
+ class="upload-demo"
6
+ :action="url + '_post/'"
7
+ :limit="mylimit || 1"
8
+ :on-exceed="handleExceed"
9
+ :auto-upload="false"
10
+ :on-success="onSuccess"
11
+ :on-error="onError"
12
+ :on-change="handleChange"
13
+ :on-remove="handleRemove"
14
+ :data="datas"
15
+ :multiple="mymultiple || false"
16
+ v-model:file-list="fileList"
17
+ >
18
+ <template #trigger>
19
+ <el-button size="small" type="primary" style="width: 100px" plain> 选择文件 </el-button>
20
+ </template>
21
+ <el-button
22
+ size="small"
23
+ @click="formwork"
24
+ style="float: left; margin: 0 12px 0 0; width: 95px"
25
+ v-if="url"
26
+ >
27
+ 下载模板
28
+ </el-button>
29
+ </el-upload>
30
+
31
+ <div style="width: 100%; display: flex" v-if="url">
32
+ <el-button size="small" @click="visible = false" style="flex: 1"> 取消 </el-button>
33
+ <el-button size="small" type="primary" @click="submitUpload" style="flex: 2">
34
+ 上传
35
+ </el-button>
36
+ </div>
37
+ <template #reference>
38
+ <el-button type="success" plain @click="visible = true" size="small">
39
+ {{ props.title || '附件上传' }}
40
+ </el-button>
41
+ </template>
42
+ </el-popover>
43
+ </template>
44
+
45
+ <script setup lang="ts">
46
+ // 定义一个函数,用于处理字符串
47
+ export const setFilePath = (arr: string[], url?: string) => {
48
+ // console.log('重新渲染数据', arr);
49
+ if (arr && arr.length > 0) {
50
+ let newArr: { name: string; oldName: string }[] = []
51
+ arr.forEach((item, i) => {
52
+ let segments = item.split('.')
53
+ let parts = segments[0].split('/') // 获取每名称
54
+ let name = parts[parts.length - 1] + '.' + segments[segments.length - 1]
55
+ let oldName = url ? url + item : item //原来的名称
56
+ // let url = segments[0] + '.' + segments[segments.length - 1]
57
+ newArr.push({ name, oldName })
58
+ })
59
+ return newArr
60
+ } else {
61
+ return [] // 如果数组为空,则返回空数组
62
+ }
63
+ }
64
+
65
+ // 将路径处理成附件的参数
66
+ export const fileArr = (url: string, pathArr: string[]) => {
67
+ if (pathArr && pathArr.length > 0) {
68
+ let objArr: any = []
69
+ if (pathArr.length > 0) {
70
+ pathArr.map((item: any) => {
71
+ objArr.push({
72
+ name: item.name,
73
+ oldName: item.oldName,
74
+ url: url + item.oldName
75
+ })
76
+ })
77
+ return objArr
78
+ } else {
79
+ return []
80
+ }
81
+ }
82
+ }
83
+
84
+ import { ref } from 'vue'
85
+ import { ElMessage, ElLoading, genFileId } from 'element-plus'
86
+ import axios from 'axios'
87
+ import type {
88
+ UploadFile,
89
+ UploadFiles,
90
+ UploadInstance,
91
+ UploadProps,
92
+ UploadUserFile
93
+ } from 'element-plus'
94
+ const upload = ref<UploadInstance>()
95
+ const exporLoading = ref()
96
+ const visible = ref(false)
97
+ // const filelist = ref([])
98
+
99
+ const props = defineProps<{
100
+ url?: string // 上传和下载模板的接口(当需要将附件传递回父组件时不需要传递此属性)
101
+ parameter?: () => {} // 模板下载的时候请求需要携带的参数:{state: 1}
102
+ data?: () => {} //上传携带的其他数据对象:{userId: 1, userName: '张三'}
103
+ title?: string // 上传按钮的名称
104
+ multiple?: boolean // 是否支持多文件
105
+ limit?: number // 最大文件数量
106
+ filePath?: UploadFile[] //UploadRawFile[] // 父组件传递的附件数据,用于显示附件列表和上传附件后传递给父组件附件数据
107
+ RowIndex?: number // 父组件传递的行索引,用于父组件中删除了附件找到对应的行
108
+ }>()
109
+ const emits = defineEmits<{
110
+ (e: 'reloadTable'): void // 组件中上传附件后刷新父组件表格数据方法
111
+ (e: 'getFile', files: UploadFiles, file?: UploadFile, rowindex?: number): void
112
+ (e: 'update:file', files: UploadFiles): void
113
+ }>()
114
+ console.log('附件props: ', props)
115
+ const datas = ref(props.data)
116
+ const mymultiple = ref<boolean>(props.multiple)
117
+ const mylimit = ref<number>(props.limit as number)
118
+ const myfilePath = ref<any>(props.filePath || [])
119
+ console.log('myfilePath: ', props.filePath)
120
+
121
+ // 对数组中的每个字符串应用处理函数
122
+ let pathArr = setFilePath(myfilePath.value)
123
+
124
+ // 打印处理后的数组
125
+ // 将父组件中传递过来的名称,处理成el-upload需要的格式
126
+ let pathUrlArr = fileArr(import.meta.env.VITE_BASE_URL9999, pathArr)
127
+ console.log('fileObj(): ', pathUrlArr)
128
+ const fileList = ref<UploadUserFile[]>(pathUrlArr)
129
+ console.log('fileList: ', fileList.value)
130
+
131
+ //当超出限制时,执行的钩子函数
132
+ const handleExceed: UploadProps['onExceed'] = (files) => {
133
+ console.log('超出限制: ', files)
134
+ ElMessage.warning(`超出最大文件数:${mylimit?.value}个文件,请重新选择`)
135
+ // upload.value!.clearFiles()
136
+ // const file = files[0] as UploadRawFile
137
+ // file.uid = genFileId()
138
+ // upload.value!.handleStart(file)
139
+ }
140
+
141
+ // 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
142
+ const handleChange = (file: any, fileLists: any) => {
143
+ // console.log('file: ', file)
144
+ // console.log('fileList: ', fileLists)
145
+ // filelist.value = fileLists //更新文件列表数据
146
+ // 如果没有url就将选中的附件文件流传递回父组件
147
+ if (!props.url) {
148
+ // const files: UploadRawFile[] = fileLists.map(
149
+ // (item) => item.raw,
150
+ // ) as UploadRawFile[]
151
+ emits('getFile', fileLists) //将选中的文件传递回父组件
152
+ emits('update:file', fileLists) //同步父组件绑定的附件字段,以便父组件提交表单的时候一起将附件提交
153
+ }
154
+ }
155
+ // 文件列表删除时
156
+ const handleRemove: UploadProps['onRemove'] = (file, fileList) => {
157
+ console.log('file: ', file)
158
+ console.log('fileList: ', fileList)
159
+ // 如果没有url时 在删除的时候将文件流同步回父组件
160
+ if (!props.url) {
161
+ // const files: UploadRawFile[] = fileList.map(
162
+ // (item) => item.raw,
163
+ // ) as UploadRawFile[]
164
+ emits('getFile', fileList, file, props.RowIndex)
165
+ emits('update:file', fileList)
166
+ }
167
+ }
168
+ //上传文件
169
+ const submitUpload = () => {
170
+ console.log(fileList.value.length)
171
+ if (!fileList.value.length) return ElMessage.warning('请选择文件后在上传12!')
172
+ exporLoading.value = ElLoading.service({ text: '导入中...' })
173
+ console.log('upload.value', upload.value)
174
+ upload.value!.submit()
175
+ visible.value = false
176
+ }
177
+ //文件上传成功回调
178
+ const onSuccess = (res: any, file: any, fileList: any) => {
179
+ exporLoading.value.close()
180
+ if (res.code !== 200) return ElMessage.warning(res.msg)
181
+ ElMessage.success(res.msg)
182
+ emits('reloadTable')
183
+ }
184
+ //文件上传失败回调
185
+ const onError = (response: any, file: any, fileList: any) => {
186
+ ElMessage.error('服务器异常!')
187
+ }
188
+
189
+ //下载模板
190
+ const formwork = () => {
191
+ axios({
192
+ method: 'get',
193
+ url: props.url + '_get/',
194
+ responseType: 'blob',
195
+ params: props.parameter
196
+ })
197
+ .then((res) => {
198
+ const url = URL.createObjectURL(new Blob([res.data]))
199
+ let link: HTMLAnchorElement | null = document.createElement('a')
200
+ link.href = url
201
+ link.setAttribute('download', '模板.xlsx')
202
+ document.body.appendChild(link)
203
+ link.click()
204
+ link = null
205
+ })
206
+ .catch((error) => {
207
+ console.log(error)
208
+ })
209
+ }
210
+ </script>
211
+
212
+ <style scoped></style>
@@ -0,0 +1,63 @@
1
+ <!--
2
+ * @module SelfBarcode
3
+ * @author : 卖女孩的小火柴
4
+ * !description : 条形码组件:根据传入的文本生成条形码
5
+ * @version : 1.0.0
6
+ * @since : 创建时间 2024-01-19 16:37:51
7
+ -->
8
+
9
+ <template>
10
+ <div>
11
+ <svg :class="'barcode' + props.value" class="mycards" :style="`max-width: ${maxWidth}`"></svg>
12
+ </div>
13
+ </template>
14
+
15
+ <script setup lang="ts">
16
+ import { ref, onMounted, nextTick, watch } from 'vue'
17
+ import JsBarcode from 'jsbarcode'
18
+ interface Props {
19
+ value: String // 条码文本
20
+ type: String // 类型
21
+ maxWidth: String // 最大宽度
22
+ newClass: String | Number // 自定义class
23
+ }
24
+ const props = defineProps<Props>()
25
+ // console.log('条码props', props)
26
+ watch(props, () => {
27
+ draw()
28
+ })
29
+ function draw() {
30
+ // 第一个参数,要渲染的dom的id或者class名称,第二个参数,条形码的实际文本,第三个参数,条形码的配置
31
+ JsBarcode('.barcode' + props.value, String(props.value), {
32
+ // format: 'CODE39', //选择要使用的条形码类型,默认值'auto' (CODE128)
33
+ width: 2, //设置条之间的宽度
34
+ height: 40, //高度
35
+ displayValue: true, //是否在条形码下方显示文字
36
+ // text: props.value,//覆盖显示的文本
37
+ // text:"456",//覆盖显示的文本
38
+ // fontOptions:"bold italic",//使文字加粗体或变斜体
39
+ // font:"fantasy",//设置文本的字体
40
+ // textAlign:"left",//设置文本的水平对齐方式
41
+ // textPosition:"top",//设置文本的垂直位置
42
+ // textMargin:5,//设置条形码和文本之间的间距
43
+ fontSize: 16, //设置文本的大小
44
+ // background: '#fff', //设置条形码的背景
45
+ // lineColor: '#2196f3', //设置条和文本的颜色。
46
+ // margin: 25, //设置条形码周围的空白边距
47
+ marginTop: 5, //相当于MarginTop
48
+ marginBottom: 0
49
+ })
50
+ }
51
+ onMounted(() => {
52
+ nextTick(() => {
53
+ draw()
54
+ })
55
+ })
56
+ </script>
57
+ <style lang="scss" scoped>
58
+ .mycards {
59
+ color: red;
60
+ max-width: 600px;
61
+ min-width: 400px;
62
+ }
63
+ </style>