shared-ritm 1.2.64 → 1.2.66

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.
Files changed (58) hide show
  1. package/README.md +103 -103
  2. package/dist/index.css +1 -1
  3. package/dist/shared-ritm.es.js +3937 -3934
  4. package/dist/shared-ritm.umd.js +7 -7
  5. package/dist/types/api/services/SearchService.d.ts +7 -0
  6. package/dist/types/api/settings/ApiService.d.ts +1 -0
  7. package/dist/types/api/types/Api_Search.d.ts +43 -0
  8. package/dist/types/api/types/Api_Users.d.ts +43 -0
  9. package/dist/types/index.d.ts +4 -2
  10. package/package.json +63 -63
  11. package/src/api/services/ControlsService.ts +64 -64
  12. package/src/api/services/GanttService.ts +17 -17
  13. package/src/api/services/InstrumentsService.ts +22 -22
  14. package/src/api/services/MetricsService.ts +109 -109
  15. package/src/api/services/ProjectsService.ts +67 -67
  16. package/src/api/services/RepairsService.ts +100 -100
  17. package/src/api/services/SearchService.ts +15 -0
  18. package/src/api/services/VideoService.ts +14 -14
  19. package/src/api/settings/ApiService.ts +1 -0
  20. package/src/api/types/Api_Controls.ts +72 -72
  21. package/src/api/types/Api_Files.ts +1 -1
  22. package/src/api/types/Api_Instruments.ts +133 -133
  23. package/src/api/types/Api_Projects.ts +55 -55
  24. package/src/api/types/Api_Repairs.ts +93 -93
  25. package/src/api/types/Api_Search.ts +48 -0
  26. package/src/api/types/Api_Tasks.ts +155 -155
  27. package/src/common/app-checkbox/AppCheckbox.vue +26 -26
  28. package/src/common/app-dialogs/AppConfirmDialog.vue +99 -99
  29. package/src/common/app-dropdown/AppDropdown.vue +31 -31
  30. package/src/common/app-input/AppInput.vue +148 -148
  31. package/src/common/app-select/AppSelect.vue +157 -157
  32. package/src/common/app-sheet/AppSheet.vue +120 -120
  33. package/src/common/app-sidebar/components/SidebarMenuItem.vue +148 -148
  34. package/src/common/app-table/AppTable.vue +250 -250
  35. package/src/common/app-table/AppTableLayout.vue +111 -111
  36. package/src/common/app-table/components/ModalSelect.vue +264 -264
  37. package/src/common/app-table/components/TableModal.vue +329 -329
  38. package/src/common/app-table/components/TablePagination.vue +152 -152
  39. package/src/common/app-table/components/TableSearch.vue +76 -76
  40. package/src/common/app-table/controllers/useBaseTable.ts +42 -42
  41. package/src/common/app-table/controllers/useColumnSelector.ts +38 -38
  42. package/src/common/app-table/controllers/useTableModel.ts +93 -93
  43. package/src/common/app-toggle/AppToggle.vue +23 -23
  44. package/src/common/app-wrapper/AppWrapper.vue +28 -28
  45. package/src/icons/components/table-filter-icon.vue +30 -30
  46. package/src/icons/dialogs/RemoveIcon.vue +12 -12
  47. package/src/icons/dialogs/SafetyIcon.vue +12 -12
  48. package/src/icons/task/attention-icon.vue +13 -13
  49. package/src/icons/task/clock-icon.vue +10 -10
  50. package/src/icons/task/delete-icon.vue +10 -10
  51. package/src/icons/task/fire-icon.vue +16 -16
  52. package/src/index.ts +4 -1
  53. package/src/main.ts +28 -28
  54. package/src/shared/styles/general.css +125 -125
  55. package/src/styles/variables.sass +12 -12
  56. package/src/utils/confirm.ts +12 -12
  57. package/src/utils/helpers.ts +39 -39
  58. package/src/utils/notification.ts +9 -9
@@ -1,329 +1,329 @@
1
- <template>
2
- <q-dialog :model-value="modelValue" @update:model-value="val => emit('update:modelValue', val)">
3
- <q-card style="min-width: 700px">
4
- <q-card-section>
5
- <div class="modal-title">{{ title }}</div>
6
- </q-card-section>
7
-
8
- <q-card-section>
9
- <q-form ref="formRef" @submit.prevent="submit">
10
- <div v-for="field in fields" :key="field.key" class="field-wrapper">
11
- <label v-if="field.type === 'text'" class="field-label">
12
- {{ field.label }}
13
- <span v-if="field.rules?.length && mode !== 'view'" class="required">*</span>
14
- </label>
15
-
16
- <q-input
17
- v-if="field.type === 'text'"
18
- v-model="formData[field.key]"
19
- :rules="field.rules"
20
- :readonly="mode === 'view' || (field.key === 'uuid' && mode === 'edit')"
21
- filled
22
- :placeholder="field.placeholder"
23
- >
24
- <template #append>
25
- <q-icon
26
- v-if="mode !== 'view' && formData[field.key] && !(field.key === 'uuid' && mode === 'edit')"
27
- name="close"
28
- class="cursor-pointer clear-input"
29
- @click="() => handleClear(field.key)"
30
- />
31
- <q-btn
32
- v-if="field.key === 'uuid' && mode === 'create'"
33
- flat
34
- no-caps
35
- label="UUID"
36
- size="sm"
37
- class="q-ml-sm uuid-btn"
38
- @click="generateUuid"
39
- />
40
- <q-icon
41
- v-else-if="field.key === 'uuid' && mode !== 'create'"
42
- name="content_copy"
43
- class="cursor-pointer q-ml-sm copy-icon"
44
- color="primary"
45
- @click="copyToClipboard(formData[field.key])"
46
- />
47
- </template>
48
- </q-input>
49
-
50
- <app-modal-select
51
- v-else-if="field.type === 'select'"
52
- v-model="formData[field.key]"
53
- :options="filteredOptions[field.key] || field.options"
54
- :rules="field.rules"
55
- :placeholder="mode === 'view' ? '' : field.placeholder"
56
- :multiple="true"
57
- :show-chip="true"
58
- :is-disabled="mode === 'view'"
59
- :loading="field.loading"
60
- :label="field.label"
61
- :is-show-required="mode !== 'view'"
62
- empty-text="Ничего не найдено"
63
- option-label="label"
64
- option-value="value"
65
- chip-color="#e9eff9"
66
- @update:search="val => field.onSearch?.(val)"
67
- @update:scroll="() => field.onScroll?.()"
68
- @clear="
69
- () => {
70
- handleClear(field.key)
71
- nextTick(() => formRef.value?.validate())
72
- }
73
- "
74
- />
75
- </div>
76
- </q-form>
77
- </q-card-section>
78
-
79
- <q-card-actions align="center">
80
- <q-btn v-if="mode === 'view'" class="remove" flat label="Удалить" @click="emit('delete')" />
81
- <q-btn
82
- v-if="mode !== 'view'"
83
- class="confirm"
84
- flat
85
- :label="mode === 'edit' ? 'Сохранить' : 'Создать'"
86
- :disable="isSubmitDisabled"
87
- @click="submit"
88
- />
89
- <q-btn v-else class="confirm" flat label="Редактировать" @click="$emit('edit')" />
90
- <q-btn v-close-popup class="cancel" flat label="Закрыть" />
91
- </q-card-actions>
92
- </q-card>
93
- </q-dialog>
94
- </template>
95
-
96
- <script setup lang="ts">
97
- import { ref, watch, defineProps, defineEmits, nextTick, computed } from 'vue'
98
- import { useQuasar } from 'quasar'
99
- import AppModalSelect from '../components/ModalSelect.vue'
100
- import { notificationSettings } from '@/utils/notification'
101
- import { isEqual, normalizeValue, uuidv4 } from '@/utils/helpers'
102
-
103
- type ModalMode = 'view' | 'edit' | 'create'
104
- type FieldType = 'text' | 'select'
105
-
106
- interface FieldOption {
107
- label: string
108
- value: string
109
- }
110
- interface FieldSchema {
111
- key: string
112
- label: string
113
- type: FieldType
114
- rules?: ((val: any) => boolean | string)[]
115
- options?: FieldOption[]
116
- placeholder?: string
117
- onSearch?: (val: string) => void
118
- onScroll?: () => void
119
- loading?: boolean
120
- }
121
-
122
- const props = defineProps<{
123
- modelValue: boolean
124
- title: string
125
- mode: ModalMode
126
- fields: FieldSchema[]
127
- initialData?: Record<string, any>
128
- }>()
129
- const emit = defineEmits<{
130
- (e: 'update:modelValue', val: boolean): void
131
- (e: 'submit', data: Record<string, any>): void
132
- (e: 'edit'): void
133
- (e: 'delete'): void
134
- }>()
135
-
136
- const $q = useQuasar()
137
- const formRef = ref()
138
- const formData = ref<Record<string, any>>({})
139
- const filteredOptions = ref<Record<string, FieldOption[]>>({})
140
- const isSubmitDisabled = computed(() => {
141
- if (props.mode === 'view') return false
142
-
143
- const hasEmptyRequired = props.fields.some(field => {
144
- const isRequired = field.rules?.some(rule => rule('') !== true)
145
- const val = formData.value[field.key]
146
- const normalized = normalizeValue(val)
147
-
148
- const empty =
149
- normalized === null ||
150
- normalized === undefined ||
151
- (typeof normalized === 'string' && normalized.trim() === '') ||
152
- (Array.isArray(normalized) && normalized.length === 0)
153
-
154
- return isRequired && empty
155
- })
156
-
157
- if (hasEmptyRequired) return true
158
-
159
- const hasChanges = props.fields.some(field => {
160
- const key = field.key
161
- const current = normalizeValue(formData.value[key])
162
- const initial = normalizeValue(props.initialData?.[key])
163
- return !isEqual(current, initial)
164
- })
165
-
166
- return !hasChanges
167
- })
168
- function submit() {
169
- formRef.value?.validate().then(ok => {
170
- if (!ok) return
171
-
172
- const changed: Record<string, any> = {}
173
-
174
- for (const field of props.fields) {
175
- const key = field.key
176
- const current = formData.value[key]
177
- const initial = props.initialData?.[key]
178
-
179
- const normalizedCurrent = field.type === 'select' ? normalizeValue(current) : current
180
- const normalizedInitial = field.type === 'select' ? normalizeValue(initial) : initial
181
-
182
- if (!isEqual(normalizedCurrent, normalizedInitial)) {
183
- changed[key] = normalizedCurrent
184
- }
185
- }
186
-
187
- emit('submit', changed)
188
- })
189
- }
190
- function handleClear(key: string) {
191
- const field = props.fields.find(f => f.key === key)
192
- formData.value[key] = field?.type === 'select' ? [] : ''
193
-
194
- nextTick(() => {
195
- formRef.value?.validate()
196
- })
197
- }
198
- function generateUuid() {
199
- formData.value.uuid = uuidv4()
200
- }
201
- function copyToClipboard(text: string) {
202
- navigator.clipboard.writeText(text).then(() => {
203
- $q.notify(notificationSettings('success', 'UUID скопирован'))
204
- })
205
- }
206
-
207
- watch(
208
- () => props.modelValue,
209
- val => {
210
- if (val) {
211
- formData.value = { ...(props.initialData ?? {}) }
212
- }
213
- },
214
- { immediate: true },
215
- )
216
- </script>
217
-
218
- <style lang="scss">
219
- .custom-select-menu {
220
- max-height: 250px !important;
221
- overflow-y: auto !important;
222
- }
223
- </style>
224
- <style scoped lang="scss">
225
- .uuid-btn {
226
- height: 32px;
227
- padding: 0 10px;
228
- border: 1px solid #3f8cff;
229
- color: #3f8cff;
230
- font-weight: 700;
231
- font-size: 14px;
232
- background: white;
233
- border-radius: 6px;
234
- }
235
-
236
- .q-card {
237
- border-radius: 12px;
238
- background: #fff;
239
- box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.25);
240
- font-family: NunitoSansFont, sans-serif;
241
-
242
- .modal-title {
243
- color: #1d425d;
244
- text-align: center;
245
- font-size: 32px;
246
- font-weight: 700;
247
- padding: 18px 29px;
248
- }
249
-
250
- .q-card__section {
251
- padding: 0;
252
- }
253
-
254
- .q-form {
255
- padding: 0 29px;
256
- }
257
-
258
- .field-wrapper {
259
- display: flex;
260
- flex-direction: column;
261
- margin-bottom: 15px;
262
- }
263
-
264
- .field-label {
265
- font-size: 14px;
266
- font-weight: 700;
267
- color: #7d8592;
268
- }
269
- ::v-deep(.q-placeholder) {
270
- color: #7d8592;
271
- }
272
- ::v-deep(.q-field__control) {
273
- border-radius: 8px;
274
- border: 1px solid #d8e0f0;
275
- background: #fff;
276
- box-shadow: 0px 1px 2px 0px rgba(184, 200, 224, 0.22);
277
- }
278
-
279
- ::v-deep(.q-field--filled .q-field__control:before) {
280
- background: #fff !important;
281
- border: none;
282
- }
283
-
284
- ::v-deep(.q-field--with-bottom) {
285
- padding-bottom: 0;
286
- }
287
-
288
- ::v-deep(.q-field__bottom) {
289
- padding: 0;
290
- }
291
-
292
- .clear-input {
293
- color: #d8e0f0;
294
- }
295
-
296
- .required {
297
- color: #f65160;
298
- font-weight: bold;
299
- }
300
-
301
- &__actions {
302
- padding: 18px 0;
303
- border-radius: 0px 0px 16px 16px;
304
- background: #f4f9fd;
305
-
306
- button {
307
- padding: 13px 37px;
308
- border-radius: 4px;
309
- font-size: 16px;
310
- font-weight: 700;
311
- text-transform: none;
312
-
313
- &.remove {
314
- border: 1px solid #f65160;
315
- color: #f65160;
316
- }
317
- &.confirm {
318
- background: #3f8cff;
319
- color: #fff;
320
- }
321
-
322
- &.cancel {
323
- color: #3f8cff;
324
- border: 1px solid #3f8cff;
325
- }
326
- }
327
- }
328
- }
329
- </style>
1
+ <template>
2
+ <q-dialog :model-value="modelValue" @update:model-value="val => emit('update:modelValue', val)">
3
+ <q-card style="min-width: 700px">
4
+ <q-card-section>
5
+ <div class="modal-title">{{ title }}</div>
6
+ </q-card-section>
7
+
8
+ <q-card-section>
9
+ <q-form ref="formRef" @submit.prevent="submit">
10
+ <div v-for="field in fields" :key="field.key" class="field-wrapper">
11
+ <label v-if="field.type === 'text'" class="field-label">
12
+ {{ field.label }}
13
+ <span v-if="field.rules?.length && mode !== 'view'" class="required">*</span>
14
+ </label>
15
+
16
+ <q-input
17
+ v-if="field.type === 'text'"
18
+ v-model="formData[field.key]"
19
+ :rules="field.rules"
20
+ :readonly="mode === 'view' || (field.key === 'uuid' && mode === 'edit')"
21
+ filled
22
+ :placeholder="field.placeholder"
23
+ >
24
+ <template #append>
25
+ <q-icon
26
+ v-if="mode !== 'view' && formData[field.key] && !(field.key === 'uuid' && mode === 'edit')"
27
+ name="close"
28
+ class="cursor-pointer clear-input"
29
+ @click="() => handleClear(field.key)"
30
+ />
31
+ <q-btn
32
+ v-if="field.key === 'uuid' && mode === 'create'"
33
+ flat
34
+ no-caps
35
+ label="UUID"
36
+ size="sm"
37
+ class="q-ml-sm uuid-btn"
38
+ @click="generateUuid"
39
+ />
40
+ <q-icon
41
+ v-else-if="field.key === 'uuid' && mode !== 'create'"
42
+ name="content_copy"
43
+ class="cursor-pointer q-ml-sm copy-icon"
44
+ color="primary"
45
+ @click="copyToClipboard(formData[field.key])"
46
+ />
47
+ </template>
48
+ </q-input>
49
+
50
+ <app-modal-select
51
+ v-else-if="field.type === 'select'"
52
+ v-model="formData[field.key]"
53
+ :options="filteredOptions[field.key] || field.options"
54
+ :rules="field.rules"
55
+ :placeholder="mode === 'view' ? '' : field.placeholder"
56
+ :multiple="true"
57
+ :show-chip="true"
58
+ :is-disabled="mode === 'view'"
59
+ :loading="field.loading"
60
+ :label="field.label"
61
+ :is-show-required="mode !== 'view'"
62
+ empty-text="Ничего не найдено"
63
+ option-label="label"
64
+ option-value="value"
65
+ chip-color="#e9eff9"
66
+ @update:search="val => field.onSearch?.(val)"
67
+ @update:scroll="() => field.onScroll?.()"
68
+ @clear="
69
+ () => {
70
+ handleClear(field.key)
71
+ nextTick(() => formRef.value?.validate())
72
+ }
73
+ "
74
+ />
75
+ </div>
76
+ </q-form>
77
+ </q-card-section>
78
+
79
+ <q-card-actions align="center">
80
+ <q-btn v-if="mode === 'view'" class="remove" flat label="Удалить" @click="emit('delete')" />
81
+ <q-btn
82
+ v-if="mode !== 'view'"
83
+ class="confirm"
84
+ flat
85
+ :label="mode === 'edit' ? 'Сохранить' : 'Создать'"
86
+ :disable="isSubmitDisabled"
87
+ @click="submit"
88
+ />
89
+ <q-btn v-else class="confirm" flat label="Редактировать" @click="$emit('edit')" />
90
+ <q-btn v-close-popup class="cancel" flat label="Закрыть" />
91
+ </q-card-actions>
92
+ </q-card>
93
+ </q-dialog>
94
+ </template>
95
+
96
+ <script setup lang="ts">
97
+ import { ref, watch, defineProps, defineEmits, nextTick, computed } from 'vue'
98
+ import { useQuasar } from 'quasar'
99
+ import AppModalSelect from '../components/ModalSelect.vue'
100
+ import { notificationSettings } from '@/utils/notification'
101
+ import { isEqual, normalizeValue, uuidv4 } from '@/utils/helpers'
102
+
103
+ type ModalMode = 'view' | 'edit' | 'create'
104
+ type FieldType = 'text' | 'select'
105
+
106
+ interface FieldOption {
107
+ label: string
108
+ value: string
109
+ }
110
+ interface FieldSchema {
111
+ key: string
112
+ label: string
113
+ type: FieldType
114
+ rules?: ((val: any) => boolean | string)[]
115
+ options?: FieldOption[]
116
+ placeholder?: string
117
+ onSearch?: (val: string) => void
118
+ onScroll?: () => void
119
+ loading?: boolean
120
+ }
121
+
122
+ const props = defineProps<{
123
+ modelValue: boolean
124
+ title: string
125
+ mode: ModalMode
126
+ fields: FieldSchema[]
127
+ initialData?: Record<string, any>
128
+ }>()
129
+ const emit = defineEmits<{
130
+ (e: 'update:modelValue', val: boolean): void
131
+ (e: 'submit', data: Record<string, any>): void
132
+ (e: 'edit'): void
133
+ (e: 'delete'): void
134
+ }>()
135
+
136
+ const $q = useQuasar()
137
+ const formRef = ref()
138
+ const formData = ref<Record<string, any>>({})
139
+ const filteredOptions = ref<Record<string, FieldOption[]>>({})
140
+ const isSubmitDisabled = computed(() => {
141
+ if (props.mode === 'view') return false
142
+
143
+ const hasEmptyRequired = props.fields.some(field => {
144
+ const isRequired = field.rules?.some(rule => rule('') !== true)
145
+ const val = formData.value[field.key]
146
+ const normalized = normalizeValue(val)
147
+
148
+ const empty =
149
+ normalized === null ||
150
+ normalized === undefined ||
151
+ (typeof normalized === 'string' && normalized.trim() === '') ||
152
+ (Array.isArray(normalized) && normalized.length === 0)
153
+
154
+ return isRequired && empty
155
+ })
156
+
157
+ if (hasEmptyRequired) return true
158
+
159
+ const hasChanges = props.fields.some(field => {
160
+ const key = field.key
161
+ const current = normalizeValue(formData.value[key])
162
+ const initial = normalizeValue(props.initialData?.[key])
163
+ return !isEqual(current, initial)
164
+ })
165
+
166
+ return !hasChanges
167
+ })
168
+ function submit() {
169
+ formRef.value?.validate().then(ok => {
170
+ if (!ok) return
171
+
172
+ const changed: Record<string, any> = {}
173
+
174
+ for (const field of props.fields) {
175
+ const key = field.key
176
+ const current = formData.value[key]
177
+ const initial = props.initialData?.[key]
178
+
179
+ const normalizedCurrent = field.type === 'select' ? normalizeValue(current) : current
180
+ const normalizedInitial = field.type === 'select' ? normalizeValue(initial) : initial
181
+
182
+ if (!isEqual(normalizedCurrent, normalizedInitial)) {
183
+ changed[key] = normalizedCurrent
184
+ }
185
+ }
186
+
187
+ emit('submit', changed)
188
+ })
189
+ }
190
+ function handleClear(key: string) {
191
+ const field = props.fields.find(f => f.key === key)
192
+ formData.value[key] = field?.type === 'select' ? [] : ''
193
+
194
+ nextTick(() => {
195
+ formRef.value?.validate()
196
+ })
197
+ }
198
+ function generateUuid() {
199
+ formData.value.uuid = uuidv4()
200
+ }
201
+ function copyToClipboard(text: string) {
202
+ navigator.clipboard.writeText(text).then(() => {
203
+ $q.notify(notificationSettings('success', 'UUID скопирован'))
204
+ })
205
+ }
206
+
207
+ watch(
208
+ () => props.modelValue,
209
+ val => {
210
+ if (val) {
211
+ formData.value = { ...(props.initialData ?? {}) }
212
+ }
213
+ },
214
+ { immediate: true },
215
+ )
216
+ </script>
217
+
218
+ <style lang="scss">
219
+ .custom-select-menu {
220
+ max-height: 250px !important;
221
+ overflow-y: auto !important;
222
+ }
223
+ </style>
224
+ <style scoped lang="scss">
225
+ .uuid-btn {
226
+ height: 32px;
227
+ padding: 0 10px;
228
+ border: 1px solid #3f8cff;
229
+ color: #3f8cff;
230
+ font-weight: 700;
231
+ font-size: 14px;
232
+ background: white;
233
+ border-radius: 6px;
234
+ }
235
+
236
+ .q-card {
237
+ border-radius: 12px;
238
+ background: #fff;
239
+ box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.25);
240
+ font-family: NunitoSansFont, sans-serif;
241
+
242
+ .modal-title {
243
+ color: #1d425d;
244
+ text-align: center;
245
+ font-size: 32px;
246
+ font-weight: 700;
247
+ padding: 18px 29px;
248
+ }
249
+
250
+ .q-card__section {
251
+ padding: 0;
252
+ }
253
+
254
+ .q-form {
255
+ padding: 0 29px;
256
+ }
257
+
258
+ .field-wrapper {
259
+ display: flex;
260
+ flex-direction: column;
261
+ margin-bottom: 15px;
262
+ }
263
+
264
+ .field-label {
265
+ font-size: 14px;
266
+ font-weight: 700;
267
+ color: #7d8592;
268
+ }
269
+ ::v-deep(.q-placeholder) {
270
+ color: #7d8592;
271
+ }
272
+ ::v-deep(.q-field__control) {
273
+ border-radius: 8px;
274
+ border: 1px solid #d8e0f0;
275
+ background: #fff;
276
+ box-shadow: 0px 1px 2px 0px rgba(184, 200, 224, 0.22);
277
+ }
278
+
279
+ ::v-deep(.q-field--filled .q-field__control:before) {
280
+ background: #fff !important;
281
+ border: none;
282
+ }
283
+
284
+ ::v-deep(.q-field--with-bottom) {
285
+ padding-bottom: 0;
286
+ }
287
+
288
+ ::v-deep(.q-field__bottom) {
289
+ padding: 0;
290
+ }
291
+
292
+ .clear-input {
293
+ color: #d8e0f0;
294
+ }
295
+
296
+ .required {
297
+ color: #f65160;
298
+ font-weight: bold;
299
+ }
300
+
301
+ &__actions {
302
+ padding: 18px 0;
303
+ border-radius: 0px 0px 16px 16px;
304
+ background: #f4f9fd;
305
+
306
+ button {
307
+ padding: 13px 37px;
308
+ border-radius: 4px;
309
+ font-size: 16px;
310
+ font-weight: 700;
311
+ text-transform: none;
312
+
313
+ &.remove {
314
+ border: 1px solid #f65160;
315
+ color: #f65160;
316
+ }
317
+ &.confirm {
318
+ background: #3f8cff;
319
+ color: #fff;
320
+ }
321
+
322
+ &.cancel {
323
+ color: #3f8cff;
324
+ border: 1px solid #3f8cff;
325
+ }
326
+ }
327
+ }
328
+ }
329
+ </style>