Ürün Modülü Müşteri Yönetimi

1.7k görüntülenme Markdown

Bir ürün hizmetinde müşterinin ne göreceğine ve ne yapabileceğine beş isteğe bağlı üye karar verir. Bunlar yönetim sekmesi, göstergeler, kısayollar, aksiyonlar ve görünüm işaretidir.

Genel Bakış

Ürün modülü müşteriye varsayılan olarak hiçbir şey açmaz. Aşağıdaki beş üye isteğe bağlıdır ve tipten bağımsızdır; doldurmak için çekirdekte değişiklik gerekmez.

Özet sekmesi client_overview_data() çıktısından kurulan kullanım halkalarını ve hesap satırlarını gösterir; Yönetim sekmesi sizin pano sayfanızı gösterir. İkisinde de gösterge olabilir, bu yüzden modül hangisini doldurduğunu bilmelidir.

has_client_management() Sekme kapısı.
client_overview_data() Özet sekmesinin göstergeleri ve hesap satırları.
client_quick_actions() Özetteki kısayol butonları.
client_callable_methods Müşterinin çalıştırabileceği adlar.
$client_area Yalnız panonun müşteri görünümünde true, yönetici görünümünde false.

Ön Koşullar

  • Çalışan bir ürün modülü: Ürün Modülü Yazma.
  • special ya da software tipinde, active ve bir modüle bağlı hizmet. Askıya alınmış dahil diğer durumlar başta reddedilir.
  • Müşteri olarak test edin; yönetici görünümü işareti ayarlamaz.

Yapı

İstediğinizModül ne yaparVarsayılan
Müşteride hiç ekran olmasınHiçbir şeyVarsayılan
Yönetim sekmesi olsunpages/dashboard.php ekleyin ya da page_dashboard() tanımlayınSekme yok
Sekme olmasın, pano yalnız yöneticidehas_client_management() false döndürsünSekme çıkar
Özette kullanım göstergelericlient_overview_data() doldurunBoş, gösterge yok
Özette kısayollarclient_quick_actions() doldurunBoş, kısayol yok
Çalıştırılabilir bir aksiyonAdını $client_callable_methods içinde bildirin, handle_{ad}() yazınReddedilir
GET ile sunulan aksiyon (indirme)Ayrıca $client_readonly_methods içinde sayınToken ve POST
Bir pano bloğunu müşteriden gizleyinBloğu $client_area denetimiyle sarınİkisine de görünür
istek zinciri
Yönetim sekmesine tıklandı
  └─ use_module_method'suz GET isteği   ->  ClientServices::get_management_details
       ├─ sahip + tip + etkin durum denetimi
       ├─ client_module_instance()        ->  $client_area = true, $area_link atanır
       ├─ ProductModule::service_management_page()  ->  get_page('dashboard')
       └─ satır içi script etiketleri ayrılır, tema köprüsünce ayrıca değerlendirilir

Genel Bakış sekmesi
  └─ hizmetler controller'ı, special ve software hizmetler için
       ├─ client_overview_data()   ->  kullanım halkaları + hesap satırları
       └─ client_quick_actions()   ->  kısayol butonları

Bir kısayol ya da pano butonu
  └─ POST use_module_method  ->  izin listesi  ->  handle_{name}()

Adım Adım

Yönetim Sekmesini Açın

Pano sayfası eklemek onaydır: kapı dosyaya bakar.

  1. Modülünüzde pages/dashboard.php oluşturun; içeride $module canlı örnektir.
  2. Pano yalnız yöneticiler içinse kapıyı ezin. Admin hizmet sayfası yine de gösterir.
  3. Tema köprüsü satır içi script'leri HTML'den ayırır ve ayrıca değerlendirir.

Özeti Doldurun

client_overview_data() üç liste döndürür. Henüz bir şey sağlanmamışken boş dizi döndürün; özet o zaman gösterge göstermez.

  1. gauges: limitli her kaynak için bir kayıt; sıfır ya da altı sınırsız demektir.
  2. resources: isteğe bağlı sayaçlar — kullanılan ve toplam biçimi ya da oran olmayan tek bir value.
  3. account: kimlik satırları. Hizmet parolası sizin yerinize eklenir.

Bir Aksiyon Açın

İki şey gerekir, tek başına hiçbiri yetmez: adın izin listesinde olması ve handle_ ön ekli bir metot.

  1. public array $client_callable_methods = ['reset_usage']; şeklinde, ön eksiz bildirin.
  2. public function handle_reset_usage(): array yazın — argümansız; istekten ve hizmetten okuyun.
  3. API istemcisini handler'ın içinde kurun: müşteri çağrısı için hiçbir şey hazırlanmaz.

İki Kez Göstermekten Kaçının

Aynı dosya, özet sekmesi olmayan admin hizmet sayfasına da hizmet eder. Blokları silmek yerine $client_area arkasında gizleyin.

Referans

Beş Üye

tam imzalar
// ProductModule üzerinde bildirilir; ihtiyacınız olanı ezin.
public bool  $client_area            = false;   // yalnız müşteri basıcısı true yapar
public array $client_callable_methods = [];     // handle_ ön eki OLMADAN adlar
public array $client_readonly_methods = [];     // yukarıdakilerin alt kümesi, GET ile güvenli

public function has_client_management(): bool;
public function client_overview_data(): array;
public function client_quick_actions(int $limit = 8): array;

// Bildirilen bir çağrılabilir için işleyiciniz. Parametresiz; JSON yükünü döndürür.
public function handle_reset_usage(): array;

client_overview_data() Biçimi

controller'ın okuduğu yapı
return [
    'gauges' => [
        [
            'key'   => 'storage',
            'label' => $this->lang['storage-usage'],
            'icon'  => 'bi bi-hdd',
            'used'  => 4.5,
            'total' => 20,          // 0 ya da altı sınırsız demektir; netlik için -1 geçin
            'unit'  => 'GB',
        ],
    ],
    'resources' => [
        // Oran biçimi: göstergeyle aynı anahtarlar.
        ['key' => 'seats', 'label' => 'Seats', 'icon' => 'bi bi-people', 'used' => 3, 'total' => 10, 'unit' => ''],
        // Değer biçimi: limiti olmayan tek bir okuma.
        ['key' => 'region', 'label' => 'Region', 'icon' => 'bi bi-globe', 'value' => 'eu-west'],
    ],
    'account' => [
        ['key' => 'account_id', 'label' => 'Account ID', 'type' => 'text', 'copyable' => true, 'value' => 'ac_1042'],
        ['key' => 'username',   'label' => 'Username',   'type' => 'text', 'copyable' => true, 'value' => 'acme'],
        ['key' => 'status',     'label' => 'Status',     'type' => 'badge', 'badge_color' => 'success', 'value' => 'Active'],
        ['key' => 'console',    'label' => 'Console',    'type' => 'link',  'value' => 'https://panel.example.com'],
    ],
];
gauges: total Sıfır ya da altı sınırsızdır: gösterge halka şeridinden çıkıp sonsuz işaretiyle özellik listesine geçer.
gauges: yüzde yok Ham sayı gönderin; oranı ve renk kademesini tema hesaplar, hesaplanmış yüzde yoksayılır.
resources: sıfır toplam Göstergeden farklı olarak burada sıfır gerçek bir limittir. Yalnız negatif toplam sınırsızdır.
account: type text, link, badge ya da password. copyable kopyalama butonu ekler; bağlantı satırı tam genişlik alır.
account: badge_color success, warning, danger ya da varsayılan. İkon renkten gelir.
account: parola satırı Anahtarı username olan satırın ardına, öyle bir satır yoksa en sona eklenir.
her değer verildiği gibi gösterilir Tarihleri ve sayıları önce biçimlendirin: ham zaman damgası müşteriye öyle ulaşır.

client_quick_actions() Biçimi

imza ve dönüş
public function client_quick_actions(int $limit = 8): array
{
    $actions = [
        // action => true: işleyiciyi yerinde, çağrılabilir izin listesi üzerinden koşturur.
        ['key' => 'reset_usage', 'label' => $this->lang['action-reset-usage'],
         'icon' => 'bi bi-arrow-counterclockwise', 'action' => true, 'method' => 'reset_usage'],

        // action => false: bunun yerine yönetim sekmesindeki bir sayfaya gider.
        ['key' => 'backups', 'label' => $this->lang['action-backups'],
         'icon' => 'bi bi-archive', 'action' => false, 'method' => 'backups'],
    ];

    // Limite uyun: kaç tanesinin sığacağına çağıran karar verir.
    return array_slice($actions, 0, $limit);
}

Handler'ınız Çalışmadan Önce

"Aksiyonum hiçbir şey yapmıyor" bildirimlerinin çoğu bu retlerden biridir.

kapı, sırasıyla
// ClientServices::use_module_method, kararlara indirgenmiş hali.
$service = $this->owned_managed_service($uid);      // sahiplik, tip, modül ve aktif durum denetimi
$method  = (string) Filter::init("REQUEST/method", "route");

$module = $this->client_module_instance($service);  // $client_area ve $area_link değerlerini ayarlar

$handleMethod = 'handle_' . str_replace('-', '_', $method);
$isTool       = in_array($method, ['tool_action', 'tool_table', 'sso_panel_login'], true);

// İKİ koşul birden: izin listesinde bildirilmiş VE işleyici gerçekten var.
$isClientCallable = !$isTool
    && in_array($method, $module->client_callable_methods ?? [], true)
    && method_exists($module, $handleMethod);

if (!$isTool && !$isClientCallable)
    throw new \Exception(Language::gc("website/services/err-invalid"));

// Salt okunur çağrılabilirler jetonu ve aktif hizmet şartını atlar.
$isReadonly = $isClientCallable && in_array($method, $module->client_readonly_methods ?? [], true);
$mutates    = ($method === 'tool_action' || $isClientCallable) && !$isReadonly;

if ($mutates && !\Validation::verify_csrf_token((string) Filter::init("POST/token", "hclear"), "services"))
    throw new \Exception(Language::g("needs/csrf-failed"));

if ($mutates && ($service['status'] ?? '') !== 'active')
    throw new \Exception(Language::gc("website/services/err-invalid"));
sahiplik, tip ve modül Hizmet oturum açmış hesaba ait olmalı, hosting, server, special ya da software tipinde olmalı ve none dışında bir modül adı taşımalıdır. "Hizmet Detaylarını Kısıtla" ile işaretlenen hizmet de bulunamadı sayılır.
izin listesi isteğe bağlı değildir Bildirilmemiş bir handler, var olsa bile sessizce reddedilir; bu da bozuk bir buton gibi görünür. handle_create gibi metotları müşteriye kapalı tutan şey budur.
token ve canlı hizmet Sahiplik araması zaten active ister, dolayısıyla askıya alınmış hizmet okumada da reddedilir. Değişiklik yapan çağrı ayrıca geçerli bir token ister.
gate:service.client_tool Handler'ınızdan hemen önce çalışır. Boş olmayan bir dize döndüren dinleyici çağrıyı o mesajla veto eder.
action:service.client_tool_ran Sonrasında çalışır: hizmet, istenen metot, çözülen metot adı ve sonuç ile. Dönüş kullanılmaz.
filter:client.service_management_content Pano HTML'ini, satır içi script'ler ayrılmadan önce referansla filtreler.

Örnek

Modül yarısı ve pano yarısı; $client_area kararı ikincisinde verilir.

modül tarafı
// handle_ ön eki olmadan bildirilir. Burada olmayan her şey reddedilir.
public array $client_callable_methods = ['reset_usage', 'download_report'];

// GET bağlantısı üzerinden sunulur, bu yüzden jeton ve POST şartından muaftır.
public array $client_readonly_methods = ['download_report'];

public function client_overview_data(): array
{
    $remote = $this->fetchRemoteStatus();
    if (!$remote) return [];                       // henüz bir şey sağlanmadı: gösterge yok

    $gauges = [];
    if (isset($remote['storage_limit']))
        $gauges[] = [
            'key'   => 'storage',
            'label' => $this->lang['storage-usage'],
            'icon'  => 'bi bi-hdd',
            'used'  => (float) ($remote['used_storage'] ?? 0),
            'total' => (float) $remote['storage_limit'] > 0 ? (float) $remote['storage_limit'] : -1,
            'unit'  => 'GB',
        ];

    $account = [];
    $username = (string) ($this->options['login']['username'] ?? '');

    // Controller parola satırını tam bunun ardına ekler.
    if ($username !== '')
        $account[] = ['key' => 'username', 'label' => $this->lang['username'], 'type' => 'text', 'copyable' => true, 'value' => $username];

    $status = (string) ($remote['status'] ?? '');
    if ($status !== '')
        $account[] = [
            'key'         => 'status',
            'label'       => $this->lang['account-status'],
            'type'        => 'badge',
            'badge_color' => $status === 'active' ? 'success' : 'secondary',
            'value'       => $this->lang['status-' . $status] ?? ucfirst($status),
        ];

    if (!$gauges && !$account) return [];

    return ['gauges' => $gauges, 'resources' => [], 'account' => $account];
}

public function handle_reset_usage(): array
{
    // Müşteri tetikler: API istemcisini sizin için hazırlayan hiçbir şey yok.
    $this->initApi();

    $accountId = $this->options['config']['id'] ?? '';
    if (!$accountId) throw new Exception($this->lang['err-not-provisioned']);

    $this->api->call('accounts/' . $accountId . '/usage/reset', [], 'POST');

    return ['status' => 'successful', 'message' => $this->lang['usage-reset-ok']];
}
pages/dashboard.php, iki izleyici
<?php
/** @var ProductModule $module */

// Yöneticide Özet sekmesi yok, bu yüzden bu blokları korumak zorunda. Müşteri aynı
// sayıları orada zaten görüyor; o yüzden burada silmek yerine gizleyin.
if (!($module->client_area ?? false)):
?>
    <div class="row">
        <!-- gösterge widget'ları ve hesap kartı -->
    </div>
<?php endif; ?>

<!-- Aksiyonlar iki görünümde de kalır: burası yönetim yüzeyidir. -->
<button type="button" class="btn btn-primary" id="acmeResetUsage">Reset Usage</button>

<script>
(function () {
    // Her aramayı null'a karşı koruyun: $client_area ile gizlenen blok kimliklerini de
    // götürür ve buradaki yakalanmamış hata bu düğmeyi değil tüm paneli düşürür.
    var btn = document.getElementById('acmeResetUsage');
    if (!btn) return;

    btn.addEventListener('click', function () {
        run_module_method('reset_usage');
    });
})();
</script>

Tuzaklar

Korumasız bir eleman araması tüm paneli öldürür

$client_area ile gizlenen blok, eleman kimliklerini de götürür. O kayıp düğüm üzerinde addEventListener çağıran satır içi script hata fırlatır. Script köprüsü de onunla düşer ve müşteri genel bir "yüklenemedi" mesajı alır. Her aramayı koruyun.

Kısayol kısayoldur, aksiyonun evi değildir

Aksiyonu panoya koyun, kısayol da oraya işaret etsin.

Zamanlayıcı altında sayfa boş gelir

Zamanlanmış görev bağlamında şablon çıktısı atlanır. Komut satırından bir sonda sıfır uzunlukta sayfa bildirir, gerçek istek panelin tamamını döndürür. Gerçek HTTP üzerinden ya da yönetici kimliğine bürünerek doğrulayın.

Faydalı oldu mu?

Geri bildiriminiz için teşekkürler!

Hâlâ Yardıma mı İhtiyacınız Var?

Yukarıda bulamadığınız her şey için destek ekibimiz her zaman yanınızda.