refactor(color): unify color sanitizing and picking behind shared components

- Add AKSRT\Core\Color::sanitize($value, $allow_alpha) as the single PHP
  color sanitizer; replace sanitize_hex_color calls and per-class regexes
  (FloatButtons, FieldSchema, ThemeSearch, icon cards, TicketStatusService)
- SchemaProvider / ControllerBase sanitize `color` fields as colors;
  alpha kept only when the schema sets showAlpha
- Split SchemaProvider OAuth validation and option matching into sibling
  traits to stay under the 1000-line limit
- Add AksColorPicker.vue + utils/color.js mirroring the PHP rules; AksField,
  FloatBtnCommonFields and TicketStatusPanel use it
- Widget background color input now uses wpColorPicker
- Remove dead AksCompositeField dimensions/spacing/background branches and
  the unused Gutenberg ColorPicker var
- Add color-unification contract test; update harness requires and tests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Fable 5 committed 2026-10-28 20:47:41 +08:00
1 parent 74021d26bb
commit 57ff405691
32 files changed
+522 -456

No files matched your search

@@ -72,11 +72,9 @@
@click="form.color = swatch"
/>
<!-- 自定义色:未选中时显示色环,选中后显示当前色并带选中环。 -->
<n-color-picker
:value="previewColor"
:modes="['hex']"
:show-alpha="false"
@update:value="setColor"
<AksColorPicker
:model-value="previewColor"
@update:model-value="setColor"
>
<template #trigger="{ onClick, ref: setTriggerRef }">
<button
@@ -92,7 +90,7 @@
@click="onClick"
/>
</template>
</n-color-picker>
</AksColorPicker>
</div>
<n-input
v-model:value="form.color"
@@ -128,6 +126,8 @@
import { computed, h, onMounted, ref } from 'vue'
import { NButton, NSpace, useDialog, useMessage } from 'naive-ui'
import api from '@/api'
import AksColorPicker from '@/components/form/AksColorPicker.vue'
import { toHex } from '@/utils/color.js'
const message = useMessage()
const dialog = useDialog()
@@ -146,7 +146,6 @@ const editing = ref(null)
const rows = ref([])
const DEFAULT_COLOR = '#6b7280'
const HEX_RE = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i
/** 与 TicketStatusService::KEY_PATTERN 保持一致。 */
const KEY_RE = /^[a-z][a-z0-9_]{1,23}$/
@@ -157,16 +156,6 @@ function normalizeKey(value) {
return String(value || '').trim().toLowerCase()
}
/**
* 归一化为 TicketStatusService::sanitize_color() 接受的小写 #rgb / #rrggbb;
* 允许省略 #。非法值返回空串。
*/
function toHex(value) {
let hex = String(value || '').trim().toLowerCase()
if (hex && !hex.startsWith('#')) hex = `#${hex}`
return HEX_RE.test(hex) ? hex : ''
}
const rules = {
name: [
{ required: true, message: '请填写状态名称', trigger: 'blur' },
@@ -205,10 +194,7 @@ const currentHex = computed(() => toHex(form.value.color))
const previewColor = computed(() => currentHex.value || DEFAULT_COLOR)
const isCustomColor = computed(() => currentHex.value !== '' && !SWATCHES.includes(currentHex.value))
/**
* 取色器已关闭 alpha(默认开启时回传 #rrggbbaa,会被后端回落成灰色),
* 这里仍只接受合法十六进制,其余忽略。
*/
/** AksColorPicker 已归一化为 hex;清空(空串)时保留当前色。 */
function setColor(value) {
const hex = toHex(value)
if (hex) form.value.color = hex