All files / src/components/Settings Privacy.tsx

0% Statements 0/67
0% Branches 0/1
0% Functions 0/1
0% Lines 0/67

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86                                                                                                                                                                           
import { useEffect } from 'react';
import { ExternalLink } from 'lucide-react';
import { useConfigStore } from '../../store/configStore';
import { silentErrorHandler } from '../../lib/error-utils';
 
export function Privacy() {
  const quickConfig = useConfigStore((s) => s.quickConfig);
  const workspaceInfo = useConfigStore((s) => s.workspaceInfo);
  const loadWorkspaceInfo = useConfigStore((s) => s.loadWorkspaceInfo);
  const saveQuickConfig = useConfigStore((s) => s.saveQuickConfig);
 
  useEffect(() => {
    loadWorkspaceInfo().catch(silentErrorHandler('Privacy'));
  }, []);
 
  const optIn = quickConfig.privacyOptIn ?? false;
 
  return (
    <div className="max-w-3xl">
      <h1 className="text-xl font-bold mb-2 text-gray-900">数据与隐私</h1>
      <div className="text-xs text-gray-500 mb-6">查看数据存储位置与 ZCLAW 的网络出站范围。</div>
 
      <div className="bg-white rounded-xl border border-gray-200 p-6 mb-6 shadow-sm">
        <h3 className="font-medium mb-2 text-gray-900">本地数据路径</h3>
        <div className="text-xs text-gray-500 mb-3">所有工作区文件、对话记录和 Agent 输出均存储在此本地目录。</div>
        <div className="p-3 bg-gray-50 border border-gray-200 rounded-lg text-xs text-gray-600 font-mono">
          {workspaceInfo?.resolvedPath || workspaceInfo?.path || quickConfig.workspaceDir || '~/.openfang/zclaw-workspace'}
        </div>
      </div>
 
      <div className="bg-white rounded-xl border border-gray-200 p-6 mb-6 shadow-sm">
        <div className="flex justify-between items-start mb-4">
          <h3 className="font-medium text-gray-900">优化计划</h3>
          <Toggle checked={optIn} onChange={(value) => { saveQuickConfig({ privacyOptIn: value }).catch(silentErrorHandler('Privacy')); }} />
        </div>
        <p className="text-xs text-gray-500 leading-relaxed">
          我们诚邀您加入优化提升计划,您的加入会帮助我们更好地迭代产品:在去标识化处理后,我们可能将您输入与生成的信息以及屏幕操作信息用于模型的训练与优化。我们尊重您的个人信息主体权益,您有权选择不允许我们将您的信息用于此目的。您也可以在后续使用中的任何时候通过"设置"中的开启或关闭按钮选择加入或退出优化计划。
        </p>
      </div>
 
      <div className="bg-white rounded-xl border border-gray-200 p-6 shadow-sm">
        <h3 className="font-medium mb-4 text-gray-900">备案信息</h3>
        <div className="space-y-3 text-xs">
          <div className="flex">
            <span className="text-gray-500 w-28 flex-shrink-0">ICP 备案/许可证号</span>
            <span className="text-gray-700">京 ICP 备 20011824 号 -21</span>
          </div>
          <div className="flex">
            <span className="text-gray-500 w-28 flex-shrink-0">算法备案</span>
            <div className="space-y-1 text-gray-700">
              <div>智谱 ChatGLM 生成算法(网信算备 110108105858001230019 号)</div>
              <div>智谱 ChatGLM 搜索算法(网信算备 110108105858004240011 号)</div>
            </div>
          </div>
          <div className="flex">
            <span className="text-gray-500 w-28 flex-shrink-0">大模型备案登记</span>
            <span className="text-gray-700">Beijing-AutoGLM-2025060650053</span>
          </div>
        </div>
 
        <div className="flex gap-4 mt-6 pt-4 border-t border-gray-100">
          <a href="#" className="text-orange-600 text-xs hover:underline flex items-center gap-1">
            <ExternalLink className="w-3 h-3" />
            隐私政策
          </a>
          <a href="#" className="text-orange-600 text-xs hover:underline flex items-center gap-1">
            <ExternalLink className="w-3 h-3" />
            用户协议
          </a>
        </div>
      </div>
    </div>
  );
}
 
function Toggle({ checked, onChange }: { checked: boolean; onChange: (v: boolean) => void }) {
  return (
    <button
      onClick={() => onChange(!checked)}
      className={`w-11 h-6 rounded-full transition-colors relative flex-shrink-0 mt-1 ${checked ? 'bg-orange-500' : 'bg-gray-200'}`}
    >
      <span className={`block w-5 h-5 bg-white rounded-full shadow-sm absolute top-0.5 transition-all ${checked ? 'left-[22px]' : 'left-0.5'}`} />
    </button>
  );
}