Последняя версия с сервера прошлого разработчика

This commit is contained in:
2025-07-10 04:35:51 +00:00
commit c731570032
1174 changed files with 134314 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
<template>
<default-field
:field="field"
:errors="errors"
:full-width-content="true"
:show-help-text="showHelpText"
>
<template slot="field">
<KeyValueTable
:edit-mode="!field.readonly"
:can-delete-row="field.canDeleteRow"
>
<KeyValueHeader
:key-label="field.keyLabel"
:value-label="field.valueLabel"
/>
<div class="bg-white overflow-hidden key-value-items">
<KeyValueItem
v-for="(item, index) in theData"
:index="index"
@remove-row="removeRow"
:item.sync="item"
:key="item.id"
:ref="item.id"
:read-only="field.readonly"
:read-only-keys="field.readonlyKeys"
:can-delete-row="field.canDeleteRow"
/>
</div>
</KeyValueTable>
<div
class="mr-11"
v-if="!field.readonly && !field.readonlyKeys && field.canAddRow"
>
<button
@click="addRowAndSelect"
:dusk="`${field.attribute}-add-key-value`"
type="button"
class="btn btn-link dim cursor-pointer rounded-lg mx-auto text-primary mt-3 px-3 rounded-b-lg flex items-center"
>
<icon type="add" width="24" height="24" view-box="0 0 24 24" />
<span class="ml-1">{{ field.actionText }}</span>
</button>
</div>
</template>
</default-field>
</template>
<script>
import { FormField, HandlesValidationErrors } from 'laravel-nova'
import KeyValueItem from '@/components/Form/KeyValueField/KeyValueItem'
import KeyValueHeader from '@/components/Form/KeyValueField/KeyValueHeader'
import KeyValueTable from '@/components/Form/KeyValueField/KeyValueTable'
function guid() {
var S4 = function () {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
}
return (
S4() +
S4() +
'-' +
S4() +
'-' +
S4() +
'-' +
S4() +
'-' +
S4() +
S4() +
S4()
)
}
export default {
mixins: [HandlesValidationErrors, FormField],
components: { KeyValueTable, KeyValueHeader, KeyValueItem },
data: () => ({ theData: [] }),
mounted() {
this.theData = _.map(this.value || {}, (value, key) => ({
id: guid(),
key: `${key}`,
value,
}))
if (this.theData.length == 0) {
this.addRow()
}
},
methods: {
/**
* Provide a function that fills a passed FormData object with the
* field's internal value attribute.
*/
fill(formData) {
formData.append(this.field.attribute, JSON.stringify(this.finalPayload))
},
/**
* Add a row to the table.
*/
addRow() {
return _.tap(guid(), id => {
this.theData = [...this.theData, { id, key: '', value: '' }]
return id
})
},
/**
* Add a row to the table and select its first field.
*/
addRowAndSelect() {
return this.selectRow(this.addRow())
},
/**
* Remove the row from the table.
*/
removeRow(id) {
return _.tap(
_.findIndex(this.theData, row => row.id == id),
index => this.theData.splice(index, 1)
)
},
/**
* Select the first field in a row with the given ref ID.
*/
selectRow(refId) {
return this.$nextTick(() => {
this.$refs[refId][0].$refs.keyField.select()
})
},
},
computed: {
/**
* Return the final filtered json object
*/
finalPayload() {
return _(this.theData)
.map(row => (row && row.key ? [row.key, row.value] : undefined))
.reject(row => row === undefined)
.fromPairs()
.value()
},
},
}
</script>

View File

@@ -0,0 +1,28 @@
<template>
<div class="bg-30 rounded-t-lg flex border-b border-50">
<div
class="bg-clip w-48 uppercase font-bold text-xs text-80 tracking-wide px-3 py-3"
>
{{ keyLabel }}
</div>
<div
class="bg-clip flex-grow uppercase font-bold text-xs text-80 tracking-wide px-3 py-3 border-l border-50"
>
{{ valueLabel }}
</div>
</div>
</template>
<script>
export default {
props: {
keyLabel: {
type: String,
},
valueLabel: {
type: String,
},
},
}
</script>

View File

@@ -0,0 +1,109 @@
<template>
<div v-if="isNotObject" class="flex items-center key-value-item">
<div class="flex flex-grow border-b border-50 key-value-fields">
<div
class="w-48 cursor-text"
:class="{ 'bg-30': readOnlyKeys || !isEditable }"
>
<textarea
:dusk="`key-value-key-${index}`"
v-model="item.key"
@focus="handleKeyFieldFocus"
ref="keyField"
type="text"
class="font-mono text-sm resize-none block min-h-input w-full form-control form-input form-input-row py-4 text-90"
:disabled="!isEditable || readOnlyKeys"
style="background-clip: border-box"
:class="{
'bg-white': !isEditable || readOnlyKeys,
'hover:bg-20 focus:bg-white': isEditable && !readOnlyKeys,
}"
/>
</div>
<div @click="handleValueFieldFocus" class="flex-grow border-l border-50">
<textarea
:dusk="`key-value-value-${index}`"
v-model="item.value"
@focus="handleValueFieldFocus"
ref="valueField"
type="text"
class="font-mono text-sm block min-h-input w-full form-control form-input form-input-row py-4 text-90"
:disabled="!isEditable"
:class="{
'bg-white': !isEditable,
'hover:bg-20 focus:bg-white': isEditable,
}"
/>
</div>
</div>
<div
v-if="isEditable && canDeleteRow"
class="flex justify-center h-11 w-11 absolute"
style="right: -50px"
>
<button
@click="$emit('remove-row', item.id)"
:dusk="`remove-key-value-${index}`"
type="button"
tabindex="-1"
class="flex appearance-none cursor-pointer text-70 hover:text-primary active:outline-none active:shadow-outline focus:outline-none focus:shadow-outline"
title="Delete"
>
<icon />
</button>
</div>
</div>
</template>
<script>
import autosize from 'autosize'
export default {
props: {
index: Number,
item: Object,
disabled: {
type: Boolean,
default: false,
},
readOnly: {
type: Boolean,
default: false,
},
readOnlyKeys: {
type: Boolean,
default: false,
},
canDeleteRow: {
type: Boolean,
default: true,
},
},
mounted() {
autosize(this.$refs.keyField)
autosize(this.$refs.valueField)
},
methods: {
handleKeyFieldFocus() {
this.$refs.keyField.select()
},
handleValueFieldFocus() {
this.$refs.valueField.select()
},
},
computed: {
isNotObject() {
return !(this.item.value instanceof Object)
},
isEditable() {
return !this.readOnly && !this.disabled
},
},
}
</script>

View File

@@ -0,0 +1,23 @@
<template>
<div
class="relative rounded-lg rounded-b-lg bg-30 bg-clip border border-60"
:class="{ 'mr-11': editMode && deleteRowEnabled }"
>
<slot />
</div>
</template>
<script>
export default {
props: {
deleteRowEnabled: {
type: Boolean,
default: true,
},
editMode: {
type: Boolean,
default: true,
},
},
}
</script>